@flusys/nestjs-entity-builder 9.1.0 → 9.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -25
- package/config/entity-builder.constants.d.ts +2 -0
- package/config/message-keys.d.ts +93 -12
- package/controllers/definition-bundle.controller.d.ts +15 -0
- package/controllers/flow-definition.controller.d.ts +7 -1
- package/controllers/index.d.ts +1 -1
- package/dtos/definition-bundle.dto.d.ts +57 -0
- package/dtos/flow.dto.d.ts +12 -20
- package/dtos/index.d.ts +1 -0
- package/entities/flow-definition.entity.d.ts +3 -9
- package/entities/flow-execution.entity.d.ts +3 -0
- package/entities/flow-version.entity.d.ts +10 -0
- package/entities/index.d.ts +3 -3
- package/fesm/21.js +96 -14
- package/fesm/458.js +695 -0
- package/fesm/{489.js → 582.js} +22 -30
- package/fesm/{996.js → 677.js} +1453 -1078
- package/fesm/794.js +135 -240
- package/fesm/{719.js → 870.js} +1955 -220
- package/fesm/{362.js → 897.js} +566 -2
- package/fesm/{606.js → 946.js} +564 -290
- package/fesm/config/index.js +15 -2
- package/fesm/controllers/index.js +9 -9
- package/fesm/docs/index.js +7 -4
- package/fesm/dtos/index.js +451 -256
- package/fesm/entities/index.js +58 -3
- package/fesm/guards/index.js +101 -22
- package/fesm/index.js +429 -948
- package/fesm/interfaces/index.js +19 -2
- package/fesm/modules/index.js +10 -628
- package/fesm/rule-engine/index.js +12 -3
- package/fesm/services/index.js +97 -27
- package/flow-engine/flow-api-key.d.ts +3 -7
- package/flow-engine/flow-graph.validator.d.ts +4 -2
- package/flow-engine/flow-permission-logic.d.ts +2 -0
- package/flow-engine/flow-run.types.d.ts +17 -8
- package/flow-engine/flow.types.d.ts +101 -13
- package/guards/designer-writable.interceptor.d.ts +12 -0
- package/guards/index.d.ts +1 -0
- package/interfaces/definition-bundle.interface.d.ts +111 -0
- package/interfaces/entity-builder-module.interface.d.ts +6 -0
- package/interfaces/flow-definition.interface.d.ts +13 -9
- package/interfaces/index.d.ts +1 -0
- package/package.json +5 -5
- package/rule-engine/rule-engine.service.d.ts +1 -0
- package/rule-engine/rule-permission.d.ts +3 -7
- package/services/definition-bundle.diff.d.ts +62 -0
- package/services/definition-bundle.file.d.ts +7 -0
- package/services/definition-bundle.service.d.ts +32 -0
- package/services/entity-builder-config.service.d.ts +2 -0
- package/services/entity-flow-scaffold.d.ts +1 -1
- package/services/flow-definition.service.d.ts +25 -12
- package/services/flow-execution.service.d.ts +7 -0
- package/services/flow-executor.service.d.ts +8 -8
- package/services/generic-entity.service.d.ts +1 -1
- package/services/index.d.ts +3 -1
- package/services/schema-evolution.service.d.ts +3 -1
- package/services/schema-sync.service.d.ts +5 -1
- package/controllers/flow-api-key.controller.d.ts +0 -14
- package/entities/flow-api-key.entity.d.ts +0 -10
- package/services/flow-api-key.service.d.ts +0 -31
package/fesm/{996.js → 677.js}
RENAMED
|
@@ -7,41 +7,11 @@ import * as __rspack_external_node_os_4f3c9d58 from "node:os";
|
|
|
7
7
|
import * as __rspack_external_node_path_806ed179 from "node:path";
|
|
8
8
|
import * as __rspack_external_node_url_3991086a from "node:url";
|
|
9
9
|
import * as __rspack_external_node_worker_threads_28ca7740 from "node:worker_threads";
|
|
10
|
+
import * as __rspack_external__flusys_nestjs_shared_exceptions_3edf22e9 from "@flusys/nestjs-shared/exceptions";
|
|
10
11
|
import * as __rspack_external_node_dns_c6249ebb from "node:dns";
|
|
11
|
-
export const __rspack_esm_id =
|
|
12
|
-
export const __rspack_esm_ids = [
|
|
12
|
+
export const __rspack_esm_id = 677;
|
|
13
|
+
export const __rspack_esm_ids = [677];
|
|
13
14
|
export const __webpack_modules__ = {
|
|
14
|
-
6576(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
15
|
-
const ENTITY_BUILDER_MODULE_OPTIONS = 'ENTITY_BUILDER_MODULE_OPTIONS';
|
|
16
|
-
/**
|
|
17
|
-
* Identifier whitelist enforced on every EntityDefinition/FieldDefinition `code`.
|
|
18
|
-
* Also the exact contract SchemaSyncService's DDL engine validates against
|
|
19
|
-
* before generating a table/column name.
|
|
20
|
-
*/ const ENTITY_CODE_PATTERN = /^[a-z][a-z0-9_]{2,59}$/;
|
|
21
|
-
/** Matches the `code` column length on both EntityDefinition and FieldDefinition. */ const ENTITY_CODE_MAX_LENGTH = 63;
|
|
22
|
-
/** Defense-in-depth prefix applied to every dynamically created table name. */ const ENTITY_TABLE_PREFIX = 'eb_';
|
|
23
|
-
/** The generic API controller's record endpoints - each can be created as a ready-made flow with the entity. */ const ENTITY_FLOW_ENDPOINTS = [
|
|
24
|
-
'insert',
|
|
25
|
-
'insertMany',
|
|
26
|
-
'getById',
|
|
27
|
-
'getByIds',
|
|
28
|
-
'getAll',
|
|
29
|
-
'getByFilter',
|
|
30
|
-
'update',
|
|
31
|
-
'updateMany',
|
|
32
|
-
'bulkUpsert',
|
|
33
|
-
'delete'
|
|
34
|
-
];
|
|
35
|
-
|
|
36
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
37
|
-
}, {
|
|
38
|
-
CP: ENTITY_BUILDER_MODULE_OPTIONS,
|
|
39
|
-
WT: ENTITY_FLOW_ENDPOINTS,
|
|
40
|
-
vs: ENTITY_CODE_PATTERN
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
},
|
|
45
15
|
982(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
46
16
|
/** Every entity the entity builder module publishes under */ const ENTITY_BUILDER_EVENT_ENTITIES = {
|
|
47
17
|
ENTITY_DEFINITION: 'entity_definition',
|
|
@@ -59,6 +29,60 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
59
29
|
});
|
|
60
30
|
|
|
61
31
|
|
|
32
|
+
},
|
|
33
|
+
4816(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
34
|
+
/* import */ var node_crypto__rspack_import_0 = __webpack_require__(2561);
|
|
35
|
+
/* import */ var _flow_types_js__rspack_import_1 = __webpack_require__(6256);
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
const API_KEY_PREFIX_LENGTH = 11; // "fk_" + 8 hex
|
|
39
|
+
const hashApiKey = (key)=>(0,node_crypto__rspack_import_0.createHash)('sha256').update(key).digest('hex');
|
|
40
|
+
const apiKeyPrefix = (key)=>key.slice(0, API_KEY_PREFIX_LENGTH);
|
|
41
|
+
/** A key as the designer makes it: `fk_<8 hex>_<32 hex>`. */ function looksLikeApiKey(key) {
|
|
42
|
+
return typeof key === 'string' && /^fk_[0-9a-f]{8}_[0-9a-f]{32}$/.test(key);
|
|
43
|
+
}
|
|
44
|
+
/** Constant-time comparison of a presented key against a stored hash. */ function apiKeyMatches(presented, storedHash) {
|
|
45
|
+
const a = Buffer.from(hashApiKey(presented), 'hex');
|
|
46
|
+
const b = Buffer.from(storedHash, 'hex');
|
|
47
|
+
return a.length === b.length && (0,node_crypto__rspack_import_0.timingSafeEqual)(a, b);
|
|
48
|
+
}
|
|
49
|
+
/** Whether `presented` is the key a Request step stores. */ const apiKeyOpens = (stored, presented)=>!!stored && looksLikeApiKey(presented) && apiKeyMatches(presented, stored.hash);
|
|
50
|
+
/**
|
|
51
|
+
* What is saved of the Request steps' API keys: a plain key the designer made becomes its prefix and
|
|
52
|
+
* hash, so the key itself is never stored; a step without `api_key` access keeps no key at all.
|
|
53
|
+
*/ function sealApiKeys(nodes) {
|
|
54
|
+
return nodes.map((node)=>{
|
|
55
|
+
if (node.type !== 'trigger' || node.config?.['apiKey'] === undefined) return node;
|
|
56
|
+
const { apiKey, ...config } = node.config;
|
|
57
|
+
if (config['authMode'] !== 'api_key') return {
|
|
58
|
+
...node,
|
|
59
|
+
config
|
|
60
|
+
};
|
|
61
|
+
if (looksLikeApiKey(apiKey)) return {
|
|
62
|
+
...node,
|
|
63
|
+
config: {
|
|
64
|
+
...config,
|
|
65
|
+
apiKey: {
|
|
66
|
+
prefix: apiKeyPrefix(apiKey),
|
|
67
|
+
hash: hashApiKey(apiKey)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
return (0,_flow_types_js__rspack_import_1/* .isStoredApiKey */.xA)(apiKey) ? node : {
|
|
72
|
+
...node,
|
|
73
|
+
config
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
79
|
+
Jb: () => (looksLikeApiKey),
|
|
80
|
+
ue: () => (sealApiKeys)
|
|
81
|
+
}, {
|
|
82
|
+
NT: apiKeyOpens
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
|
|
62
86
|
},
|
|
63
87
|
8333(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
64
88
|
|
|
@@ -80,8 +104,6 @@ var message_keys = __webpack_require__(5732);
|
|
|
80
104
|
var flow_errors = __webpack_require__(8542);
|
|
81
105
|
// EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/flow-engine/flow.types.ts
|
|
82
106
|
var flow_types = __webpack_require__(6256);
|
|
83
|
-
// EXTERNAL MODULE: external "@flusys/nestjs-shared/constants"
|
|
84
|
-
var constants_ = __webpack_require__(9140);
|
|
85
107
|
// EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/interfaces/generic-record.interface.ts
|
|
86
108
|
var generic_record_interface = __webpack_require__(3372);
|
|
87
109
|
;// CONCATENATED MODULE: external "node:os"
|
|
@@ -302,7 +324,7 @@ const timeoutError = (job)=>new flow_errors/* .FlowCodeError */.yL(message_keys/
|
|
|
302
324
|
const unavailableError = (node, detail)=>new flow_errors/* .FlowCodeError */.yL(message_keys/* .FLOW_ERROR_MESSAGES.CODE_UNAVAILABLE */.zr.CODE_UNAVAILABLE, {
|
|
303
325
|
node
|
|
304
326
|
}, `The code sandbox could not run the code: ${detail}`);
|
|
305
|
-
let
|
|
327
|
+
let flow_code_sandbox_CodeSandboxPool = class CodeSandboxPool {
|
|
306
328
|
idle = [];
|
|
307
329
|
running = new Map();
|
|
308
330
|
queue = [];
|
|
@@ -432,14 +454,12 @@ let pool;
|
|
|
432
454
|
detail: error.message
|
|
433
455
|
}, error.message);
|
|
434
456
|
}
|
|
435
|
-
pool ??= new
|
|
457
|
+
pool ??= new flow_code_sandbox_CodeSandboxPool();
|
|
436
458
|
return pool.run(code, input, timeoutMs, node);
|
|
437
459
|
}
|
|
438
460
|
|
|
439
461
|
// EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/flow-engine/flow-graph.validator.ts
|
|
440
462
|
var flow_graph_validator = __webpack_require__(3186);
|
|
441
|
-
// EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/rule-engine/rule-permission.ts
|
|
442
|
-
var rule_permission = __webpack_require__(5191);
|
|
443
463
|
// EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/rule-engine/rule-values.ts
|
|
444
464
|
var rule_values = __webpack_require__(6622);
|
|
445
465
|
;// CONCATENATED MODULE: ./projects/nestjs-entity-builder/src/flow-engine/flow-node-handlers.ts
|
|
@@ -452,15 +472,7 @@ var rule_values = __webpack_require__(6622);
|
|
|
452
472
|
|
|
453
473
|
|
|
454
474
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
const PERMISSION_ACTION = {
|
|
458
|
-
insert: 'create',
|
|
459
|
-
update: 'update',
|
|
460
|
-
delete: 'delete',
|
|
461
|
-
read: 'read'
|
|
462
|
-
};
|
|
463
|
-
/** With `env`, `lookup` expressions read through the flow (permission check, transaction). */ function evaluationContext(state, env) {
|
|
475
|
+
/** With `env`, `lookup` expressions read through the flow (its transaction). */ function evaluationContext(state, env) {
|
|
464
476
|
const base = {
|
|
465
477
|
input: state.input,
|
|
466
478
|
vars: state.vars,
|
|
@@ -478,7 +490,6 @@ const PERMISSION_ACTION = {
|
|
|
478
490
|
function lookupResolver(env, state) {
|
|
479
491
|
return {
|
|
480
492
|
find: async (entityCode, query)=>{
|
|
481
|
-
await authorize(env, state, entityCode, 'read');
|
|
482
493
|
const service = await env.entityService(entityCode, state.qr);
|
|
483
494
|
const { data, total } = await service.getAll(undefined, {
|
|
484
495
|
filter: query.filter,
|
|
@@ -556,7 +567,7 @@ async function runValidate(cfg, env, state) {
|
|
|
556
567
|
passed: true
|
|
557
568
|
}
|
|
558
569
|
};
|
|
559
|
-
const status = cfg.statusCode ?? (failed.every((check)=>(0,flow_graph_validator/* .usesPermissionFunction */.
|
|
570
|
+
const status = cfg.statusCode ?? (failed.every((check)=>(0,flow_graph_validator/* .usesPermissionFunction */.u9)(check.rule)) ? 403 : 400);
|
|
560
571
|
const errors = failed.map((check)=>({
|
|
561
572
|
field: check.field || check.id,
|
|
562
573
|
message: check.message
|
|
@@ -569,21 +580,17 @@ async function runValidate(cfg, env, state) {
|
|
|
569
580
|
}
|
|
570
581
|
});
|
|
571
582
|
}
|
|
572
|
-
/** `{ allowed, missing }` - `missing` lists the codes the caller does not hold. */ async function runPermissionCheck(cfg, env, state) {
|
|
573
|
-
const codes = (0,rule_permission/* .parsePermissionCodes */.PS)(cfg.codes);
|
|
574
|
-
let branch;
|
|
575
|
-
if (cfg.branch === null) branch = null;
|
|
576
|
-
else if (cfg.branch !== undefined) branch = (0,rule_permission/* .toBranchArgument */.lH)([
|
|
577
|
-
await env.ruleEngine.resolveExpression(cfg.branch, evaluationContext(state, env))
|
|
578
|
-
], 0);
|
|
583
|
+
/** `{ allowed, missing }` - whether the caller passes the AND / OR rule; `missing` lists the codes it names that the caller does not hold. */ async function runPermissionCheck(cfg, env, state) {
|
|
579
584
|
const permissions = state.permissions ?? env.ruleEngine.createPermissionResolver(state.user);
|
|
580
|
-
const granted = state.user ? await permissions.granted(
|
|
581
|
-
const missing =
|
|
582
|
-
const allowed =
|
|
583
|
-
|
|
585
|
+
const granted = state.user ? await permissions.granted(undefined) : [];
|
|
586
|
+
const missing = (0,utils_.permissionLogicCodes)(cfg.permissions).filter((code)=>!(0,utils_.matchesPermission)(granted, code));
|
|
587
|
+
const allowed = (0,utils_.evaluatePermissionLogic)(cfg.permissions, granted).passed;
|
|
588
|
+
return deniedResult(cfg, {
|
|
584
589
|
allowed,
|
|
585
590
|
missing
|
|
586
|
-
};
|
|
591
|
+
}, allowed);
|
|
592
|
+
}
|
|
593
|
+
/** A denied check: `onDenied: branch` follows the `denied` port, otherwise the run is answered `statusCode` (403). */ function deniedResult(cfg, output, allowed) {
|
|
587
594
|
if (cfg.onDenied === 'branch') return {
|
|
588
595
|
output,
|
|
589
596
|
port: allowed ? 'allowed' : 'denied'
|
|
@@ -599,6 +606,68 @@ async function runValidate(cfg, env, state) {
|
|
|
599
606
|
output
|
|
600
607
|
};
|
|
601
608
|
}
|
|
609
|
+
/** One id, a list of ids, or nothing (undefined / null / empty text), each id once. */ function idList(value) {
|
|
610
|
+
const items = Array.isArray(value) ? value : [
|
|
611
|
+
value
|
|
612
|
+
];
|
|
613
|
+
return [
|
|
614
|
+
...new Set(items.filter((item)=>item !== undefined && item !== null && item !== '').map(String))
|
|
615
|
+
];
|
|
616
|
+
}
|
|
617
|
+
/** One id from an expression's value; anything but non-empty text is none. */ function oneId(value) {
|
|
618
|
+
return typeof value === 'string' && value ? value : null;
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* `{ userId, currentCompanyId, currentBranchId, companies, branches }` - what the user (the signed-in
|
|
622
|
+
* caller, or the one `userId` names) may work in; none without a user or the company feature. With
|
|
623
|
+
* `companyIds` / `branchIds` it also answers `allowed` and `missing`: every id asked for must be within
|
|
624
|
+
* reach (`branchMatch`, among the branches of `branchCompany`), and a target that resolves to nothing
|
|
625
|
+
* is a denial, never a pass.
|
|
626
|
+
*/ async function runCompanyBranchCheck(cfg, env, state) {
|
|
627
|
+
const ctx = evaluationContext(state, env);
|
|
628
|
+
const resolve = async (expression)=>expression === undefined ? undefined : env.ruleEngine.resolveExpression(expression, ctx);
|
|
629
|
+
const asCaller = cfg.subject !== 'user';
|
|
630
|
+
const userId = asCaller ? state.user?.id ?? null : oneId(await resolve(cfg.userId));
|
|
631
|
+
const { companies, branches } = userId ? await env.companyAccess(userId) : {
|
|
632
|
+
companies: [],
|
|
633
|
+
branches: []
|
|
634
|
+
};
|
|
635
|
+
const currentCompanyId = asCaller ? state.user?.companyId ?? null : null;
|
|
636
|
+
const currentBranchId = asCaller ? state.user?.branchId ?? null : null;
|
|
637
|
+
const output = {
|
|
638
|
+
userId,
|
|
639
|
+
currentCompanyId,
|
|
640
|
+
currentBranchId,
|
|
641
|
+
companies,
|
|
642
|
+
branches
|
|
643
|
+
};
|
|
644
|
+
if (cfg.companyIds === undefined && cfg.branchIds === undefined) return {
|
|
645
|
+
output
|
|
646
|
+
};
|
|
647
|
+
const wanted = async (expression)=>expression === undefined ? null : idList(await resolve(expression));
|
|
648
|
+
const wantedCompanies = await wanted(cfg.companyIds);
|
|
649
|
+
const wantedBranches = await wanted(cfg.branchIds);
|
|
650
|
+
const granted = branches.filter((branch)=>cfg.branchCompany !== 'current' || branch.companyId === currentCompanyId).map((branch)=>branch.id);
|
|
651
|
+
const reachable = await reachableBranches(cfg.branchMatch ?? 'direct', granted, wantedBranches, env);
|
|
652
|
+
const missing = {
|
|
653
|
+
companyIds: (wantedCompanies ?? []).filter((id)=>!companies.some((company)=>company.id === id)),
|
|
654
|
+
branchIds: (wantedBranches ?? []).filter((id)=>!reachable.has(id))
|
|
655
|
+
};
|
|
656
|
+
const nothingToCheck = wantedCompanies?.length === 0 || wantedBranches?.length === 0;
|
|
657
|
+
const allowed = !nothingToCheck && !missing.companyIds.length && !missing.branchIds.length;
|
|
658
|
+
return deniedResult(cfg, {
|
|
659
|
+
...output,
|
|
660
|
+
allowed,
|
|
661
|
+
missing
|
|
662
|
+
}, allowed);
|
|
663
|
+
}
|
|
664
|
+
/** The branches a check passes: the granted ones (direct), and with `within` every branch under them too. */ async function reachableBranches(match, granted, wanted, env) {
|
|
665
|
+
if (match !== 'within' || !wanted?.length || !granted.length || !env.branchTree || wanted.every((id)=>granted.includes(id))) return new Set(granted);
|
|
666
|
+
return new Set([
|
|
667
|
+
...granted,
|
|
668
|
+
...await env.branchTree(granted)
|
|
669
|
+
]);
|
|
670
|
+
}
|
|
602
671
|
const USES_PERMISSIONS = /\b(permissions|hasPermission|hasAnyPermission|hasAllPermissions)\b/;
|
|
603
672
|
/** The caller as a code step sees it; permission codes (current branch) are fetched only for code that reads them. */ async function codeUser(code, state) {
|
|
604
673
|
const user = state.user;
|
|
@@ -641,16 +710,6 @@ function asId(value) {
|
|
|
641
710
|
});
|
|
642
711
|
return value;
|
|
643
712
|
}
|
|
644
|
-
/** Fails closed: the caller needs the entity permission; the system only when that was granted for this run; anything else is refused. */ async function authorize(env, state, entityCode, action) {
|
|
645
|
-
if (state.runAs === 'caller') return env.assertPermission((0,constants_.dynamicEntityPermission)(entityCode, PERMISSION_ACTION[action]), state.user);
|
|
646
|
-
if (state.runAs === 'system' && state.systemAuthorized === true) return;
|
|
647
|
-
throw new flow_errors/* .FlowHttpError */.hk(403, 'This flow is not allowed to read or write records as the system.', undefined, {
|
|
648
|
-
messageKey: message_keys/* .FLOW_ERROR_MESSAGES.RUN_AS_NOT_ALLOWED */.zr.RUN_AS_NOT_ALLOWED,
|
|
649
|
-
messageVariables: {
|
|
650
|
-
runAs: String(state.runAs)
|
|
651
|
-
}
|
|
652
|
-
});
|
|
653
|
-
}
|
|
654
713
|
function writeOptions(state) {
|
|
655
714
|
return state.qr ? {
|
|
656
715
|
queryRunner: state.qr,
|
|
@@ -727,15 +786,16 @@ async function updateRecord(entityCode, service, values, state) {
|
|
|
727
786
|
}
|
|
728
787
|
/** @returns false when the record does not exist and `skip` allows that. */ async function deleteRecord(entityCode, service, id, skipMissing, state) {
|
|
729
788
|
countWrite(state);
|
|
789
|
+
let action;
|
|
730
790
|
try {
|
|
731
|
-
await service.delete(id, state.user, writeOptions(state));
|
|
791
|
+
action = await service.delete(id, state.user, writeOptions(state));
|
|
732
792
|
} catch (error) {
|
|
733
793
|
if (skipMissing && error instanceof common_.NotFoundException) return false;
|
|
734
794
|
throw error;
|
|
735
795
|
}
|
|
736
796
|
if (state.qr) state.pendingEvents.push({
|
|
737
797
|
entityCode,
|
|
738
|
-
action
|
|
798
|
+
action,
|
|
739
799
|
row: {
|
|
740
800
|
id
|
|
741
801
|
}
|
|
@@ -780,8 +840,6 @@ async function insertChildren(node, child, parentId, env, state) {
|
|
|
780
840
|
* A write of several records (many, or any children) is all-or-nothing.
|
|
781
841
|
*/ async function runInsert(node, cfg, env, state) {
|
|
782
842
|
const children = cfg.children ?? [];
|
|
783
|
-
await authorize(env, state, cfg.entityCode, 'insert');
|
|
784
|
-
for (const child of children)await authorize(env, state, child.entityCode, 'insert');
|
|
785
843
|
const service = await env.entityService(cfg.entityCode, state.qr);
|
|
786
844
|
const insertOne = async ()=>{
|
|
787
845
|
const saved = await insertRecord(cfg.entityCode, service, await mapFieldValues(cfg.fields, env, state), state);
|
|
@@ -835,8 +893,6 @@ async function insertChildren(node, child, parentId, env, state) {
|
|
|
835
893
|
}
|
|
836
894
|
/** one: the saved record (null when skipped). many / filter: `{ items, count, updated, created, skipped }`, all-or-nothing. */ async function runUpdate(node, cfg, env, state) {
|
|
837
895
|
const target = writeTarget(cfg);
|
|
838
|
-
await authorize(env, state, cfg.entityCode, 'update');
|
|
839
|
-
if (target !== 'filter' && cfg.onNotFound === 'insert') await authorize(env, state, cfg.entityCode, 'insert');
|
|
840
896
|
const service = await env.entityService(cfg.entityCode, state.qr);
|
|
841
897
|
if (target === 'one') return {
|
|
842
898
|
output: (await updateOrCreate(cfg, service, undefined, env, state)).row
|
|
@@ -867,7 +923,6 @@ async function insertChildren(node, child, parentId, env, state) {
|
|
|
867
923
|
/** one: `{ id, deleted }`. many / filter: `{ ids, count, skipped }`, all-or-nothing; an id listed twice is deleted once. */ async function runDelete(node, cfg, env, state) {
|
|
868
924
|
const target = writeTarget(cfg);
|
|
869
925
|
const skipMissing = cfg.onNotFound === 'skip';
|
|
870
|
-
await authorize(env, state, cfg.entityCode, 'delete');
|
|
871
926
|
const service = await env.entityService(cfg.entityCode, state.qr);
|
|
872
927
|
const idOf = async (item)=>asId(cfg.id === undefined ? itemId(item) : await env.ruleEngine.resolveExpression(cfg.id, evaluationContext(state, env)));
|
|
873
928
|
if (target === 'one') {
|
|
@@ -897,6 +952,377 @@ async function insertChildren(node, child, parentId, env, state) {
|
|
|
897
952
|
})
|
|
898
953
|
};
|
|
899
954
|
}
|
|
955
|
+
/** As strict as the email module's own check, and without the characters that would break an address header. */ const EMAIL_PATTERN = /^[^\s@,;<>"]+@[^\s@,;<>"]+\.[^\s@,;<>"]+$/;
|
|
956
|
+
const MAX_EMAIL_LENGTH = 254;
|
|
957
|
+
const shown = (value)=>String(typeof value === 'object' && value !== null ? JSON.stringify(value) : value).slice(0, 100);
|
|
958
|
+
/** A value as message text: nothing for null / undefined, JSON for an object. */ function asText(value) {
|
|
959
|
+
if (value === null || value === undefined) return '';
|
|
960
|
+
return typeof value === 'object' ? JSON.stringify(value) : String(value);
|
|
961
|
+
}
|
|
962
|
+
/** Reserves `count` sends of the run's budget before any goes out, so a step never sends only some of its messages because of the limit. */ function countMessages(state, count) {
|
|
963
|
+
if (state.messages + count > flow_types/* .FLOW_LIMITS.MAX_MESSAGES_PER_RUN */.Or.MAX_MESSAGES_PER_RUN) throw new flow_errors/* .FlowLimitError */.IM(message_keys/* .FLOW_ERROR_MESSAGES.TOO_MANY_MESSAGES */.zr.TOO_MANY_MESSAGES, {
|
|
964
|
+
max: flow_types/* .FLOW_LIMITS.MAX_MESSAGES_PER_RUN */.Or.MAX_MESSAGES_PER_RUN
|
|
965
|
+
});
|
|
966
|
+
state.messages += count;
|
|
967
|
+
}
|
|
968
|
+
function assertRecipientCount(node, count, max) {
|
|
969
|
+
if (count > max) throw new flow_errors/* .FlowLimitError */.IM(message_keys/* .FLOW_ERROR_MESSAGES.TOO_MANY_RECIPIENTS */.zr.TOO_MANY_RECIPIENTS, {
|
|
970
|
+
node: (0,flow_types/* .nodeLabel */.dA)(node),
|
|
971
|
+
count,
|
|
972
|
+
max
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
/** Whatever the module threw, or its `success: false`, fails the step with the reason (a limit stays a limit). */ function sendFailure(key, node, error) {
|
|
976
|
+
if (error instanceof flow_errors/* .FlowKeyedError */.Hp || error instanceof flow_errors/* .FlowHttpError */.hk) return error;
|
|
977
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
978
|
+
return new flow_errors/* .FlowKeyedError */.Hp(key, {
|
|
979
|
+
node: (0,flow_types/* .nodeLabel */.dA)(node),
|
|
980
|
+
detail
|
|
981
|
+
}, `"${(0,flow_types/* .nodeLabel */.dA)(node)}" could not send: ${detail}`);
|
|
982
|
+
}
|
|
983
|
+
/** Inside a transaction the message waits for the commit, so a run that rolls back sends nothing. */ async function deliver(node, state, send) {
|
|
984
|
+
if (state.qr) {
|
|
985
|
+
state.pendingEvents.push({
|
|
986
|
+
delivery: (0,flow_types/* .nodeLabel */.dA)(node),
|
|
987
|
+
send
|
|
988
|
+
});
|
|
989
|
+
return 'queued';
|
|
990
|
+
}
|
|
991
|
+
await send();
|
|
992
|
+
return 'sent';
|
|
993
|
+
}
|
|
994
|
+
/** One id or a list of them, each once; null / undefined / empty text is none. Anything but an id rejects with `key`. */ function idsOf(node, value, key, text) {
|
|
995
|
+
const items = (Array.isArray(value) ? value : [
|
|
996
|
+
value
|
|
997
|
+
]).filter((item)=>item !== undefined && item !== null && item !== '');
|
|
998
|
+
for (const item of items){
|
|
999
|
+
if (typeof item !== 'string' || !flow_types/* .FLOW_ID_PATTERN.test */.E2.test(item)) {
|
|
1000
|
+
throw new flow_errors/* .FlowHttpError */.hk(400, text(shown(item)), undefined, {
|
|
1001
|
+
messageKey: key,
|
|
1002
|
+
messageVariables: {
|
|
1003
|
+
node: (0,flow_types/* .nodeLabel */.dA)(node),
|
|
1004
|
+
value: shown(item)
|
|
1005
|
+
}
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
return [
|
|
1010
|
+
...new Set(items)
|
|
1011
|
+
];
|
|
1012
|
+
}
|
|
1013
|
+
const notificationRecipients = (node, value)=>idsOf(node, value, message_keys/* .FLOW_ERROR_MESSAGES.NOTIFICATION_RECIPIENT_INVALID */.zr.NOTIFICATION_RECIPIENT_INVALID, (shownValue)=>`"${(0,flow_types/* .nodeLabel */.dA)(node)}" cannot notify "${shownValue}": it is not a user id.`);
|
|
1014
|
+
/** Addresses: one, a list, or comma / semicolon separated text; each once (case aside), in the order given. */ function emailAddresses(node, value) {
|
|
1015
|
+
const items = (Array.isArray(value) ? value : [
|
|
1016
|
+
value
|
|
1017
|
+
]).filter((item)=>item !== undefined && item !== null);
|
|
1018
|
+
const seen = new Map();
|
|
1019
|
+
for (const item of items){
|
|
1020
|
+
const parts = typeof item === 'string' ? item.split(/[,;]/) : [
|
|
1021
|
+
item
|
|
1022
|
+
];
|
|
1023
|
+
for (const part of parts){
|
|
1024
|
+
const address = typeof part === 'string' ? part.trim() : part;
|
|
1025
|
+
if (address === '') continue;
|
|
1026
|
+
if (typeof address !== 'string' || address.length > MAX_EMAIL_LENGTH || !EMAIL_PATTERN.test(address)) {
|
|
1027
|
+
throw new flow_errors/* .FlowHttpError */.hk(400, `"${shown(address)}" is not a valid email address.`, undefined, {
|
|
1028
|
+
messageKey: message_keys/* .FLOW_ERROR_MESSAGES.EMAIL_ADDRESS_INVALID */.zr.EMAIL_ADDRESS_INVALID,
|
|
1029
|
+
messageVariables: {
|
|
1030
|
+
node: (0,flow_types/* .nodeLabel */.dA)(node),
|
|
1031
|
+
address: shown(address)
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
if (!seen.has(address.toLowerCase())) seen.set(address.toLowerCase(), address);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
return [
|
|
1039
|
+
...seen.values()
|
|
1040
|
+
];
|
|
1041
|
+
}
|
|
1042
|
+
/** The company a notification shows under: the one given, else the caller's current one. */ function notificationCompany(node, value, given, state) {
|
|
1043
|
+
if (!given) return state.user?.companyId ?? null;
|
|
1044
|
+
if (value === undefined || value === null || value === '') return null;
|
|
1045
|
+
if (typeof value === 'string' && flow_types/* .FLOW_ID_PATTERN.test */.E2.test(value)) return value;
|
|
1046
|
+
throw new flow_errors/* .FlowHttpError */.hk(400, `"${(0,flow_types/* .nodeLabel */.dA)(node)}": "${shown(value)}" is not a company id.`, undefined, {
|
|
1047
|
+
messageKey: message_keys/* .FLOW_ERROR_MESSAGES.NOTIFICATION_COMPANY_INVALID */.zr.NOTIFICATION_COMPANY_INVALID,
|
|
1048
|
+
messageVariables: {
|
|
1049
|
+
node: (0,flow_types/* .nodeLabel */.dA)(node),
|
|
1050
|
+
value: shown(value)
|
|
1051
|
+
}
|
|
1052
|
+
});
|
|
1053
|
+
}
|
|
1054
|
+
/** Sends `batches` (each already checked) as one step: the run's budget is taken for all of them first; a test run sends nothing. */ async function sendAll(node, state, batches, skipKey, recipients, send) {
|
|
1055
|
+
countMessages(state, batches.length);
|
|
1056
|
+
if (state.mode === 'dry_run') return {
|
|
1057
|
+
output: {
|
|
1058
|
+
skipped: true,
|
|
1059
|
+
reasonKey: skipKey,
|
|
1060
|
+
count: batches.length,
|
|
1061
|
+
recipients
|
|
1062
|
+
},
|
|
1063
|
+
skipped: true
|
|
1064
|
+
};
|
|
1065
|
+
let status = 'sent';
|
|
1066
|
+
for (const batch of batches)status = await deliver(node, state, ()=>send(batch));
|
|
1067
|
+
return status;
|
|
1068
|
+
}
|
|
1069
|
+
const nobody = (extra = {})=>({
|
|
1070
|
+
output: {
|
|
1071
|
+
skipped: true,
|
|
1072
|
+
reasonKey: message_keys/* .FLOW_SKIP_MESSAGES.NO_RECIPIENTS */.CB.NO_RECIPIENTS,
|
|
1073
|
+
recipients: 0,
|
|
1074
|
+
...extra
|
|
1075
|
+
},
|
|
1076
|
+
skipped: true
|
|
1077
|
+
});
|
|
1078
|
+
/** Title, message, type, data and push of a notification, read in the current scope (the item's, in many mode). */ async function notificationContent(node, cfg, env, state) {
|
|
1079
|
+
const ctx = evaluationContext(state, env);
|
|
1080
|
+
const title = asText(await env.ruleEngine.resolveExpression(cfg.title, ctx)).trim().slice(0, flow_types/* .FLOW_LIMITS.MAX_NOTIFICATION_TITLE_LENGTH */.Or.MAX_NOTIFICATION_TITLE_LENGTH);
|
|
1081
|
+
if (!title) throw new flow_errors/* .FlowHttpError */.hk(400, `The title of "${(0,flow_types/* .nodeLabel */.dA)(node)}" is empty.`, undefined, {
|
|
1082
|
+
messageKey: message_keys/* .FLOW_ERROR_MESSAGES.NOTIFICATION_TITLE_EMPTY */.zr.NOTIFICATION_TITLE_EMPTY,
|
|
1083
|
+
messageVariables: {
|
|
1084
|
+
node: (0,flow_types/* .nodeLabel */.dA)(node)
|
|
1085
|
+
}
|
|
1086
|
+
});
|
|
1087
|
+
const message = cfg.message === undefined ? '' : asText(await env.ruleEngine.resolveExpression(cfg.message, ctx));
|
|
1088
|
+
const data = cfg.data && Object.keys(cfg.data).length ? await mapValues(cfg.data, env, state) : null;
|
|
1089
|
+
return {
|
|
1090
|
+
title,
|
|
1091
|
+
message: message || null,
|
|
1092
|
+
type: cfg.type ?? 'info',
|
|
1093
|
+
data,
|
|
1094
|
+
realtime: cfg.realtime !== false
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
/** One notification to the users `userIds` names, or null when that is nobody. */ async function userNotification(node, cfg, env, state) {
|
|
1098
|
+
const ctx = evaluationContext(state, env);
|
|
1099
|
+
const userIds = notificationRecipients(node, cfg.userIds === undefined ? undefined : await env.ruleEngine.resolveExpression(cfg.userIds, ctx));
|
|
1100
|
+
if (!userIds.length) return null;
|
|
1101
|
+
assertRecipientCount(node, userIds.length, flow_types/* .FLOW_LIMITS.MAX_NOTIFICATION_RECIPIENTS */.Or.MAX_NOTIFICATION_RECIPIENTS);
|
|
1102
|
+
const content = await notificationContent(node, cfg, env, state);
|
|
1103
|
+
const companyId = notificationCompany(node, cfg.companyId === undefined ? undefined : await env.ruleEngine.resolveExpression(cfg.companyId, ctx), cfg.companyId !== undefined, state);
|
|
1104
|
+
return {
|
|
1105
|
+
...content,
|
|
1106
|
+
userIds,
|
|
1107
|
+
companyId
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
/** One notification per company that has members, each shown under its own company. */ async function companyNotifications(node, cfg, env, state) {
|
|
1111
|
+
const companyMembers = env.companyMembers;
|
|
1112
|
+
if (!companyMembers) {
|
|
1113
|
+
throw new flow_errors/* .FlowKeyedError */.Hp(message_keys/* .FLOW_ERROR_MESSAGES.NOTIFICATION_COMPANY_UNAVAILABLE */.zr.NOTIFICATION_COMPANY_UNAVAILABLE, {
|
|
1114
|
+
node: (0,flow_types/* .nodeLabel */.dA)(node)
|
|
1115
|
+
}, `"${(0,flow_types/* .nodeLabel */.dA)(node)}" notifies companies, which needs the company feature.`);
|
|
1116
|
+
}
|
|
1117
|
+
const ctx = evaluationContext(state, env);
|
|
1118
|
+
const resolve = async (expression)=>expression === undefined ? undefined : env.ruleEngine.resolveExpression(expression, ctx);
|
|
1119
|
+
const companyIds = idsOf(node, await resolve(cfg.companyIds), message_keys/* .FLOW_ERROR_MESSAGES.NOTIFICATION_COMPANY_INVALID */.zr.NOTIFICATION_COMPANY_INVALID, (value)=>`"${(0,flow_types/* .nodeLabel */.dA)(node)}": "${value}" is not a company id.`);
|
|
1120
|
+
const branchIds = idsOf(node, await resolve(cfg.branchIds), message_keys/* .FLOW_ERROR_MESSAGES.NOTIFICATION_BRANCH_INVALID */.zr.NOTIFICATION_BRANCH_INVALID, (value)=>`"${(0,flow_types/* .nodeLabel */.dA)(node)}": "${value}" is not a branch id.`);
|
|
1121
|
+
if (!companyIds.length) return [];
|
|
1122
|
+
const content = await notificationContent(node, cfg, env, state);
|
|
1123
|
+
const batches = [];
|
|
1124
|
+
let total = 0;
|
|
1125
|
+
for (const companyId of companyIds){
|
|
1126
|
+
const userIds = await companyMembers(companyId, branchIds.length ? branchIds : undefined);
|
|
1127
|
+
total += userIds.length;
|
|
1128
|
+
assertRecipientCount(node, total, flow_types/* .FLOW_LIMITS.MAX_COMPANY_NOTIFICATION_RECIPIENTS */.Or.MAX_COMPANY_NOTIFICATION_RECIPIENTS);
|
|
1129
|
+
if (userIds.length) batches.push({
|
|
1130
|
+
...content,
|
|
1131
|
+
userIds,
|
|
1132
|
+
companyId
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
return batches;
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1138
|
+
* one: `{ status, recipients }`. many / company: `{ status, count, recipients }` (+ `skipped` items
|
|
1139
|
+
* with nobody to notify, in many mode). `status` is `sent`, or `queued` inside a transaction (sent once
|
|
1140
|
+
* it commits). Every message is checked before the first goes out; nobody at all skips the step, and
|
|
1141
|
+
* a test run checks everything but sends nothing.
|
|
1142
|
+
*/ async function runSendNotification(node, cfg, env, state) {
|
|
1143
|
+
const notifications = env.notifications;
|
|
1144
|
+
if (!notifications) throw new flow_errors/* .FlowKeyedError */.Hp(message_keys/* .FLOW_ERROR_MESSAGES.NOTIFICATION_UNAVAILABLE */.zr.NOTIFICATION_UNAVAILABLE, {
|
|
1145
|
+
node: (0,flow_types/* .nodeLabel */.dA)(node)
|
|
1146
|
+
}, `"${(0,flow_types/* .nodeLabel */.dA)(node)}" needs the notification module, which this app does not run.`);
|
|
1147
|
+
const target = cfg.target ?? 'one';
|
|
1148
|
+
let batches;
|
|
1149
|
+
let skippedItems = 0;
|
|
1150
|
+
if (target === 'company') {
|
|
1151
|
+
batches = await companyNotifications(node, cfg, env, state);
|
|
1152
|
+
} else if (target === 'many') {
|
|
1153
|
+
const items = await resolveList(node, cfg.items, flow_types/* .FLOW_LIMITS.MAX_MESSAGES_PER_RUN */.Or.MAX_MESSAGES_PER_RUN, env, state);
|
|
1154
|
+
const prepared = await eachItem(state, items, ()=>userNotification(node, cfg, env, state));
|
|
1155
|
+
batches = prepared.filter((batch)=>batch !== null);
|
|
1156
|
+
skippedItems = prepared.length - batches.length;
|
|
1157
|
+
} else {
|
|
1158
|
+
batches = [
|
|
1159
|
+
await userNotification(node, cfg, env, state)
|
|
1160
|
+
].filter((batch)=>batch !== null);
|
|
1161
|
+
}
|
|
1162
|
+
const counts = target === 'one' ? {} : {
|
|
1163
|
+
count: batches.length,
|
|
1164
|
+
...target === 'many' ? {
|
|
1165
|
+
skipped: skippedItems
|
|
1166
|
+
} : {}
|
|
1167
|
+
};
|
|
1168
|
+
if (!batches.length) return nobody(counts);
|
|
1169
|
+
const recipients = batches.reduce((sum, batch)=>sum + batch.userIds.length, 0);
|
|
1170
|
+
const sent = await sendAll(node, state, batches, message_keys/* .FLOW_SKIP_MESSAGES.NOTIFICATION */.CB.NOTIFICATION, recipients, async (batch)=>{
|
|
1171
|
+
try {
|
|
1172
|
+
await notifications.sendToMany(batch);
|
|
1173
|
+
} catch (error) {
|
|
1174
|
+
throw sendFailure(message_keys/* .FLOW_ERROR_MESSAGES.NOTIFICATION_FAILED */.zr.NOTIFICATION_FAILED, node, error);
|
|
1175
|
+
}
|
|
1176
|
+
});
|
|
1177
|
+
if (typeof sent !== 'string') return sent;
|
|
1178
|
+
return {
|
|
1179
|
+
output: {
|
|
1180
|
+
status: sent,
|
|
1181
|
+
recipients,
|
|
1182
|
+
...counts
|
|
1183
|
+
}
|
|
1184
|
+
};
|
|
1185
|
+
}
|
|
1186
|
+
/** One email, read in the current scope (the item's, in many mode), or null when `to` has no address. */ async function prepareEmail(node, cfg, email, env, state) {
|
|
1187
|
+
const ctx = evaluationContext(state, env);
|
|
1188
|
+
const addresses = async (expression)=>expression === undefined ? [] : emailAddresses(node, await env.ruleEngine.resolveExpression(expression, ctx));
|
|
1189
|
+
const to = await addresses(cfg.to);
|
|
1190
|
+
if (!to.length) return null;
|
|
1191
|
+
// Someone already on `to` gets the email once.
|
|
1192
|
+
const listed = new Set(to.map((address)=>address.toLowerCase()));
|
|
1193
|
+
const notListed = (list)=>{
|
|
1194
|
+
const kept = list.filter((address)=>!listed.has(address.toLowerCase()));
|
|
1195
|
+
kept.forEach((address)=>listed.add(address.toLowerCase()));
|
|
1196
|
+
return kept;
|
|
1197
|
+
};
|
|
1198
|
+
const cc = notListed(await addresses(cfg.cc));
|
|
1199
|
+
const bcc = notListed(await addresses(cfg.bcc));
|
|
1200
|
+
const recipients = to.length + cc.length + bcc.length;
|
|
1201
|
+
assertRecipientCount(node, recipients, flow_types/* .FLOW_LIMITS.MAX_EMAIL_RECIPIENTS */.Or.MAX_EMAIL_RECIPIENTS);
|
|
1202
|
+
const replyTo = await addresses(cfg.replyTo);
|
|
1203
|
+
if (replyTo.length > 1) {
|
|
1204
|
+
throw new flow_errors/* .FlowHttpError */.hk(400, `"${replyTo.join(', ')}" is not a single email address.`, undefined, {
|
|
1205
|
+
messageKey: message_keys/* .FLOW_ERROR_MESSAGES.EMAIL_ADDRESS_INVALID */.zr.EMAIL_ADDRESS_INVALID,
|
|
1206
|
+
messageVariables: {
|
|
1207
|
+
node: (0,flow_types/* .nodeLabel */.dA)(node),
|
|
1208
|
+
address: shown(replyTo.join(', '))
|
|
1209
|
+
}
|
|
1210
|
+
});
|
|
1211
|
+
}
|
|
1212
|
+
const base = {
|
|
1213
|
+
to,
|
|
1214
|
+
...cc.length ? {
|
|
1215
|
+
cc
|
|
1216
|
+
} : {},
|
|
1217
|
+
...bcc.length ? {
|
|
1218
|
+
bcc
|
|
1219
|
+
} : {},
|
|
1220
|
+
...replyTo.length ? {
|
|
1221
|
+
replyTo: replyTo[0]
|
|
1222
|
+
} : {},
|
|
1223
|
+
...cfg.emailConfigId ? {
|
|
1224
|
+
emailConfigId: cfg.emailConfigId
|
|
1225
|
+
} : {}
|
|
1226
|
+
};
|
|
1227
|
+
const user = state.user;
|
|
1228
|
+
if (cfg.mode === 'template') {
|
|
1229
|
+
const variables = await mapValues(cfg.variables, env, state);
|
|
1230
|
+
const templateSlug = (cfg.templateSlug ?? '').trim();
|
|
1231
|
+
return {
|
|
1232
|
+
recipients,
|
|
1233
|
+
send: ()=>email.sendTemplate({
|
|
1234
|
+
...base,
|
|
1235
|
+
templateSlug,
|
|
1236
|
+
variables
|
|
1237
|
+
}, user)
|
|
1238
|
+
};
|
|
1239
|
+
}
|
|
1240
|
+
// A line break in a subject would start a new mail header.
|
|
1241
|
+
const subject = asText(cfg.subject === undefined ? '' : await env.ruleEngine.resolveExpression(cfg.subject, ctx)).replace(/[\r\n]+/g, ' ').trim().slice(0, flow_types/* .FLOW_LIMITS.MAX_EMAIL_SUBJECT_LENGTH */.Or.MAX_EMAIL_SUBJECT_LENGTH);
|
|
1242
|
+
if (!subject) throw new flow_errors/* .FlowHttpError */.hk(400, `The subject of "${(0,flow_types/* .nodeLabel */.dA)(node)}" is empty.`, undefined, {
|
|
1243
|
+
messageKey: message_keys/* .FLOW_ERROR_MESSAGES.EMAIL_SUBJECT_EMPTY */.zr.EMAIL_SUBJECT_EMPTY,
|
|
1244
|
+
messageVariables: {
|
|
1245
|
+
node: (0,flow_types/* .nodeLabel */.dA)(node)
|
|
1246
|
+
}
|
|
1247
|
+
});
|
|
1248
|
+
const html = cfg.format === 'html';
|
|
1249
|
+
const body = cfg.body === undefined ? '' : asText(html ? await env.ruleEngine.resolveHtml(cfg.body, ctx) : await env.ruleEngine.resolveExpression(cfg.body, ctx));
|
|
1250
|
+
if (!body.trim()) throw new flow_errors/* .FlowHttpError */.hk(400, `The message of "${(0,flow_types/* .nodeLabel */.dA)(node)}" is empty.`, undefined, {
|
|
1251
|
+
messageKey: message_keys/* .FLOW_ERROR_MESSAGES.EMAIL_BODY_EMPTY */.zr.EMAIL_BODY_EMPTY,
|
|
1252
|
+
messageVariables: {
|
|
1253
|
+
node: (0,flow_types/* .nodeLabel */.dA)(node)
|
|
1254
|
+
}
|
|
1255
|
+
});
|
|
1256
|
+
return {
|
|
1257
|
+
recipients,
|
|
1258
|
+
send: ()=>email.send({
|
|
1259
|
+
...base,
|
|
1260
|
+
subject,
|
|
1261
|
+
...html ? {
|
|
1262
|
+
html: body
|
|
1263
|
+
} : {
|
|
1264
|
+
text: body
|
|
1265
|
+
}
|
|
1266
|
+
}, user)
|
|
1267
|
+
};
|
|
1268
|
+
}
|
|
1269
|
+
/**
|
|
1270
|
+
* one: `{ status, recipients, messageId }`. many: `{ status, count, recipients, skipped, messageIds }`
|
|
1271
|
+
* (one id per email sent, in order). `status` is `sent`, or `queued` inside a transaction (sent once it
|
|
1272
|
+
* commits, no ids yet). Every email is checked before the first goes out; no address at all skips the
|
|
1273
|
+
* step, and a test run checks everything but sends nothing.
|
|
1274
|
+
*/ async function runSendEmail(node, cfg, env, state) {
|
|
1275
|
+
const email = env.email;
|
|
1276
|
+
if (!email) throw new flow_errors/* .FlowKeyedError */.Hp(message_keys/* .FLOW_ERROR_MESSAGES.EMAIL_UNAVAILABLE */.zr.EMAIL_UNAVAILABLE, {
|
|
1277
|
+
node: (0,flow_types/* .nodeLabel */.dA)(node)
|
|
1278
|
+
}, `"${(0,flow_types/* .nodeLabel */.dA)(node)}" needs the email module, which this app does not run.`);
|
|
1279
|
+
const many = cfg.target === 'many';
|
|
1280
|
+
let emails;
|
|
1281
|
+
let skippedItems = 0;
|
|
1282
|
+
if (many) {
|
|
1283
|
+
const items = await resolveList(node, cfg.items, flow_types/* .FLOW_LIMITS.MAX_MESSAGES_PER_RUN */.Or.MAX_MESSAGES_PER_RUN, env, state);
|
|
1284
|
+
const prepared = await eachItem(state, items, ()=>prepareEmail(node, cfg, email, env, state));
|
|
1285
|
+
emails = prepared.filter((item)=>item !== null);
|
|
1286
|
+
skippedItems = prepared.length - emails.length;
|
|
1287
|
+
} else {
|
|
1288
|
+
emails = [
|
|
1289
|
+
await prepareEmail(node, cfg, email, env, state)
|
|
1290
|
+
].filter((prepared)=>prepared !== null);
|
|
1291
|
+
}
|
|
1292
|
+
if (!emails.length) return nobody(many ? {
|
|
1293
|
+
count: 0,
|
|
1294
|
+
skipped: skippedItems
|
|
1295
|
+
} : {});
|
|
1296
|
+
const recipients = emails.reduce((sum, prepared)=>sum + prepared.recipients, 0);
|
|
1297
|
+
const messageIds = [];
|
|
1298
|
+
const sent = await sendAll(node, state, emails, message_keys/* .FLOW_SKIP_MESSAGES.EMAIL */.CB.EMAIL, recipients, async (prepared)=>{
|
|
1299
|
+
let result;
|
|
1300
|
+
try {
|
|
1301
|
+
result = await prepared.send();
|
|
1302
|
+
} catch (error) {
|
|
1303
|
+
throw sendFailure(message_keys/* .FLOW_ERROR_MESSAGES.EMAIL_FAILED */.zr.EMAIL_FAILED, node, error);
|
|
1304
|
+
}
|
|
1305
|
+
if (!result?.success) throw sendFailure(message_keys/* .FLOW_ERROR_MESSAGES.EMAIL_FAILED */.zr.EMAIL_FAILED, node, result?.error || 'The email was not accepted.');
|
|
1306
|
+
messageIds.push(result.messageId ?? null);
|
|
1307
|
+
});
|
|
1308
|
+
if (typeof sent !== 'string') return sent;
|
|
1309
|
+
if (!many) return {
|
|
1310
|
+
output: {
|
|
1311
|
+
status: sent,
|
|
1312
|
+
recipients,
|
|
1313
|
+
messageId: messageIds[0] ?? null
|
|
1314
|
+
}
|
|
1315
|
+
};
|
|
1316
|
+
return {
|
|
1317
|
+
output: {
|
|
1318
|
+
status: sent,
|
|
1319
|
+
count: emails.length,
|
|
1320
|
+
recipients,
|
|
1321
|
+
skipped: skippedItems,
|
|
1322
|
+
messageIds
|
|
1323
|
+
}
|
|
1324
|
+
};
|
|
1325
|
+
}
|
|
900
1326
|
/** Runs one node. Ports/branching/looping are the executor's job; this only does the node's own work. */ async function runNode(node, env, state) {
|
|
901
1327
|
const ctx = evaluationContext(state, env);
|
|
902
1328
|
const c = node.config;
|
|
@@ -911,6 +1337,8 @@ async function insertChildren(node, child, parentId, env, state) {
|
|
|
911
1337
|
return runCode(node, c, state);
|
|
912
1338
|
case 'permission_check':
|
|
913
1339
|
return runPermissionCheck(c, env, state);
|
|
1340
|
+
case 'company_branch_check':
|
|
1341
|
+
return runCompanyBranchCheck(c, env, state);
|
|
914
1342
|
case 'set':
|
|
915
1343
|
{
|
|
916
1344
|
const cfg = c;
|
|
@@ -967,7 +1395,6 @@ async function insertChildren(node, child, parentId, env, state) {
|
|
|
967
1395
|
case 'entity_get':
|
|
968
1396
|
{
|
|
969
1397
|
const cfg = c;
|
|
970
|
-
await authorize(env, state, cfg.entityCode, 'read');
|
|
971
1398
|
const id = asId(await env.ruleEngine.resolveExpression(cfg.id, ctx));
|
|
972
1399
|
const service = await env.entityService(cfg.entityCode, state.qr);
|
|
973
1400
|
try {
|
|
@@ -984,7 +1411,6 @@ async function insertChildren(node, child, parentId, env, state) {
|
|
|
984
1411
|
case 'entity_query':
|
|
985
1412
|
{
|
|
986
1413
|
const cfg = c;
|
|
987
|
-
await authorize(env, state, cfg.entityCode, 'read');
|
|
988
1414
|
const service = await env.entityService(cfg.entityCode, state.qr);
|
|
989
1415
|
const filter = await mapFilter(node, cfg.filter, env, state, 'skip');
|
|
990
1416
|
const search = cfg.search ? await env.ruleEngine.resolveExpression(cfg.search, ctx) : undefined;
|
|
@@ -1061,6 +1487,7 @@ async function insertChildren(node, child, parentId, env, state) {
|
|
|
1061
1487
|
k,
|
|
1062
1488
|
String(v ?? '')
|
|
1063
1489
|
]));
|
|
1490
|
+
if (cfg.forwardAuth === true && state.authorization && !Object.keys(headers).some((name)=>name.toLowerCase() === 'authorization')) headers['authorization'] = state.authorization;
|
|
1064
1491
|
const body = cfg.body && Object.keys(cfg.body).length ? await mapValues(cfg.body, env, state) : undefined;
|
|
1065
1492
|
const remaining = state.deadline - Date.now();
|
|
1066
1493
|
if (remaining <= 0) throw new flow_errors/* .FlowLimitError */.IM(message_keys/* .FLOW_ERROR_MESSAGES.OUT_OF_TIME */.zr.OUT_OF_TIME);
|
|
@@ -1099,6 +1526,10 @@ async function insertChildren(node, child, parentId, env, state) {
|
|
|
1099
1526
|
}
|
|
1100
1527
|
};
|
|
1101
1528
|
}
|
|
1529
|
+
case 'send_notification':
|
|
1530
|
+
return runSendNotification(node, c, env, state);
|
|
1531
|
+
case 'send_email':
|
|
1532
|
+
return runSendEmail(node, c, env, state);
|
|
1102
1533
|
case 'respond':
|
|
1103
1534
|
{
|
|
1104
1535
|
const cfg = c;
|
|
@@ -1379,14 +1810,16 @@ function successResult(state, startedAt) {
|
|
|
1379
1810
|
},
|
|
1380
1811
|
3186(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
1381
1812
|
/* import */ var _flusys_nestjs_shared_utils__rspack_import_0 = __webpack_require__(9216);
|
|
1382
|
-
/* import */ var
|
|
1383
|
-
/* import */ var
|
|
1813
|
+
/* import */ var _config_entity_builder_constants_js__rspack_import_9 = __webpack_require__(6576);
|
|
1814
|
+
/* import */ var _config_message_keys_js__rspack_import_8 = __webpack_require__(5732);
|
|
1384
1815
|
/* import */ var _interfaces_generic_record_interface_js__rspack_import_1 = __webpack_require__(3372);
|
|
1385
|
-
/* import */ var _rule_engine_index_js__rspack_import_2 = __webpack_require__(
|
|
1816
|
+
/* import */ var _rule_engine_index_js__rspack_import_2 = __webpack_require__(8429);
|
|
1386
1817
|
/* import */ var _rule_engine_rule_ip_js__rspack_import_3 = __webpack_require__(809);
|
|
1387
1818
|
/* import */ var _rule_engine_rule_permission_js__rspack_import_4 = __webpack_require__(5191);
|
|
1388
1819
|
/* import */ var _rule_engine_rule_regex_js__rspack_import_5 = __webpack_require__(6308);
|
|
1389
1820
|
/* import */ var _flow_types_js__rspack_import_6 = __webpack_require__(6256);
|
|
1821
|
+
/* import */ var _flow_api_key_js__rspack_import_7 = __webpack_require__(4816);
|
|
1822
|
+
|
|
1390
1823
|
|
|
1391
1824
|
|
|
1392
1825
|
|
|
@@ -1567,37 +2000,37 @@ function isExpression(value) {
|
|
|
1567
2000
|
return !!value && typeof value === 'object' && typeof value.type === 'string';
|
|
1568
2001
|
}
|
|
1569
2002
|
/** Expression shape check with the engine's limits (no evaluation). */ function expressionProblem(value, depth = 0, options = {}) {
|
|
1570
|
-
if (!isExpression(value)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
1571
|
-
if (depth > _rule_engine_index_js__rspack_import_2/* .RULE_ENGINE_LIMITS.MAX_GROUP_DEPTH */.bw.MAX_GROUP_DEPTH) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2003
|
+
if (!isExpression(value)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.NOT_AN_EXPRESSION */.IP.NOT_AN_EXPRESSION);
|
|
2004
|
+
if (depth > _rule_engine_index_js__rspack_import_2/* .RULE_ENGINE_LIMITS.MAX_GROUP_DEPTH */.bw.MAX_GROUP_DEPTH) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.TOO_DEEP */.IP.TOO_DEEP);
|
|
1572
2005
|
switch(value.type){
|
|
1573
2006
|
case 'literal':
|
|
1574
2007
|
return null;
|
|
1575
2008
|
case 'field_ref':
|
|
1576
|
-
return typeof value.ref === 'string' && value.ref.length > 0 ? null : (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2009
|
+
return typeof value.ref === 'string' && value.ref.length > 0 ? null : (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.EMPTY_REFERENCE */.IP.EMPTY_REFERENCE);
|
|
1577
2010
|
case 'template':
|
|
1578
|
-
if (typeof value.template !== 'string') return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
1579
|
-
return value.template.length <= _rule_engine_index_js__rspack_import_2/* .RULE_TEMPLATE_MAX_LENGTH */.ym ? null : (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2011
|
+
if (typeof value.template !== 'string') return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.NO_TEMPLATE_TEXT */.IP.NO_TEMPLATE_TEXT);
|
|
2012
|
+
return value.template.length <= _rule_engine_index_js__rspack_import_2/* .RULE_TEMPLATE_MAX_LENGTH */.ym ? null : (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.TEMPLATE_TOO_LONG */.IP.TEMPLATE_TOO_LONG);
|
|
1580
2013
|
case 'arithmetic':
|
|
1581
|
-
return Array.isArray(value.operands) ? firstProblem(value.operands, depth, options) : (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2014
|
+
return Array.isArray(value.operands) ? firstProblem(value.operands, depth, options) : (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.NO_OPERANDS */.IP.NO_OPERANDS);
|
|
1582
2015
|
case 'concat':
|
|
1583
|
-
return Array.isArray(value.parts) ? firstProblem(value.parts, depth, options) : (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2016
|
+
return Array.isArray(value.parts) ? firstProblem(value.parts, depth, options) : (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.NO_PARTS */.IP.NO_PARTS);
|
|
1584
2017
|
case 'function':
|
|
1585
2018
|
return functionProblem(value, depth, options);
|
|
1586
2019
|
case 'lookup':
|
|
1587
2020
|
return lookupProblem(value, depth, options);
|
|
1588
2021
|
default:
|
|
1589
|
-
return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2022
|
+
return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.UNKNOWN_EXPRESSION_TYPE */.IP.UNKNOWN_EXPRESSION_TYPE, {
|
|
1590
2023
|
type: value.type
|
|
1591
2024
|
});
|
|
1592
2025
|
}
|
|
1593
2026
|
}
|
|
1594
2027
|
function functionProblem(value, depth, options) {
|
|
1595
|
-
if (!Array.isArray(value.args)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2028
|
+
if (!Array.isArray(value.args)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.NO_ARGUMENTS */.IP.NO_ARGUMENTS);
|
|
1596
2029
|
const arity = FUNCTION_ARITY[value.name];
|
|
1597
|
-
if (!arity) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2030
|
+
if (!arity) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.UNKNOWN_FUNCTION */.IP.UNKNOWN_FUNCTION, {
|
|
1598
2031
|
name: String(value.name)
|
|
1599
2032
|
});
|
|
1600
|
-
if (value.args.length < arity[0] || value.args.length > arity[1]) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2033
|
+
if (value.args.length < arity[0] || value.args.length > arity[1]) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.WRONG_ARGUMENT_COUNT */.IP.WRONG_ARGUMENT_COUNT, {
|
|
1601
2034
|
name: value.name,
|
|
1602
2035
|
min: arity[0],
|
|
1603
2036
|
max: arity[1]
|
|
@@ -1605,7 +2038,7 @@ function functionProblem(value, depth, options) {
|
|
|
1605
2038
|
const unitAt = DURATION_ARG[value.name];
|
|
1606
2039
|
const unit = unitAt === undefined ? undefined : value.args[unitAt];
|
|
1607
2040
|
if (unit?.type === 'literal' && !_rule_engine_index_js__rspack_import_2/* .RULE_DURATION_UNITS.includes */.qO.includes(unit.value)) {
|
|
1608
|
-
return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2041
|
+
return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.DURATION_UNIT_INVALID */.IP.DURATION_UNIT_INVALID, {
|
|
1609
2042
|
units: _rule_engine_index_js__rspack_import_2/* .RULE_DURATION_UNITS.join */.qO.join(', ')
|
|
1610
2043
|
});
|
|
1611
2044
|
}
|
|
@@ -1628,18 +2061,18 @@ function functionProblem(value, depth, options) {
|
|
|
1628
2061
|
try {
|
|
1629
2062
|
parsed = (0,_rule_engine_rule_permission_js__rspack_import_4/* .parsePermissionCodes */.PS)(codes.value);
|
|
1630
2063
|
} catch {
|
|
1631
|
-
return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2064
|
+
return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .RULE_ENGINE_MESSAGES.TOO_MANY_PERMISSION_CODES */.x3.TOO_MANY_PERMISSION_CODES, {
|
|
1632
2065
|
max: _rule_engine_index_js__rspack_import_2/* .RULE_ENGINE_LIMITS.MAX_PERMISSION_CODES */.bw.MAX_PERMISSION_CODES
|
|
1633
2066
|
});
|
|
1634
2067
|
}
|
|
1635
|
-
return parsed.length ? null : (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2068
|
+
return parsed.length ? null : (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.PERMISSION_CODE_REQUIRED */.IP.PERMISSION_CODE_REQUIRED, {
|
|
1636
2069
|
name: value.name
|
|
1637
2070
|
});
|
|
1638
2071
|
}
|
|
1639
2072
|
if (value.name === 'IP_IN_RANGE') {
|
|
1640
2073
|
const ranges = literal(1);
|
|
1641
2074
|
const invalid = ranges.ok ? (0,_rule_engine_rule_ip_js__rspack_import_3/* .invalidIpRange */.I8)(ranges.value) : null;
|
|
1642
|
-
return invalid ? (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2075
|
+
return invalid ? (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.IP_RANGE_INVALID */.IP.IP_RANGE_INVALID, {
|
|
1643
2076
|
range: invalid
|
|
1644
2077
|
}) : null;
|
|
1645
2078
|
}
|
|
@@ -1653,13 +2086,13 @@ function functionProblem(value, depth, options) {
|
|
|
1653
2086
|
function patternProblem(pattern) {
|
|
1654
2087
|
switch((0,_rule_engine_rule_regex_js__rspack_import_5/* .rulePatternProblem */._V)(pattern)){
|
|
1655
2088
|
case 'too_long':
|
|
1656
|
-
return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2089
|
+
return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.REGEX_TOO_LONG */.IP.REGEX_TOO_LONG, {
|
|
1657
2090
|
max: _rule_engine_index_js__rspack_import_2/* .RULE_ENGINE_LIMITS.MAX_REGEX_PATTERN_LENGTH */.bw.MAX_REGEX_PATTERN_LENGTH
|
|
1658
2091
|
});
|
|
1659
2092
|
case 'invalid':
|
|
1660
|
-
return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2093
|
+
return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.REGEX_INVALID */.IP.REGEX_INVALID);
|
|
1661
2094
|
case 'too_complex':
|
|
1662
|
-
return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2095
|
+
return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.REGEX_TOO_COMPLEX */.IP.REGEX_TOO_COMPLEX, {
|
|
1663
2096
|
max: _rule_engine_index_js__rspack_import_2/* .RULE_ENGINE_LIMITS.MAX_REGEX_REPEAT */.bw.MAX_REGEX_REPEAT
|
|
1664
2097
|
});
|
|
1665
2098
|
default:
|
|
@@ -1667,20 +2100,20 @@ function patternProblem(pattern) {
|
|
|
1667
2100
|
}
|
|
1668
2101
|
}
|
|
1669
2102
|
function lookupProblem(value, depth, options) {
|
|
1670
|
-
if (typeof value.entity !== 'string' || !
|
|
1671
|
-
if (options.knownEntityCodes && !options.knownEntityCodes.has(value.entity)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2103
|
+
if (typeof value.entity !== 'string' || !_config_entity_builder_constants_js__rspack_import_9/* .ENTITY_CODE_PATTERN.test */.vs.test(value.entity)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.LOOKUP_ENTITY_INVALID */.IP.LOOKUP_ENTITY_INVALID);
|
|
2104
|
+
if (options.knownEntityCodes && !options.knownEntityCodes.has(value.entity)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.LOOKUP_ENTITY_UNKNOWN */.IP.LOOKUP_ENTITY_UNKNOWN, {
|
|
1672
2105
|
entity: value.entity
|
|
1673
2106
|
});
|
|
1674
2107
|
if (![
|
|
1675
2108
|
'exists',
|
|
1676
2109
|
'count',
|
|
1677
2110
|
'first'
|
|
1678
|
-
].includes(value.mode)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
1679
|
-
if (value.field !== undefined && (typeof value.field !== 'string' || !COLUMN_CODE.test(value.field))) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
1680
|
-
if (value.sort !== undefined && (typeof value.sort?.field !== 'string' || !COLUMN_CODE.test(value.sort.field))) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
1681
|
-
if (!value.filter || typeof value.filter !== 'object' || Array.isArray(value.filter)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2111
|
+
].includes(value.mode)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.LOOKUP_MODE_INVALID */.IP.LOOKUP_MODE_INVALID);
|
|
2112
|
+
if (value.field !== undefined && (typeof value.field !== 'string' || !COLUMN_CODE.test(value.field))) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.LOOKUP_FIELD_INVALID */.IP.LOOKUP_FIELD_INVALID);
|
|
2113
|
+
if (value.sort !== undefined && (typeof value.sort?.field !== 'string' || !COLUMN_CODE.test(value.sort.field))) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.LOOKUP_FIELD_INVALID */.IP.LOOKUP_FIELD_INVALID);
|
|
2114
|
+
if (!value.filter || typeof value.filter !== 'object' || Array.isArray(value.filter)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.LOOKUP_FILTER_INVALID */.IP.LOOKUP_FILTER_INVALID);
|
|
1682
2115
|
for (const [key, item] of Object.entries(value.filter)){
|
|
1683
|
-
if (!COLUMN_CODE.test(key)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2116
|
+
if (!COLUMN_CODE.test(key)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.LOOKUP_FILTER_INVALID */.IP.LOOKUP_FILTER_INVALID);
|
|
1684
2117
|
const problem = filterValueProblem(item, depth, options);
|
|
1685
2118
|
if (problem) return problem;
|
|
1686
2119
|
}
|
|
@@ -1689,13 +2122,13 @@ function lookupProblem(value, depth, options) {
|
|
|
1689
2122
|
/** A filter entry: an expression (eq) or `{ op, value? }` with an expression value. */ function filterValueProblem(item, depth, options) {
|
|
1690
2123
|
if (!(0,_interfaces_generic_record_interface_js__rspack_import_1/* .isRecordFilterCondition */.t1)(item)) {
|
|
1691
2124
|
const op = item && typeof item === 'object' && !Array.isArray(item) && !('type' in item) ? item.op : undefined;
|
|
1692
|
-
if (typeof op === 'string' && !_interfaces_generic_record_interface_js__rspack_import_1/* .RECORD_FILTER_OPS.includes */.ox.includes(op)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2125
|
+
if (typeof op === 'string' && !_interfaces_generic_record_interface_js__rspack_import_1/* .RECORD_FILTER_OPS.includes */.ox.includes(op)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.FILTER_OPERATOR_UNKNOWN */.IP.FILTER_OPERATOR_UNKNOWN, {
|
|
1693
2126
|
op
|
|
1694
2127
|
});
|
|
1695
2128
|
return expressionProblem(item, depth + 1, options);
|
|
1696
2129
|
}
|
|
1697
2130
|
if (item.op === 'is_null' || item.op === 'not_null') return null;
|
|
1698
|
-
if (item.value === undefined) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2131
|
+
if (item.value === undefined) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.FILTER_VALUE_REQUIRED */.IP.FILTER_VALUE_REQUIRED, {
|
|
1699
2132
|
op: item.op
|
|
1700
2133
|
});
|
|
1701
2134
|
return expressionProblem(item.value, depth + 1, options);
|
|
@@ -1709,8 +2142,8 @@ function firstProblem(items, depth, options) {
|
|
|
1709
2142
|
}
|
|
1710
2143
|
function conditionProblem(node, options) {
|
|
1711
2144
|
const hasLeft = node?.left !== undefined;
|
|
1712
|
-
if (!node || !hasLeft && (typeof node.field !== 'string' || !node.field) || typeof node.comparison !== 'string') return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
1713
|
-
if (!_rule_engine_index_js__rspack_import_2/* .RULE_COMPARISON_OPERATORS.includes */.dJ.includes(node.comparison)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2145
|
+
if (!node || !hasLeft && (typeof node.field !== 'string' || !node.field) || typeof node.comparison !== 'string') return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.CONDITION_INCOMPLETE */.IP.CONDITION_INCOMPLETE);
|
|
2146
|
+
if (!_rule_engine_index_js__rspack_import_2/* .RULE_COMPARISON_OPERATORS.includes */.dJ.includes(node.comparison)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.UNKNOWN_COMPARISON */.IP.UNKNOWN_COMPARISON, {
|
|
1714
2147
|
comparison: node.comparison
|
|
1715
2148
|
});
|
|
1716
2149
|
if (hasLeft) {
|
|
@@ -1726,15 +2159,15 @@ function conditionProblem(node, options) {
|
|
|
1726
2159
|
return null;
|
|
1727
2160
|
}
|
|
1728
2161
|
/** Rule group shape check with the engine's limits (no evaluation). */ function groupProblem(group, depth = 0, options = {}) {
|
|
1729
|
-
if (!group || typeof group !== 'object' || !Array.isArray(group.conditions)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2162
|
+
if (!group || typeof group !== 'object' || !Array.isArray(group.conditions)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.NOT_A_RULE */.IP.NOT_A_RULE);
|
|
1730
2163
|
const g = group;
|
|
1731
|
-
if (depth > _rule_engine_index_js__rspack_import_2/* .RULE_ENGINE_LIMITS.MAX_GROUP_DEPTH */.bw.MAX_GROUP_DEPTH) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
1732
|
-
if (g.conditions.length > _rule_engine_index_js__rspack_import_2/* .RULE_ENGINE_LIMITS.MAX_CONDITIONS_PER_GROUP */.bw.MAX_CONDITIONS_PER_GROUP) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2164
|
+
if (depth > _rule_engine_index_js__rspack_import_2/* .RULE_ENGINE_LIMITS.MAX_GROUP_DEPTH */.bw.MAX_GROUP_DEPTH) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.TOO_DEEP */.IP.TOO_DEEP);
|
|
2165
|
+
if (g.conditions.length > _rule_engine_index_js__rspack_import_2/* .RULE_ENGINE_LIMITS.MAX_CONDITIONS_PER_GROUP */.bw.MAX_CONDITIONS_PER_GROUP) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.TOO_MANY_CONDITIONS */.IP.TOO_MANY_CONDITIONS);
|
|
1733
2166
|
if (![
|
|
1734
2167
|
'AND',
|
|
1735
2168
|
'OR',
|
|
1736
2169
|
'NOT'
|
|
1737
|
-
].includes(g.operator)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2170
|
+
].includes(g.operator)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SHAPE_MESSAGES.UNKNOWN_OPERATOR */.IP.UNKNOWN_OPERATOR);
|
|
1738
2171
|
for (const node of g.conditions){
|
|
1739
2172
|
const problem = node && (0,_rule_engine_index_js__rspack_import_2/* .isRuleGroup */.GD)(node) ? groupProblem(node, depth + 1, options) : conditionProblem(node, options);
|
|
1740
2173
|
if (problem) return problem;
|
|
@@ -1744,30 +2177,20 @@ function conditionProblem(node, options) {
|
|
|
1744
2177
|
/**
|
|
1745
2178
|
* Save-time check of a whole flow: structure (Request steps with distinct URLs, valid ids/ports, no cycles),
|
|
1746
2179
|
* every node's configuration, every reference to another node, and the combination of
|
|
1747
|
-
* settings (
|
|
2180
|
+
* settings (auth / transaction). Pure: no I/O, so the same result is what the
|
|
1748
2181
|
* designer shows and what the server enforces.
|
|
1749
2182
|
*/ function validateFlow(flow, context = {}) {
|
|
1750
2183
|
const errors = [];
|
|
1751
2184
|
const warnings = [];
|
|
1752
2185
|
const err = (message)=>errors.push(message);
|
|
1753
|
-
if (!_flow_types_js__rspack_import_6/* .FLOW_SLUG_PATTERN.test */.YD.test(flow.slug ?? '')) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
1754
|
-
if (!_flow_types_js__rspack_import_6/* .FLOW_RUN_AS.includes */.gl.includes(flow.runAs)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.RUN_AS_INVALID */.qj.RUN_AS_INVALID, {
|
|
1755
|
-
runAs: String(flow.runAs)
|
|
1756
|
-
}));
|
|
1757
|
-
if (!_flow_types_js__rspack_import_6/* .FLOW_AUTH_MODES.includes */.fO.includes(flow.authMode)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.AUTH_MODE_INVALID */.qj.AUTH_MODE_INVALID, {
|
|
1758
|
-
authMode: String(flow.authMode)
|
|
1759
|
-
}));
|
|
1760
|
-
if (flow.runAs === 'caller' && flow.authMode !== 'jwt' && flow.authMode !== 'permission' && flow.authMode !== 'internal') {
|
|
1761
|
-
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.RUN_AS_CALLER_NEEDS_AUTH */.qj.RUN_AS_CALLER_NEEDS_AUTH));
|
|
1762
|
-
}
|
|
1763
|
-
validateInputSchema(flow, err);
|
|
2186
|
+
if (!_flow_types_js__rspack_import_6/* .FLOW_SLUG_PATTERN.test */.YD.test(flow.slug ?? '')) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.SLUG_INVALID */.qj.SLUG_INVALID));
|
|
1764
2187
|
const nodes = Array.isArray(flow.nodes) ? flow.nodes : [];
|
|
1765
2188
|
const edges = Array.isArray(flow.edges) ? flow.edges : [];
|
|
1766
|
-
if (!nodes.length) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
1767
|
-
if (nodes.length > _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_NODES */.Or.MAX_NODES) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2189
|
+
if (!nodes.length) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NO_NODES */.qj.NO_NODES));
|
|
2190
|
+
if (nodes.length > _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_NODES */.Or.MAX_NODES) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.TOO_MANY_NODES */.qj.TOO_MANY_NODES, {
|
|
1768
2191
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_NODES */.Or.MAX_NODES
|
|
1769
2192
|
}));
|
|
1770
|
-
if (edges.length > _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_EDGES */.Or.MAX_EDGES) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2193
|
+
if (edges.length > _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_EDGES */.Or.MAX_EDGES) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.TOO_MANY_EDGES */.qj.TOO_MANY_EDGES, {
|
|
1771
2194
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_EDGES */.Or.MAX_EDGES
|
|
1772
2195
|
}));
|
|
1773
2196
|
if (errors.length && (!nodes.length || nodes.length > _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_NODES */.Or.MAX_NODES || edges.length > _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_EDGES */.Or.MAX_EDGES)) return {
|
|
@@ -1777,16 +2200,16 @@ function conditionProblem(node, options) {
|
|
|
1777
2200
|
const byId = new Map();
|
|
1778
2201
|
for (const node of nodes){
|
|
1779
2202
|
if (!_flow_types_js__rspack_import_6/* .FLOW_NODE_ID_PATTERN.test */.z6.test(node?.id ?? '')) {
|
|
1780
|
-
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2203
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_ID_INVALID */.qj.NODE_ID_INVALID, {
|
|
1781
2204
|
id: node?.id
|
|
1782
2205
|
}));
|
|
1783
2206
|
continue;
|
|
1784
2207
|
}
|
|
1785
|
-
if (byId.has(node.id)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2208
|
+
if (byId.has(node.id)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_ID_DUPLICATE */.qj.NODE_ID_DUPLICATE, {
|
|
1786
2209
|
id: node.id
|
|
1787
2210
|
}));
|
|
1788
2211
|
byId.set(node.id, node);
|
|
1789
|
-
if (!_flow_types_js__rspack_import_6/* .FLOW_NODE_TYPES.includes */.q2.includes(node.type)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2212
|
+
if (!_flow_types_js__rspack_import_6/* .FLOW_NODE_TYPES.includes */.q2.includes(node.type)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_TYPE_UNKNOWN */.qj.NODE_TYPE_UNKNOWN, {
|
|
1790
2213
|
id: node.id,
|
|
1791
2214
|
type: node.type
|
|
1792
2215
|
}));
|
|
@@ -1799,24 +2222,24 @@ function conditionProblem(node, options) {
|
|
|
1799
2222
|
const outgoing = new Map();
|
|
1800
2223
|
const edgeIds = new Set();
|
|
1801
2224
|
for (const edge of edges){
|
|
1802
|
-
if (edgeIds.has(edge.id)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2225
|
+
if (edgeIds.has(edge.id)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.EDGE_ID_DUPLICATE */.qj.EDGE_ID_DUPLICATE, {
|
|
1803
2226
|
id: edge.id
|
|
1804
2227
|
}));
|
|
1805
2228
|
edgeIds.add(edge.id);
|
|
1806
2229
|
const from = byId.get(edge.from);
|
|
1807
2230
|
const to = byId.get(edge.to);
|
|
1808
2231
|
if (!from || !to) {
|
|
1809
|
-
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2232
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.EDGE_DANGLING */.qj.EDGE_DANGLING, {
|
|
1810
2233
|
from: edge.from,
|
|
1811
2234
|
to: edge.to
|
|
1812
2235
|
}));
|
|
1813
2236
|
continue;
|
|
1814
2237
|
}
|
|
1815
|
-
if (edge.from === edge.to) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2238
|
+
if (edge.from === edge.to) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.EDGE_SELF */.qj.EDGE_SELF, {
|
|
1816
2239
|
id: edge.from
|
|
1817
2240
|
}));
|
|
1818
|
-
if (to.type === 'trigger') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
1819
|
-
if (!(0,_flow_types_js__rspack_import_6/* .portsOf */.a5)(from).includes(edge.port)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2241
|
+
if (to.type === 'trigger') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.EDGE_INTO_TRIGGER */.qj.EDGE_INTO_TRIGGER));
|
|
2242
|
+
if (!(0,_flow_types_js__rspack_import_6/* .portsOf */.a5)(from).includes(edge.port)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.EDGE_NO_PORT */.qj.EDGE_NO_PORT, {
|
|
1820
2243
|
id: from.id,
|
|
1821
2244
|
port: edge.port
|
|
1822
2245
|
}));
|
|
@@ -1832,111 +2255,191 @@ function conditionProblem(node, options) {
|
|
|
1832
2255
|
const seenPairs = new Set();
|
|
1833
2256
|
for (const edge of edges){
|
|
1834
2257
|
const key = `${edge.from}|${edge.port}|${edge.to}`;
|
|
1835
|
-
if (seenPairs.has(key)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2258
|
+
if (seenPairs.has(key)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.EDGE_TWICE */.qj.EDGE_TWICE, {
|
|
1836
2259
|
from: edge.from,
|
|
1837
2260
|
to: edge.to
|
|
1838
2261
|
}));
|
|
1839
2262
|
seenPairs.add(key);
|
|
1840
2263
|
}
|
|
1841
2264
|
const cyclic = hasCycle(nodes, outgoing);
|
|
1842
|
-
if (cyclic) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2265
|
+
if (cyclic) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.CYCLE */.qj.CYCLE));
|
|
1843
2266
|
const reachable = triggers.length ? new Set(triggers.flatMap((trigger)=>[
|
|
1844
2267
|
...reach(trigger.id, outgoing)
|
|
1845
2268
|
])) : null;
|
|
1846
2269
|
for (const node of nodes){
|
|
1847
|
-
if (reachable && !reachable.has(node.id)) warnings.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2270
|
+
if (reachable && !reachable.has(node.id)) warnings.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_UNREACHABLE */.qj.NODE_UNREACHABLE, {
|
|
1848
2271
|
node: (0,_flow_types_js__rspack_import_6/* .nodeLabel */.dA)(node)
|
|
1849
2272
|
}));
|
|
1850
2273
|
}
|
|
1851
2274
|
checkNodeReferences(nodes, byId, flow, err, warnings);
|
|
1852
2275
|
if (!cyclic && reachable) checkReferenceTiming(nodes, edges, byId, reachable, warnings);
|
|
1853
2276
|
if (!cyclic) checkLoopDepth(nodes, outgoing, err);
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
2277
|
+
// Transaction and access are a Request step's own: each is checked against the steps its runs reach.
|
|
2278
|
+
const runs = (0,_flow_types_js__rspack_import_6/* .flowEndpoints */.Xr)(flow).map((endpoint)=>({
|
|
2279
|
+
endpoint,
|
|
2280
|
+
label: (0,_flow_types_js__rspack_import_6/* .nodeLabel */.dA)(byId.get(endpoint.nodeId) ?? {
|
|
2281
|
+
id: endpoint.nodeId,
|
|
2282
|
+
name: ''
|
|
2283
|
+
}),
|
|
2284
|
+
steps: [
|
|
2285
|
+
...reach(endpoint.nodeId, outgoing)
|
|
2286
|
+
].map((id)=>byId.get(id)).filter((node)=>!!node)
|
|
2287
|
+
}));
|
|
2288
|
+
checkEndpointRuns(runs, warnings);
|
|
2289
|
+
checkTransactionUse(flow, runs, outgoing, context, warnings);
|
|
1864
2290
|
return {
|
|
1865
2291
|
errors,
|
|
1866
2292
|
warnings
|
|
1867
2293
|
};
|
|
1868
2294
|
}
|
|
2295
|
+
/** The entities a step reads or writes: its own, its child inserts' and those its lookups read. */ function entitiesOf(node) {
|
|
2296
|
+
const codes = collectLookupEntities(node.config);
|
|
2297
|
+
if (node.type.startsWith('entity_') && typeof node.config?.['entityCode'] === 'string') codes.add(node.config['entityCode']);
|
|
2298
|
+
const children = node.type === 'entity_insert' && Array.isArray(node.config?.['children']) ? node.config['children'] : [];
|
|
2299
|
+
for (const child of children)if (typeof child?.entityCode === 'string') codes.add(child.entityCode);
|
|
2300
|
+
return [
|
|
2301
|
+
...codes
|
|
2302
|
+
];
|
|
2303
|
+
}
|
|
2304
|
+
/** What depends on a Request step's access and transaction, for the steps its runs reach. A finding shared by several Request steps is reported once. */ function checkEndpointRuns(runs, warnings) {
|
|
2305
|
+
const reported = new Set();
|
|
2306
|
+
const warnOnce = (message)=>{
|
|
2307
|
+
const key = JSON.stringify(message);
|
|
2308
|
+
if (reported.has(key)) return;
|
|
2309
|
+
reported.add(key);
|
|
2310
|
+
warnings.push(message);
|
|
2311
|
+
};
|
|
2312
|
+
const keyless = {
|
|
2313
|
+
endpoints: [],
|
|
2314
|
+
entities: new Set()
|
|
2315
|
+
};
|
|
2316
|
+
for (const { endpoint, label, steps } of runs){
|
|
2317
|
+
if (endpoint.isTransactional) {
|
|
2318
|
+
if (steps.some((n)=>n.type === 'http_request')) warnings.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.TRANSACTIONAL_HTTP */.qj.TRANSACTIONAL_HTTP, {
|
|
2319
|
+
node: label
|
|
2320
|
+
}));
|
|
2321
|
+
// Inside the run's transaction a message is only sent once it commits: a failed send is logged, it cannot take the error path.
|
|
2322
|
+
for (const n of steps)if ((0,_flow_types_js__rspack_import_6/* .isMessageNode */.SE)(n.type) && n.onError === 'continue') warnOnce((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.MESSAGE_AFTER_COMMIT */.qj.MESSAGE_AFTER_COMMIT, {
|
|
2323
|
+
node: (0,_flow_types_js__rspack_import_6/* .nodeLabel */.dA)(n)
|
|
2324
|
+
}));
|
|
2325
|
+
}
|
|
2326
|
+
if (endpoint.authMode === 'public' && steps.some((n)=>(0,_flow_types_js__rspack_import_6/* .isMessageNode */.SE)(n.type))) warnOnce((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.PUBLIC_MESSAGE */.qj.PUBLIC_MESSAGE));
|
|
2327
|
+
// 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.
|
|
2328
|
+
if (!_flow_types_js__rspack_import_6/* .KEYLESS_AUTH_MODES.has */.d7.has(endpoint.authMode)) continue;
|
|
2329
|
+
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_8/* .FLOW_VALIDATION_MESSAGES.PERMISSION_WITHOUT_USER */.qj.PERMISSION_WITHOUT_USER));
|
|
2330
|
+
const entities = steps.flatMap(entitiesOf);
|
|
2331
|
+
if (!entities.length) continue;
|
|
2332
|
+
keyless.endpoints.push(endpoint.path ? `/${endpoint.path}` : '/');
|
|
2333
|
+
for (const code of entities)keyless.entities.add(code);
|
|
2334
|
+
}
|
|
2335
|
+
if (keyless.endpoints.length) warnings.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.KEYLESS_ENTITY */.qj.KEYLESS_ENTITY, {
|
|
2336
|
+
endpoints: keyless.endpoints.join(', '),
|
|
2337
|
+
entities: [
|
|
2338
|
+
...keyless.entities
|
|
2339
|
+
].join(', ')
|
|
2340
|
+
}));
|
|
2341
|
+
}
|
|
1869
2342
|
/** At least one Request step; at most one on the flow's own URL, the others on distinct paths. */ function checkTriggers(triggers, err) {
|
|
1870
|
-
if (!triggers.length) return err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2343
|
+
if (!triggers.length) return err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.TRIGGER_MISSING */.qj.TRIGGER_MISSING));
|
|
1871
2344
|
const main = triggers.filter((trigger)=>!(0,_flow_types_js__rspack_import_6/* .triggerPath */.um)(trigger));
|
|
1872
|
-
if (main.length > 1) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2345
|
+
if (main.length > 1) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.TRIGGER_MAIN_DUPLICATE */.qj.TRIGGER_MAIN_DUPLICATE, {
|
|
1873
2346
|
count: main.length
|
|
1874
2347
|
}));
|
|
1875
2348
|
const paths = new Set();
|
|
1876
2349
|
for (const trigger of triggers){
|
|
1877
2350
|
const path = (0,_flow_types_js__rspack_import_6/* .triggerPath */.um)(trigger);
|
|
1878
2351
|
if (!path) continue;
|
|
1879
|
-
if (paths.has(path)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2352
|
+
if (paths.has(path)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.TRIGGER_PATH_DUPLICATE */.qj.TRIGGER_PATH_DUPLICATE, {
|
|
1880
2353
|
path
|
|
1881
2354
|
}));
|
|
1882
2355
|
paths.add(path);
|
|
1883
2356
|
}
|
|
1884
2357
|
}
|
|
1885
2358
|
/**
|
|
1886
|
-
* What the runtime would always refuse, caught on save: an API-key flow
|
|
1887
|
-
*
|
|
2359
|
+
* What the runtime would always refuse, caught on save: an API-key URL (a flow has no key to send),
|
|
2360
|
+
* a required input left out, a chain that comes back to this flow or nests deeper
|
|
1888
2361
|
* than the limit. An inactive flow and an input the called flow does not declare are warnings.
|
|
1889
|
-
*/ function checkCalledFlow(
|
|
2362
|
+
*/ function checkCalledFlow(node, flow, known, err, warn) {
|
|
2363
|
+
const { flowSlug: slug, endpoint, input, inputList } = node.config;
|
|
2364
|
+
const at = {
|
|
2365
|
+
node: (0,_flow_types_js__rspack_import_6/* .nodeLabel */.dA)(node)
|
|
2366
|
+
};
|
|
1890
2367
|
const target = known.get(slug);
|
|
1891
2368
|
const vars = {
|
|
1892
2369
|
...at,
|
|
1893
2370
|
flow: slug
|
|
1894
2371
|
};
|
|
1895
|
-
if (!target.isActive) warn.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
1896
|
-
if (target.authMode === 'api_key') {
|
|
1897
|
-
// A function runs as whoever calls it, so it fails only when a flow running as the caller does.
|
|
1898
|
-
if (flow.authMode === 'internal') warn.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.NODE_FLOW_API_KEY */.qj.NODE_FLOW_API_KEY, vars));
|
|
1899
|
-
else if (flow.runAs === 'caller') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.NODE_FLOW_API_KEY */.qj.NODE_FLOW_API_KEY, vars));
|
|
1900
|
-
}
|
|
2372
|
+
if (!target.isActive) warn.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_FLOW_INACTIVE */.qj.NODE_FLOW_INACTIVE, vars));
|
|
1901
2373
|
const path = typeof endpoint === 'string' && endpoint ? endpoint : null;
|
|
1902
2374
|
const entry = target.endpoints.find((e)=>e.path === path);
|
|
2375
|
+
// A flow has no key to send, so an API-key URL is never callable from one.
|
|
2376
|
+
if (entry?.authMode === 'api_key') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_FLOW_API_KEY */.qj.NODE_FLOW_API_KEY, vars));
|
|
1903
2377
|
if (!entry) {
|
|
1904
|
-
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(path ?
|
|
2378
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(path ? _config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_FLOW_ENDPOINT_UNKNOWN */.qj.NODE_FLOW_ENDPOINT_UNKNOWN : _config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_FLOW_ENDPOINT_REQUIRED */.qj.NODE_FLOW_ENDPOINT_REQUIRED, {
|
|
1905
2379
|
...vars,
|
|
1906
2380
|
endpoint: path ?? ''
|
|
1907
2381
|
}));
|
|
1908
2382
|
} else if (entry.bodyType === 'list') {
|
|
1909
|
-
if (inputList === undefined) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2383
|
+
if (inputList === undefined) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_FLOW_INPUT_LIST_REQUIRED */.qj.NODE_FLOW_INPUT_LIST_REQUIRED, vars));
|
|
1910
2384
|
} else if (inputList !== undefined) {
|
|
1911
|
-
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2385
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_FLOW_INPUT_LIST_UNEXPECTED */.qj.NODE_FLOW_INPUT_LIST_UNEXPECTED, vars));
|
|
1912
2386
|
} else {
|
|
1913
2387
|
checkCalledInputs(input, entry.inputSchema, vars, err, warn);
|
|
1914
2388
|
}
|
|
1915
2389
|
const loop = callPathTo(slug, flow.slug, known, new Set());
|
|
1916
|
-
if (loop) return err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2390
|
+
if (loop) return err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_FLOW_LOOP */.qj.NODE_FLOW_LOOP, {
|
|
1917
2391
|
...at,
|
|
1918
2392
|
chain: [
|
|
1919
2393
|
flow.slug,
|
|
1920
2394
|
...loop
|
|
1921
2395
|
].join(' > ')
|
|
1922
2396
|
}));
|
|
1923
|
-
if (1 + callDepth(slug, known, new Set()) > _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_CALL_DEPTH */.Or.MAX_CALL_DEPTH) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2397
|
+
if (1 + callDepth(slug, known, new Set()) > _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_CALL_DEPTH */.Or.MAX_CALL_DEPTH) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_FLOW_TOO_DEEP */.qj.NODE_FLOW_TOO_DEEP, {
|
|
1924
2398
|
...at,
|
|
1925
2399
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_CALL_DEPTH */.Or.MAX_CALL_DEPTH
|
|
1926
2400
|
}));
|
|
1927
2401
|
}
|
|
2402
|
+
/**
|
|
2403
|
+
* What the Call flow steps of `caller` whose call chain reaches `slug` (that flow itself, or one
|
|
2404
|
+
* that calls it, however deep) would hit against the flows in `known`: the save errors of those
|
|
2405
|
+
* steps, and the flow they run being off (a warning on save, a failure at run).
|
|
2406
|
+
*/ function callProblems(caller, slug, known) {
|
|
2407
|
+
const problems = [];
|
|
2408
|
+
for (const node of Array.isArray(caller.nodes) ? caller.nodes : []){
|
|
2409
|
+
const c = node?.config ?? {};
|
|
2410
|
+
if (node?.type !== 'call_flow' || typeof c.flowSlug !== 'string') continue;
|
|
2411
|
+
if (c.flowSlug !== slug && !callPathTo(c.flowSlug, slug, known, new Set())) continue;
|
|
2412
|
+
const at = {
|
|
2413
|
+
node: (0,_flow_types_js__rspack_import_6/* .nodeLabel */.dA)(node)
|
|
2414
|
+
};
|
|
2415
|
+
const target = known.get(c.flowSlug);
|
|
2416
|
+
if (!target) {
|
|
2417
|
+
problems.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_FLOW_UNKNOWN */.qj.NODE_FLOW_UNKNOWN, {
|
|
2418
|
+
...at,
|
|
2419
|
+
flow: c.flowSlug
|
|
2420
|
+
}));
|
|
2421
|
+
continue;
|
|
2422
|
+
}
|
|
2423
|
+
if (!target.isActive) problems.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_FLOW_INACTIVE */.qj.NODE_FLOW_INACTIVE, {
|
|
2424
|
+
...at,
|
|
2425
|
+
flow: c.flowSlug
|
|
2426
|
+
}));
|
|
2427
|
+
checkCalledFlow(node, caller, known, (m)=>problems.push(m), []);
|
|
2428
|
+
}
|
|
2429
|
+
return problems;
|
|
2430
|
+
}
|
|
1928
2431
|
/** The named inputs sent to a flow whose body is an object: every required one given, the rest declared. */ function checkCalledInputs(input, schema, vars, err, warn) {
|
|
1929
2432
|
const given = input && typeof input === 'object' && !Array.isArray(input) ? Object.keys(input) : [];
|
|
1930
2433
|
if (schema.length) {
|
|
1931
2434
|
const declared = new Set(schema.map((field)=>field.name));
|
|
1932
|
-
for (const name of given)if (!declared.has(name)) warn.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2435
|
+
for (const name of given)if (!declared.has(name)) warn.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_FLOW_INPUT_UNDECLARED */.qj.NODE_FLOW_INPUT_UNDECLARED, {
|
|
1933
2436
|
...vars,
|
|
1934
2437
|
input: name
|
|
1935
2438
|
}));
|
|
1936
2439
|
}
|
|
1937
2440
|
for (const field of schema){
|
|
1938
2441
|
if (field.required && (field.default === undefined || field.default === null) && !given.includes(field.name)) {
|
|
1939
|
-
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2442
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_FLOW_INPUT_MISSING */.qj.NODE_FLOW_INPUT_MISSING, {
|
|
1940
2443
|
...vars,
|
|
1941
2444
|
input: field.name
|
|
1942
2445
|
}));
|
|
@@ -1966,42 +2469,36 @@ function conditionProblem(node, options) {
|
|
|
1966
2469
|
running.delete(slug);
|
|
1967
2470
|
return deepest;
|
|
1968
2471
|
}
|
|
1969
|
-
function validateInputSchema(flow, err) {
|
|
1970
|
-
if (flow.bodyType !== undefined && !_flow_types_js__rspack_import_6/* .FLOW_BODY_TYPES.includes */.Y3.includes(flow.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, {
|
|
1971
|
-
type: String(flow.bodyType)
|
|
1972
|
-
}));
|
|
1973
|
-
validateInputFields(flow.inputSchema ?? [], '', 1, err);
|
|
1974
|
-
}
|
|
1975
2472
|
/** One level of the request body: the top-level fields, or the fields of an object / list item at `prefix`. */ function validateInputFields(fields, prefix, depth, err) {
|
|
1976
|
-
if (fields.length > _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_INPUT_FIELDS */.Or.MAX_INPUT_FIELDS) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2473
|
+
if (fields.length > _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_INPUT_FIELDS */.Or.MAX_INPUT_FIELDS) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.INPUT_TOO_MANY */.qj.INPUT_TOO_MANY, {
|
|
1977
2474
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_INPUT_FIELDS */.Or.MAX_INPUT_FIELDS
|
|
1978
2475
|
}));
|
|
1979
2476
|
const seen = new Set();
|
|
1980
2477
|
for (const field of fields){
|
|
1981
2478
|
const name = `${prefix}${field?.name ?? ''}`;
|
|
1982
|
-
if (!_flow_types_js__rspack_import_6/* .FLOW_INPUT_NAME_PATTERN.test */.fZ.test(field?.name ?? '')) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2479
|
+
if (!_flow_types_js__rspack_import_6/* .FLOW_INPUT_NAME_PATTERN.test */.fZ.test(field?.name ?? '')) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.INPUT_NAME_INVALID */.qj.INPUT_NAME_INVALID, {
|
|
1983
2480
|
name
|
|
1984
2481
|
}));
|
|
1985
|
-
else if (seen.has(field.name)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2482
|
+
else if (seen.has(field.name)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.INPUT_NAME_DUPLICATE */.qj.INPUT_NAME_DUPLICATE, {
|
|
1986
2483
|
name
|
|
1987
2484
|
}));
|
|
1988
2485
|
seen.add(field?.name);
|
|
1989
|
-
if (!_flow_types_js__rspack_import_6/* .FLOW_INPUT_TYPES.includes */.Q7.includes(field?.type)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2486
|
+
if (!_flow_types_js__rspack_import_6/* .FLOW_INPUT_TYPES.includes */.Q7.includes(field?.type)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.INPUT_TYPE_UNKNOWN */.qj.INPUT_TYPE_UNKNOWN, {
|
|
1990
2487
|
name,
|
|
1991
2488
|
type: field?.type
|
|
1992
2489
|
}));
|
|
1993
2490
|
const itemType = field?.type === 'array' ? field.itemType : undefined;
|
|
1994
|
-
if (itemType !== undefined && (itemType === 'array' || !_flow_types_js__rspack_import_6/* .FLOW_INPUT_TYPES.includes */.Q7.includes(itemType))) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2491
|
+
if (itemType !== undefined && (itemType === 'array' || !_flow_types_js__rspack_import_6/* .FLOW_INPUT_TYPES.includes */.Q7.includes(itemType))) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.INPUT_ITEM_TYPE_UNKNOWN */.qj.INPUT_ITEM_TYPE_UNKNOWN, {
|
|
1995
2492
|
name,
|
|
1996
2493
|
type: itemType
|
|
1997
2494
|
}));
|
|
1998
|
-
if ((field?.type === 'choice' || itemType === 'choice') && !field.options?.length) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2495
|
+
if ((field?.type === 'choice' || itemType === 'choice') && !field.options?.length) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.INPUT_CHOICE_NO_OPTIONS */.qj.INPUT_CHOICE_NO_OPTIONS, {
|
|
1999
2496
|
name
|
|
2000
2497
|
}));
|
|
2001
2498
|
const holdsFields = field?.type === 'object' || itemType === 'object';
|
|
2002
2499
|
if (!holdsFields || !Array.isArray(field.fields) || !field.fields.length) continue;
|
|
2003
2500
|
if (depth >= _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_INPUT_DEPTH */.Or.MAX_INPUT_DEPTH) {
|
|
2004
|
-
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2501
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.INPUT_TOO_DEEP */.qj.INPUT_TOO_DEEP, {
|
|
2005
2502
|
name,
|
|
2006
2503
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_INPUT_DEPTH */.Or.MAX_INPUT_DEPTH
|
|
2007
2504
|
}));
|
|
@@ -2020,7 +2517,7 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2020
2517
|
};
|
|
2021
2518
|
const expr = (value, what)=>{
|
|
2022
2519
|
const problem = expressionProblem(value, 0, shape);
|
|
2023
|
-
if (problem) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2520
|
+
if (problem) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_EXPRESSION_PROBLEM */.qj.NODE_EXPRESSION_PROBLEM, {
|
|
2024
2521
|
...at,
|
|
2025
2522
|
what,
|
|
2026
2523
|
problem
|
|
@@ -2028,7 +2525,7 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2028
2525
|
};
|
|
2029
2526
|
const exprMap = (value, kind)=>{
|
|
2030
2527
|
if (value === undefined) return;
|
|
2031
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) return err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2528
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_PAIRS_INVALID */.qj.NODE_PAIRS_INVALID, {
|
|
2032
2529
|
...at,
|
|
2033
2530
|
what: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(kind.list)
|
|
2034
2531
|
}));
|
|
@@ -2038,13 +2535,13 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2038
2535
|
};
|
|
2039
2536
|
const filterMap = (value, kind)=>{
|
|
2040
2537
|
if (value === undefined) return;
|
|
2041
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) return err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2538
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_PAIRS_INVALID */.qj.NODE_PAIRS_INVALID, {
|
|
2042
2539
|
...at,
|
|
2043
2540
|
what: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(kind.list)
|
|
2044
2541
|
}));
|
|
2045
2542
|
for (const [key, item] of Object.entries(value)){
|
|
2046
2543
|
const problem = filterValueProblem(item, -1, shape);
|
|
2047
|
-
if (problem) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2544
|
+
if (problem) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_EXPRESSION_PROBLEM */.qj.NODE_EXPRESSION_PROBLEM, {
|
|
2048
2545
|
...at,
|
|
2049
2546
|
what: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(kind.item, {
|
|
2050
2547
|
name: key
|
|
@@ -2055,115 +2552,172 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2055
2552
|
};
|
|
2056
2553
|
const rule = (value, what)=>{
|
|
2057
2554
|
const problem = groupProblem(value, 0, shape);
|
|
2058
|
-
if (problem) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2555
|
+
if (problem) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_RULE_PROBLEM */.qj.NODE_RULE_PROBLEM, {
|
|
2059
2556
|
...at,
|
|
2060
2557
|
what,
|
|
2061
2558
|
problem
|
|
2062
2559
|
}));
|
|
2063
2560
|
};
|
|
2064
2561
|
const entity = (value)=>{
|
|
2065
|
-
if (typeof value !== 'string' || !
|
|
2066
|
-
if (context.knownEntityCodes && !context.knownEntityCodes.has(value)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2562
|
+
if (typeof value !== 'string' || !_config_entity_builder_constants_js__rspack_import_9/* .ENTITY_CODE_PATTERN.test */.vs.test(value)) return err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_CHOOSE_ENTITY */.qj.NODE_CHOOSE_ENTITY, at));
|
|
2563
|
+
if (context.knownEntityCodes && !context.knownEntityCodes.has(value)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_ENTITY_UNKNOWN */.qj.NODE_ENTITY_UNKNOWN, {
|
|
2067
2564
|
...at,
|
|
2068
2565
|
entity: value
|
|
2069
2566
|
}));
|
|
2070
2567
|
};
|
|
2071
2568
|
const KIND = {
|
|
2072
2569
|
variable: {
|
|
2073
|
-
list:
|
|
2074
|
-
item:
|
|
2570
|
+
list: _config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.VARIABLES */.bc.VARIABLES,
|
|
2571
|
+
item: _config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.VARIABLE */.bc.VARIABLE
|
|
2075
2572
|
},
|
|
2076
2573
|
field: {
|
|
2077
|
-
list:
|
|
2078
|
-
item:
|
|
2574
|
+
list: _config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.FIELDS */.bc.FIELDS,
|
|
2575
|
+
item: _config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.FIELD */.bc.FIELD
|
|
2079
2576
|
},
|
|
2080
2577
|
filter: {
|
|
2081
|
-
list:
|
|
2082
|
-
item:
|
|
2578
|
+
list: _config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.FILTERS */.bc.FILTERS,
|
|
2579
|
+
item: _config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.FILTER */.bc.FILTER
|
|
2083
2580
|
},
|
|
2084
2581
|
input: {
|
|
2085
|
-
list:
|
|
2086
|
-
item:
|
|
2582
|
+
list: _config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.INPUTS */.bc.INPUTS,
|
|
2583
|
+
item: _config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.INPUT */.bc.INPUT
|
|
2087
2584
|
},
|
|
2088
2585
|
header: {
|
|
2089
|
-
list:
|
|
2090
|
-
item:
|
|
2586
|
+
list: _config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.HEADERS */.bc.HEADERS,
|
|
2587
|
+
item: _config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.HEADER */.bc.HEADER
|
|
2091
2588
|
},
|
|
2092
2589
|
body: {
|
|
2093
|
-
list:
|
|
2094
|
-
item:
|
|
2590
|
+
list: _config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.BODY_VALUES */.bc.BODY_VALUES,
|
|
2591
|
+
item: _config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.BODY_VALUE */.bc.BODY_VALUE
|
|
2095
2592
|
},
|
|
2096
2593
|
payload: {
|
|
2097
|
-
list:
|
|
2098
|
-
item:
|
|
2594
|
+
list: _config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.PAYLOAD_VALUES */.bc.PAYLOAD_VALUES,
|
|
2595
|
+
item: _config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.PAYLOAD_VALUE */.bc.PAYLOAD_VALUE
|
|
2099
2596
|
},
|
|
2100
2597
|
response: {
|
|
2101
|
-
list:
|
|
2102
|
-
item:
|
|
2598
|
+
list: _config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.RESPONSE_VALUES */.bc.RESPONSE_VALUES,
|
|
2599
|
+
item: _config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.RESPONSE_VALUE */.bc.RESPONSE_VALUE
|
|
2600
|
+
},
|
|
2601
|
+
data: {
|
|
2602
|
+
list: _config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.DATA_VALUES */.bc.DATA_VALUES,
|
|
2603
|
+
item: _config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.DATA_VALUE */.bc.DATA_VALUE
|
|
2604
|
+
},
|
|
2605
|
+
template: {
|
|
2606
|
+
list: _config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.TEMPLATE_VALUES */.bc.TEMPLATE_VALUES,
|
|
2607
|
+
item: _config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.TEMPLATE_VALUE */.bc.TEMPLATE_VALUE
|
|
2103
2608
|
}
|
|
2104
2609
|
};
|
|
2610
|
+
const optionalExpr = (value, what)=>{
|
|
2611
|
+
if (value !== undefined) expr(value, what);
|
|
2612
|
+
};
|
|
2613
|
+
/** An AND / OR rule of permission codes: one that names none needs a permission, a malformed one is `invalid`. */ const permissionRule = (value, invalid)=>{
|
|
2614
|
+
const problem = (0,_flusys_nestjs_shared_utils__rspack_import_0.permissionLogicProblem)(value);
|
|
2615
|
+
if (problem === 'empty') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_PERMISSION_REQUIRED */.qj.NODE_PERMISSION_REQUIRED, at));
|
|
2616
|
+
else if (problem === 'too_many') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .RULE_ENGINE_MESSAGES.TOO_MANY_PERMISSION_CODES */.x3.TOO_MANY_PERMISSION_CODES, {
|
|
2617
|
+
max: _rule_engine_index_js__rspack_import_2/* .RULE_ENGINE_LIMITS.MAX_PERMISSION_CODES */.bw.MAX_PERMISSION_CODES
|
|
2618
|
+
}));
|
|
2619
|
+
else if (problem) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(invalid, at));
|
|
2620
|
+
};
|
|
2621
|
+
const serviceRunning = (service, unavailable)=>{
|
|
2622
|
+
if (context.messageServices && !context.messageServices[service]) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(unavailable, at));
|
|
2623
|
+
};
|
|
2105
2624
|
switch(node.type){
|
|
2106
2625
|
case 'trigger':
|
|
2107
2626
|
{
|
|
2108
|
-
if (c.path !== undefined && c.path !== '' && (typeof c.path !== 'string' || !_flow_types_js__rspack_import_6/* .FLOW_ENDPOINT_PATH_PATTERN.test */.YO.test(c.path))) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2627
|
+
if (c.path !== undefined && c.path !== '' && (typeof c.path !== 'string' || !_flow_types_js__rspack_import_6/* .FLOW_ENDPOINT_PATH_PATTERN.test */.YO.test(c.path))) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.TRIGGER_PATH_INVALID */.qj.TRIGGER_PATH_INVALID, at));
|
|
2628
|
+
if (c.authMode !== undefined && !_flow_types_js__rspack_import_6/* .FLOW_AUTH_MODES.includes */.fO.includes(c.authMode)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.TRIGGER_AUTH_INVALID */.qj.TRIGGER_AUTH_INVALID, at));
|
|
2629
|
+
if (c.permissions !== undefined) permissionRule(c.permissions, _config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.TRIGGER_AUTH_INVALID */.qj.TRIGGER_AUTH_INVALID);
|
|
2630
|
+
if (c.isTransactional !== undefined && typeof c.isTransactional !== 'boolean') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.TRIGGER_TRANSACTION_INVALID */.qj.TRIGGER_TRANSACTION_INVALID, at));
|
|
2631
|
+
if (c.timeoutMs !== undefined && !(Number.isInteger(c.timeoutMs) && c.timeoutMs >= _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MIN_TIMEOUT_MS */.Or.MIN_TIMEOUT_MS && c.timeoutMs <= _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_TIMEOUT_MS */.Or.MAX_TIMEOUT_MS)) {
|
|
2632
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.TRIGGER_TIMEOUT_RANGE */.qj.TRIGGER_TIMEOUT_RANGE, {
|
|
2633
|
+
...at,
|
|
2634
|
+
min: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MIN_TIMEOUT_MS */.Or.MIN_TIMEOUT_MS / 1000,
|
|
2635
|
+
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_TIMEOUT_MS */.Or.MAX_TIMEOUT_MS / 1000
|
|
2636
|
+
}));
|
|
2637
|
+
}
|
|
2638
|
+
if (c.rateLimitPerMinute !== undefined && !(Number.isInteger(c.rateLimitPerMinute) && c.rateLimitPerMinute >= 0 && c.rateLimitPerMinute <= _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_RATE_LIMIT_PER_MINUTE */.Or.MAX_RATE_LIMIT_PER_MINUTE)) {
|
|
2639
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.TRIGGER_RATE_LIMIT_RANGE */.qj.TRIGGER_RATE_LIMIT_RANGE, {
|
|
2640
|
+
...at,
|
|
2641
|
+
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_RATE_LIMIT_PER_MINUTE */.Or.MAX_RATE_LIMIT_PER_MINUTE
|
|
2642
|
+
}));
|
|
2643
|
+
}
|
|
2644
|
+
// Without a key an API-key URL could never be called; any other access keeps none.
|
|
2645
|
+
if (c.authMode === 'api_key' && c.apiKey === undefined) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.TRIGGER_API_KEY_REQUIRED */.qj.TRIGGER_API_KEY_REQUIRED, at));
|
|
2646
|
+
else if (c.apiKey !== undefined && !(0,_flow_api_key_js__rspack_import_7/* .looksLikeApiKey */.Jb)(c.apiKey) && !(0,_flow_types_js__rspack_import_6/* .isStoredApiKey */.xA)(c.apiKey)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.TRIGGER_API_KEY_INVALID */.qj.TRIGGER_API_KEY_INVALID, at));
|
|
2647
|
+
// Field errors are named after the URL (`<path>: <field>`) once a flow has several.
|
|
2109
2648
|
const path = (0,_flow_types_js__rspack_import_6/* .triggerPath */.um)(node);
|
|
2110
|
-
if (!
|
|
2111
|
-
if (c.bodyType !== undefined && !_flow_types_js__rspack_import_6/* .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, {
|
|
2649
|
+
if (c.bodyType !== undefined && !_flow_types_js__rspack_import_6/* .FLOW_BODY_TYPES.includes */.Y3.includes(c.bodyType)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.BODY_TYPE_UNKNOWN */.qj.BODY_TYPE_UNKNOWN, {
|
|
2112
2650
|
type: String(c.bodyType)
|
|
2113
2651
|
}));
|
|
2114
|
-
validateInputFields(Array.isArray(c.inputSchema) ? c.inputSchema : [], `${path}:
|
|
2652
|
+
validateInputFields(Array.isArray(c.inputSchema) ? c.inputSchema : [], path ? `${path}: ` : '', 1, err);
|
|
2115
2653
|
break;
|
|
2116
2654
|
}
|
|
2117
2655
|
case 'validate':
|
|
2118
2656
|
validateChecks(c, at, rule, err);
|
|
2119
|
-
if (c.mode !== undefined && c.mode !== 'all' && c.mode !== 'first') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2657
|
+
if (c.mode !== undefined && c.mode !== 'all' && c.mode !== 'first') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_MODE_INVALID */.qj.NODE_MODE_INVALID, at));
|
|
2120
2658
|
if (c.statusCode !== undefined && !(Number.isInteger(c.statusCode) && c.statusCode >= 400 && c.statusCode <= 499)) {
|
|
2121
|
-
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2659
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_STATUS_4XX */.qj.NODE_STATUS_4XX, at));
|
|
2122
2660
|
}
|
|
2123
2661
|
break;
|
|
2124
2662
|
case 'permission_check':
|
|
2125
2663
|
{
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2664
|
+
if (c.permissions === undefined) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_PERMISSION_REQUIRED */.qj.NODE_PERMISSION_REQUIRED, at));
|
|
2665
|
+
else permissionRule(c.permissions, _config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_PERMISSION_OPTION_INVALID */.qj.NODE_PERMISSION_OPTION_INVALID);
|
|
2666
|
+
if (c.onDenied !== undefined && c.onDenied !== 'reject' && c.onDenied !== 'branch') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_PERMISSION_OPTION_INVALID */.qj.NODE_PERMISSION_OPTION_INVALID, at));
|
|
2667
|
+
if (c.message !== undefined && typeof c.message !== 'string') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_PERMISSION_OPTION_INVALID */.qj.NODE_PERMISSION_OPTION_INVALID, at));
|
|
2668
|
+
if (c.statusCode !== undefined && !(Number.isInteger(c.statusCode) && c.statusCode >= 400 && c.statusCode <= 499)) {
|
|
2669
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_STATUS_4XX */.qj.NODE_STATUS_4XX, at));
|
|
2670
|
+
}
|
|
2671
|
+
break;
|
|
2672
|
+
}
|
|
2673
|
+
case 'company_branch_check':
|
|
2674
|
+
{
|
|
2675
|
+
if (c.subject !== undefined && !_flow_types_js__rspack_import_6/* .FLOW_ACCESS_SUBJECTS.includes */.iM.includes(c.subject)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_PERMISSION_OPTION_INVALID */.qj.NODE_PERMISSION_OPTION_INVALID, at));
|
|
2676
|
+
if (c.branchMatch !== undefined && !_flow_types_js__rspack_import_6/* .FLOW_BRANCH_MATCHES.includes */.Et.includes(c.branchMatch)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_PERMISSION_OPTION_INVALID */.qj.NODE_PERMISSION_OPTION_INVALID, at));
|
|
2677
|
+
if (c.subject === 'user') {
|
|
2678
|
+
if (c.userId === undefined) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_ACCESS_USER_REQUIRED */.qj.NODE_ACCESS_USER_REQUIRED, at));
|
|
2679
|
+
else expr(c.userId, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_USER */.bc.THE_USER));
|
|
2132
2680
|
}
|
|
2133
|
-
|
|
2134
|
-
if (c.
|
|
2135
|
-
|
|
2136
|
-
|
|
2681
|
+
// Another user has no current company.
|
|
2682
|
+
if (c.branchCompany !== undefined && (!_flow_types_js__rspack_import_6/* .FLOW_BRANCH_COMPANIES.includes */.sk.includes(c.branchCompany) || c.branchCompany === 'current' && c.subject === 'user')) {
|
|
2683
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_PERMISSION_OPTION_INVALID */.qj.NODE_PERMISSION_OPTION_INVALID, at));
|
|
2684
|
+
}
|
|
2685
|
+
if (c.companyIds !== undefined) expr(c.companyIds, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_VALUE */.bc.THE_VALUE));
|
|
2686
|
+
if (c.branchIds !== undefined) expr(c.branchIds, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_VALUE */.bc.THE_VALUE));
|
|
2687
|
+
if (c.onDenied !== undefined && c.onDenied !== 'reject' && c.onDenied !== 'branch') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_PERMISSION_OPTION_INVALID */.qj.NODE_PERMISSION_OPTION_INVALID, at));
|
|
2688
|
+
// Without an id to check there is nothing to allow or deny.
|
|
2689
|
+
if (c.onDenied === 'branch' && c.companyIds === undefined && c.branchIds === undefined) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_ACCESS_TARGET_REQUIRED */.qj.NODE_ACCESS_TARGET_REQUIRED, at));
|
|
2690
|
+
if (c.message !== undefined && typeof c.message !== 'string') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_PERMISSION_OPTION_INVALID */.qj.NODE_PERMISSION_OPTION_INVALID, at));
|
|
2137
2691
|
if (c.statusCode !== undefined && !(Number.isInteger(c.statusCode) && c.statusCode >= 400 && c.statusCode <= 499)) {
|
|
2138
|
-
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2692
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_STATUS_4XX */.qj.NODE_STATUS_4XX, at));
|
|
2139
2693
|
}
|
|
2140
2694
|
break;
|
|
2141
2695
|
}
|
|
2142
2696
|
case 'set':
|
|
2143
2697
|
exprMap(c.values, KIND.variable);
|
|
2144
|
-
if (!c.values || !Object.keys(c.values).length) warn.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2698
|
+
if (!c.values || !Object.keys(c.values).length) warn.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_SETS_NOTHING */.qj.NODE_SETS_NOTHING, at));
|
|
2145
2699
|
for (const key of Object.keys(c.values ?? {})){
|
|
2146
|
-
if (!_flow_types_js__rspack_import_6/* .FLOW_INPUT_NAME_PATTERN.test */.fZ.test(key)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2700
|
+
if (!_flow_types_js__rspack_import_6/* .FLOW_INPUT_NAME_PATTERN.test */.fZ.test(key)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_VARIABLE_INVALID */.qj.NODE_VARIABLE_INVALID, {
|
|
2147
2701
|
...at,
|
|
2148
2702
|
name: key
|
|
2149
2703
|
}));
|
|
2150
2704
|
}
|
|
2151
2705
|
break;
|
|
2152
2706
|
case 'condition':
|
|
2153
|
-
rule(c.rule, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2707
|
+
rule(c.rule, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_RULE */.bc.THE_RULE));
|
|
2154
2708
|
break;
|
|
2155
2709
|
case 'switch':
|
|
2156
2710
|
{
|
|
2157
|
-
expr(c.value, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2711
|
+
expr(c.value, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_VALUE */.bc.THE_VALUE));
|
|
2158
2712
|
const cases = Array.isArray(c.cases) ? c.cases : [];
|
|
2159
|
-
if (!cases.length) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2713
|
+
if (!cases.length) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_CASE_REQUIRED */.qj.NODE_CASE_REQUIRED, at));
|
|
2160
2714
|
const ids = new Set();
|
|
2161
2715
|
for (const item of cases){
|
|
2162
|
-
if (typeof item.id !== 'string' || !/^[A-Za-z][A-Za-z0-9_]{0,29}$/.test(item.id) || item.id === 'default') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2716
|
+
if (typeof item.id !== 'string' || !/^[A-Za-z][A-Za-z0-9_]{0,29}$/.test(item.id) || item.id === 'default') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_CASE_INVALID */.qj.NODE_CASE_INVALID, {
|
|
2163
2717
|
...at,
|
|
2164
2718
|
name: String(item.id)
|
|
2165
2719
|
}));
|
|
2166
|
-
else if (ids.has(item.id)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2720
|
+
else if (ids.has(item.id)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_CASE_DUPLICATE */.qj.NODE_CASE_DUPLICATE, {
|
|
2167
2721
|
...at,
|
|
2168
2722
|
name: item.id
|
|
2169
2723
|
}));
|
|
@@ -2172,10 +2726,10 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2172
2726
|
break;
|
|
2173
2727
|
}
|
|
2174
2728
|
case 'foreach':
|
|
2175
|
-
expr(c.items, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2176
|
-
if (c.collect !== undefined) expr(c.collect, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2729
|
+
expr(c.items, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_LIST */.bc.THE_LIST));
|
|
2730
|
+
if (c.collect !== undefined) expr(c.collect, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_COLLECTED_VALUE */.bc.THE_COLLECTED_VALUE));
|
|
2177
2731
|
if (c.maxItems !== undefined && !(Number.isInteger(c.maxItems) && c.maxItems >= 1 && c.maxItems <= _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_FOREACH_ITEMS */.Or.MAX_FOREACH_ITEMS)) {
|
|
2178
|
-
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2732
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_MAX_ITEMS_RANGE */.qj.NODE_MAX_ITEMS_RANGE, {
|
|
2179
2733
|
...at,
|
|
2180
2734
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_FOREACH_ITEMS */.Or.MAX_FOREACH_ITEMS
|
|
2181
2735
|
}));
|
|
@@ -2228,30 +2782,34 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2228
2782
|
break;
|
|
2229
2783
|
case 'entity_get':
|
|
2230
2784
|
entity(c.entityCode);
|
|
2231
|
-
expr(c.id, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2785
|
+
expr(c.id, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_RECORD_ID */.bc.THE_RECORD_ID));
|
|
2232
2786
|
break;
|
|
2233
2787
|
case 'entity_query':
|
|
2234
2788
|
entity(c.entityCode);
|
|
2235
2789
|
filterMap(c.filter, KIND.filter);
|
|
2236
|
-
if (c.search !== undefined) expr(c.search, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2790
|
+
if (c.search !== undefined) expr(c.search, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_SEARCH_TEXT */.bc.THE_SEARCH_TEXT));
|
|
2791
|
+
if (c.sort !== undefined) {
|
|
2792
|
+
const sort = c.sort;
|
|
2793
|
+
if (typeof sort?.field !== 'string' || !COLUMN_CODE.test(sort.field) || sort.direction !== undefined && sort.direction !== 'ASC' && sort.direction !== 'DESC') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_SORT_INVALID */.qj.NODE_SORT_INVALID, at));
|
|
2794
|
+
}
|
|
2237
2795
|
if (c.limit !== undefined && !(Number.isInteger(c.limit) && c.limit >= 1 && c.limit <= _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_QUERY_LIMIT */.Or.MAX_QUERY_LIMIT)) {
|
|
2238
|
-
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2796
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_LIMIT_RANGE */.qj.NODE_LIMIT_RANGE, {
|
|
2239
2797
|
...at,
|
|
2240
2798
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_QUERY_LIMIT */.Or.MAX_QUERY_LIMIT
|
|
2241
2799
|
}));
|
|
2242
2800
|
}
|
|
2243
2801
|
break;
|
|
2244
2802
|
case 'call_flow':
|
|
2245
|
-
if (typeof c.flowSlug !== 'string' || !_flow_types_js__rspack_import_6/* .FLOW_SLUG_PATTERN.test */.YD.test(c.flowSlug)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2246
|
-
else if (c.flowSlug === flow.slug) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2247
|
-
else if (context.knownFlows && !context.knownFlows.has(c.flowSlug)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2803
|
+
if (typeof c.flowSlug !== 'string' || !_flow_types_js__rspack_import_6/* .FLOW_SLUG_PATTERN.test */.YD.test(c.flowSlug)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_CHOOSE_FLOW */.qj.NODE_CHOOSE_FLOW, at));
|
|
2804
|
+
else if (c.flowSlug === flow.slug) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_CALLS_ITSELF */.qj.NODE_CALLS_ITSELF, at));
|
|
2805
|
+
else if (context.knownFlows && !context.knownFlows.has(c.flowSlug)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_FLOW_UNKNOWN */.qj.NODE_FLOW_UNKNOWN, {
|
|
2248
2806
|
...at,
|
|
2249
2807
|
flow: c.flowSlug
|
|
2250
2808
|
}));
|
|
2251
|
-
else if (context.knownFlows) checkCalledFlow(
|
|
2252
|
-
if (c.endpoint !== undefined && c.endpoint !== '' && (typeof c.endpoint !== 'string' || !_flow_types_js__rspack_import_6/* .FLOW_ENDPOINT_PATH_PATTERN.test */.YO.test(c.endpoint))) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2809
|
+
else if (context.knownFlows) checkCalledFlow(node, flow, context.knownFlows, err, warn);
|
|
2810
|
+
if (c.endpoint !== undefined && c.endpoint !== '' && (typeof c.endpoint !== 'string' || !_flow_types_js__rspack_import_6/* .FLOW_ENDPOINT_PATH_PATTERN.test */.YO.test(c.endpoint))) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.TRIGGER_PATH_INVALID */.qj.TRIGGER_PATH_INVALID, at));
|
|
2253
2811
|
exprMap(c.input, KIND.input);
|
|
2254
|
-
if (c.inputList !== undefined) expr(c.inputList, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2812
|
+
if (c.inputList !== undefined) expr(c.inputList, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_INPUT_LIST */.bc.THE_INPUT_LIST));
|
|
2255
2813
|
break;
|
|
2256
2814
|
case 'http_request':
|
|
2257
2815
|
{
|
|
@@ -2261,12 +2819,13 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2261
2819
|
'PUT',
|
|
2262
2820
|
'PATCH',
|
|
2263
2821
|
'DELETE'
|
|
2264
|
-
].includes(String(c.method))) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2265
|
-
expr(c.url, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2822
|
+
].includes(String(c.method))) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_CHOOSE_METHOD */.qj.NODE_CHOOSE_METHOD, at));
|
|
2823
|
+
expr(c.url, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_URL */.bc.THE_URL));
|
|
2266
2824
|
exprMap(c.headers, KIND.header);
|
|
2267
2825
|
exprMap(c.body, KIND.body);
|
|
2826
|
+
if (c.forwardAuth === true) warn.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_FORWARDS_TOKEN */.qj.NODE_FORWARDS_TOKEN, at));
|
|
2268
2827
|
if (c.timeoutMs !== undefined && !(Number.isInteger(c.timeoutMs) && c.timeoutMs >= 100 && c.timeoutMs <= _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_HTTP_TIMEOUT_MS */.Or.MAX_HTTP_TIMEOUT_MS)) {
|
|
2269
|
-
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2828
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_TIMEOUT_RANGE */.qj.NODE_TIMEOUT_RANGE, {
|
|
2270
2829
|
...at,
|
|
2271
2830
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_HTTP_TIMEOUT_MS */.Or.MAX_HTTP_TIMEOUT_MS
|
|
2272
2831
|
}));
|
|
@@ -2274,28 +2833,71 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2274
2833
|
break;
|
|
2275
2834
|
}
|
|
2276
2835
|
case 'publish_event':
|
|
2277
|
-
if (typeof c.eventName !== 'string' || !/^[a-z][a-z0-9_.-]{1,59}$/.test(c.eventName)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2836
|
+
if (typeof c.eventName !== 'string' || !/^[a-z][a-z0-9_.-]{1,59}$/.test(c.eventName)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_EVENT_NAME_INVALID */.qj.NODE_EVENT_NAME_INVALID, at));
|
|
2278
2837
|
exprMap(c.payload, KIND.payload);
|
|
2279
2838
|
break;
|
|
2839
|
+
case 'send_notification':
|
|
2840
|
+
{
|
|
2841
|
+
serviceRunning('notification', _config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_NOTIFICATION_UNAVAILABLE */.qj.NODE_NOTIFICATION_UNAVAILABLE);
|
|
2842
|
+
const target = c.target ?? 'one';
|
|
2843
|
+
if (!_flow_types_js__rspack_import_6/* .FLOW_NOTIFICATION_TARGETS.includes */.as.includes(target)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_MESSAGE_TARGET_INVALID */.qj.NODE_MESSAGE_TARGET_INVALID, at));
|
|
2844
|
+
if (target === 'many') expr(c.items, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_LIST */.bc.THE_LIST));
|
|
2845
|
+
if (target === 'company') {
|
|
2846
|
+
if (context.companyMembers === false) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_NOTIFICATION_COMPANY_UNAVAILABLE */.qj.NODE_NOTIFICATION_COMPANY_UNAVAILABLE, at));
|
|
2847
|
+
expr(c.companyIds, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_COMPANIES */.bc.THE_COMPANIES));
|
|
2848
|
+
optionalExpr(c.branchIds, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_BRANCHES */.bc.THE_BRANCHES));
|
|
2849
|
+
} else {
|
|
2850
|
+
expr(c.userIds, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_RECIPIENTS */.bc.THE_RECIPIENTS));
|
|
2851
|
+
optionalExpr(c.companyId, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_COMPANY */.bc.THE_COMPANY));
|
|
2852
|
+
}
|
|
2853
|
+
expr(c.title, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_TITLE */.bc.THE_TITLE));
|
|
2854
|
+
optionalExpr(c.message, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_MESSAGE */.bc.THE_MESSAGE));
|
|
2855
|
+
exprMap(c.data, KIND.data);
|
|
2856
|
+
if (c.type !== undefined && !_flow_types_js__rspack_import_6/* .FLOW_NOTIFICATION_TYPES.includes */.LG.includes(c.type)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_NOTIFICATION_OPTION_INVALID */.qj.NODE_NOTIFICATION_OPTION_INVALID, at));
|
|
2857
|
+
if (c.realtime !== undefined && typeof c.realtime !== 'boolean') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_NOTIFICATION_OPTION_INVALID */.qj.NODE_NOTIFICATION_OPTION_INVALID, at));
|
|
2858
|
+
break;
|
|
2859
|
+
}
|
|
2860
|
+
case 'send_email':
|
|
2861
|
+
{
|
|
2862
|
+
serviceRunning('email', _config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_EMAIL_UNAVAILABLE */.qj.NODE_EMAIL_UNAVAILABLE);
|
|
2863
|
+
if (!_flow_types_js__rspack_import_6/* .FLOW_EMAIL_TARGETS.includes */.B9.includes(c.target ?? 'one')) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_MESSAGE_TARGET_INVALID */.qj.NODE_MESSAGE_TARGET_INVALID, at));
|
|
2864
|
+
if (c.target === 'many') expr(c.items, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_LIST */.bc.THE_LIST));
|
|
2865
|
+
expr(c.to, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_RECIPIENTS */.bc.THE_RECIPIENTS));
|
|
2866
|
+
optionalExpr(c.cc, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_CC */.bc.THE_CC));
|
|
2867
|
+
optionalExpr(c.bcc, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_BCC */.bc.THE_BCC));
|
|
2868
|
+
optionalExpr(c.replyTo, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_REPLY_TO */.bc.THE_REPLY_TO));
|
|
2869
|
+
if (c.mode !== undefined && !_flow_types_js__rspack_import_6/* .FLOW_EMAIL_MODES.includes */.v1.includes(c.mode)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_EMAIL_OPTION_INVALID */.qj.NODE_EMAIL_OPTION_INVALID, at));
|
|
2870
|
+
if (c.format !== undefined && !_flow_types_js__rspack_import_6/* .FLOW_EMAIL_FORMATS.includes */.FU.includes(c.format)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_EMAIL_OPTION_INVALID */.qj.NODE_EMAIL_OPTION_INVALID, at));
|
|
2871
|
+
if (c.emailConfigId !== undefined && c.emailConfigId !== '' && (typeof c.emailConfigId !== 'string' || !_flow_types_js__rspack_import_6/* .FLOW_ID_PATTERN.test */.E2.test(c.emailConfigId))) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_EMAIL_OPTION_INVALID */.qj.NODE_EMAIL_OPTION_INVALID, at));
|
|
2872
|
+
if (c.mode === 'template') {
|
|
2873
|
+
const slug = typeof c.templateSlug === 'string' ? c.templateSlug.trim() : '';
|
|
2874
|
+
if (!slug || slug.length > _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_EMAIL_TEMPLATE_SLUG_LENGTH */.Or.MAX_EMAIL_TEMPLATE_SLUG_LENGTH) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_EMAIL_TEMPLATE_REQUIRED */.qj.NODE_EMAIL_TEMPLATE_REQUIRED, at));
|
|
2875
|
+
exprMap(c.variables, KIND.template);
|
|
2876
|
+
} else {
|
|
2877
|
+
expr(c.subject, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_SUBJECT */.bc.THE_SUBJECT));
|
|
2878
|
+
expr(c.body, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_BODY */.bc.THE_BODY));
|
|
2879
|
+
}
|
|
2880
|
+
break;
|
|
2881
|
+
}
|
|
2280
2882
|
case 'respond':
|
|
2281
2883
|
{
|
|
2282
2884
|
const status = c.statusCode;
|
|
2283
|
-
if (!(Number.isInteger(status) && status >= 200 && status <= 599)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2885
|
+
if (!(Number.isInteger(status) && status >= 200 && status <= 599)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_STATUS_2XX_5XX */.qj.NODE_STATUS_2XX_5XX, at));
|
|
2284
2886
|
exprMap(c.body, KIND.response);
|
|
2285
|
-
if (c.bodyExpression !== undefined) expr(c.bodyExpression, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2887
|
+
if (c.bodyExpression !== undefined) expr(c.bodyExpression, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_RESPONSE */.bc.THE_RESPONSE));
|
|
2286
2888
|
break;
|
|
2287
2889
|
}
|
|
2288
2890
|
case 'commit':
|
|
2289
|
-
if (node.onError === 'continue') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2891
|
+
if (node.onError === 'continue') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_COMMIT_CONTINUE */.qj.NODE_COMMIT_CONTINUE, at));
|
|
2290
2892
|
break;
|
|
2291
2893
|
case 'code':
|
|
2292
|
-
if (typeof c.code !== 'string' || !c.code.trim()) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2293
|
-
else if (c.code.length > _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_CODE_LENGTH */.Or.MAX_CODE_LENGTH) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2894
|
+
if (typeof c.code !== 'string' || !c.code.trim()) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_CODE_REQUIRED */.qj.NODE_CODE_REQUIRED, at));
|
|
2895
|
+
else if (c.code.length > _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_CODE_LENGTH */.Or.MAX_CODE_LENGTH) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_CODE_TOO_LONG */.qj.NODE_CODE_TOO_LONG, {
|
|
2294
2896
|
...at,
|
|
2295
2897
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_CODE_LENGTH */.Or.MAX_CODE_LENGTH
|
|
2296
2898
|
}));
|
|
2297
2899
|
if (c.timeoutMs !== undefined && !(Number.isInteger(c.timeoutMs) && c.timeoutMs >= _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MIN_CODE_TIMEOUT_MS */.Or.MIN_CODE_TIMEOUT_MS && c.timeoutMs <= _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_CODE_TIMEOUT_MS */.Or.MAX_CODE_TIMEOUT_MS)) {
|
|
2298
|
-
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2900
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_CODE_TIMEOUT_RANGE */.qj.NODE_CODE_TIMEOUT_RANGE, {
|
|
2299
2901
|
...at,
|
|
2300
2902
|
min: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MIN_CODE_TIMEOUT_MS */.Or.MIN_CODE_TIMEOUT_MS,
|
|
2301
2903
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_CODE_TIMEOUT_MS */.Or.MAX_CODE_TIMEOUT_MS
|
|
@@ -2306,19 +2908,19 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2306
2908
|
}
|
|
2307
2909
|
/** `target` and what it needs: one - an id; many - a list (the id is optional, the item's own id by default); filter - a filter and a limit. */ function writeTargetConfig(c, targets, notFound, { at, expr, filterMap, err }) {
|
|
2308
2910
|
const target = c.target ?? 'one';
|
|
2309
|
-
if (typeof target !== 'string' || !targets.includes(target)) return err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2310
|
-
if (c.onNotFound !== undefined && !notFound.includes(c.onNotFound)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2911
|
+
if (typeof target !== 'string' || !targets.includes(target)) return err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_WRITE_TARGET_INVALID */.qj.NODE_WRITE_TARGET_INVALID, at));
|
|
2912
|
+
if (c.onNotFound !== undefined && !notFound.includes(c.onNotFound)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_NOT_FOUND_INVALID */.qj.NODE_NOT_FOUND_INVALID, at));
|
|
2311
2913
|
const needsId = notFound.length > 0;
|
|
2312
|
-
if (target === 'one' && needsId) expr(c.id, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2914
|
+
if (target === 'one' && needsId) expr(c.id, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_RECORD_ID */.bc.THE_RECORD_ID));
|
|
2313
2915
|
if (target === 'many') {
|
|
2314
|
-
expr(c.items, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2315
|
-
if (needsId && c.id !== undefined) expr(c.id, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2916
|
+
expr(c.items, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_LIST */.bc.THE_LIST));
|
|
2917
|
+
if (needsId && c.id !== undefined) expr(c.id, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_RECORD_ID */.bc.THE_RECORD_ID));
|
|
2316
2918
|
}
|
|
2317
2919
|
if (target === 'filter') {
|
|
2318
2920
|
filterMap(c.filter);
|
|
2319
|
-
if (!c.filter || typeof c.filter !== 'object' || !Object.keys(c.filter).length) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2921
|
+
if (!c.filter || typeof c.filter !== 'object' || !Object.keys(c.filter).length) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_FILTER_REQUIRED */.qj.NODE_FILTER_REQUIRED, at));
|
|
2320
2922
|
if (c.limit !== undefined && !(Number.isInteger(c.limit) && c.limit >= 1 && c.limit <= _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_WRITE_ITEMS */.Or.MAX_WRITE_ITEMS)) {
|
|
2321
|
-
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2923
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_LIMIT_RANGE */.qj.NODE_LIMIT_RANGE, {
|
|
2322
2924
|
...at,
|
|
2323
2925
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_WRITE_ITEMS */.Or.MAX_WRITE_ITEMS
|
|
2324
2926
|
}));
|
|
@@ -2327,45 +2929,45 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2327
2929
|
}
|
|
2328
2930
|
function childInserts(value, { at, entity, expr, err }) {
|
|
2329
2931
|
if (value === undefined) return;
|
|
2330
|
-
if (!Array.isArray(value)) return err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2331
|
-
if (value.length > _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_CHILD_INSERTS */.Or.MAX_CHILD_INSERTS) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2932
|
+
if (!Array.isArray(value)) return err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_CHILDREN_INVALID */.qj.NODE_CHILDREN_INVALID, at));
|
|
2933
|
+
if (value.length > _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_CHILD_INSERTS */.Or.MAX_CHILD_INSERTS) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_CHILDREN_TOO_MANY */.qj.NODE_CHILDREN_TOO_MANY, {
|
|
2332
2934
|
...at,
|
|
2333
2935
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_CHILD_INSERTS */.Or.MAX_CHILD_INSERTS
|
|
2334
2936
|
}));
|
|
2335
2937
|
const names = new Set();
|
|
2336
2938
|
for (const child of value){
|
|
2337
2939
|
if (!child || typeof child !== 'object') {
|
|
2338
|
-
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2940
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_CHILDREN_INVALID */.qj.NODE_CHILDREN_INVALID, at));
|
|
2339
2941
|
continue;
|
|
2340
2942
|
}
|
|
2341
2943
|
const name = String(child.as ?? '');
|
|
2342
|
-
if (!_flow_types_js__rspack_import_6/* .FLOW_INPUT_NAME_PATTERN.test */.fZ.test(name)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2944
|
+
if (!_flow_types_js__rspack_import_6/* .FLOW_INPUT_NAME_PATTERN.test */.fZ.test(name)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_CHILD_NAME_INVALID */.qj.NODE_CHILD_NAME_INVALID, {
|
|
2343
2945
|
...at,
|
|
2344
2946
|
name
|
|
2345
2947
|
}));
|
|
2346
|
-
else if (names.has(name)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2948
|
+
else if (names.has(name)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_CHILD_NAME_DUPLICATE */.qj.NODE_CHILD_NAME_DUPLICATE, {
|
|
2347
2949
|
...at,
|
|
2348
2950
|
name
|
|
2349
2951
|
}));
|
|
2350
2952
|
names.add(name);
|
|
2351
2953
|
entity(child.entityCode);
|
|
2352
|
-
if (typeof child.parentField !== 'string' || !COLUMN_CODE.test(child.parentField)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2954
|
+
if (typeof child.parentField !== 'string' || !COLUMN_CODE.test(child.parentField)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_CHILD_PARENT_FIELD_REQUIRED */.qj.NODE_CHILD_PARENT_FIELD_REQUIRED, {
|
|
2353
2955
|
...at,
|
|
2354
2956
|
name
|
|
2355
2957
|
}));
|
|
2356
|
-
expr(child.items, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2958
|
+
expr(child.items, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.CHILD_LIST */.bc.CHILD_LIST, {
|
|
2357
2959
|
name
|
|
2358
2960
|
}));
|
|
2359
2961
|
const fields = child.fields;
|
|
2360
2962
|
if (fields === undefined) continue;
|
|
2361
2963
|
if (!fields || typeof fields !== 'object' || Array.isArray(fields)) {
|
|
2362
|
-
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2964
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_PAIRS_INVALID */.qj.NODE_PAIRS_INVALID, {
|
|
2363
2965
|
...at,
|
|
2364
|
-
what: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2966
|
+
what: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.FIELDS */.bc.FIELDS)
|
|
2365
2967
|
}));
|
|
2366
2968
|
continue;
|
|
2367
2969
|
}
|
|
2368
|
-
for (const [key, item] of Object.entries(fields))expr(item, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2970
|
+
for (const [key, item] of Object.entries(fields))expr(item, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.CHILD_FIELD */.bc.CHILD_FIELD, {
|
|
2369
2971
|
name: `${name}.${key}`
|
|
2370
2972
|
}));
|
|
2371
2973
|
}
|
|
@@ -2373,7 +2975,8 @@ function childInserts(value, { at, entity, expr, err }) {
|
|
|
2373
2975
|
/**
|
|
2374
2976
|
* How many loop levels each part of a node's config runs inside, beyond the loops around the node:
|
|
2375
2977
|
* a foreach's `collect` runs in its own loop; a many / filter write's per-record expressions in one
|
|
2376
|
-
* of the node's own; child records one deeper than their parent record
|
|
2978
|
+
* of the node's own; child records one deeper than their parent record; a many message step's values
|
|
2979
|
+
* (all but its list) one per item.
|
|
2377
2980
|
*/ function configScopes(node) {
|
|
2378
2981
|
const config = node.config ?? {};
|
|
2379
2982
|
if (node.type === 'foreach') {
|
|
@@ -2391,14 +2994,29 @@ function childInserts(value, { at, entity, expr, err }) {
|
|
|
2391
2994
|
}
|
|
2392
2995
|
];
|
|
2393
2996
|
}
|
|
2394
|
-
if (
|
|
2395
|
-
{
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2997
|
+
if ((0,_flow_types_js__rspack_import_6/* .isMessageNode */.SE)(node.type) && config['target'] === 'many') {
|
|
2998
|
+
const { items, ...perItem } = config;
|
|
2999
|
+
return [
|
|
3000
|
+
{
|
|
3001
|
+
value: items,
|
|
3002
|
+
extra: 0,
|
|
3003
|
+
ownLoop: false
|
|
3004
|
+
},
|
|
3005
|
+
{
|
|
3006
|
+
value: perItem,
|
|
3007
|
+
extra: 1,
|
|
3008
|
+
ownLoop: false
|
|
3009
|
+
}
|
|
3010
|
+
];
|
|
3011
|
+
}
|
|
3012
|
+
if (!WRITE_NODE_TYPES.has(node.type)) return [
|
|
3013
|
+
{
|
|
3014
|
+
value: config,
|
|
3015
|
+
extra: 0,
|
|
3016
|
+
ownLoop: false
|
|
3017
|
+
}
|
|
3018
|
+
];
|
|
3019
|
+
const { fields, id, children, ...rest } = config;
|
|
2402
3020
|
const perRecord = (rest.target ?? 'one') === 'one' ? 0 : 1;
|
|
2403
3021
|
const scopes = [
|
|
2404
3022
|
{
|
|
@@ -2429,32 +3047,32 @@ function childInserts(value, { at, entity, expr, err }) {
|
|
|
2429
3047
|
return scopes;
|
|
2430
3048
|
}
|
|
2431
3049
|
function validateChecks(c, at, rule, err) {
|
|
2432
|
-
if (!Array.isArray(c.checks) || !c.checks.length) return err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2433
|
-
if (c.checks.length > _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_VALIDATE_CHECKS */.Or.MAX_VALIDATE_CHECKS) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
3050
|
+
if (!Array.isArray(c.checks) || !c.checks.length) return err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_CHECK_REQUIRED */.qj.NODE_CHECK_REQUIRED, at));
|
|
3051
|
+
if (c.checks.length > _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_VALIDATE_CHECKS */.Or.MAX_VALIDATE_CHECKS) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_TOO_MANY_CHECKS */.qj.NODE_TOO_MANY_CHECKS, {
|
|
2434
3052
|
...at,
|
|
2435
3053
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_VALIDATE_CHECKS */.Or.MAX_VALIDATE_CHECKS
|
|
2436
3054
|
}));
|
|
2437
3055
|
const ids = new Set();
|
|
2438
3056
|
for (const check of c.checks){
|
|
2439
3057
|
const id = check?.id;
|
|
2440
|
-
if (typeof id !== 'string' || !CHECK_ID.test(id)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
3058
|
+
if (typeof id !== 'string' || !CHECK_ID.test(id)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_CHECK_ID_INVALID */.qj.NODE_CHECK_ID_INVALID, {
|
|
2441
3059
|
...at,
|
|
2442
3060
|
name: String(id)
|
|
2443
3061
|
}));
|
|
2444
|
-
else if (ids.has(id)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
3062
|
+
else if (ids.has(id)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_CHECK_ID_DUPLICATE */.qj.NODE_CHECK_ID_DUPLICATE, {
|
|
2445
3063
|
...at,
|
|
2446
3064
|
name: id
|
|
2447
3065
|
}));
|
|
2448
3066
|
else ids.add(id);
|
|
2449
3067
|
const name = String(id);
|
|
2450
|
-
rule(check?.rule, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
3068
|
+
rule(check?.rule, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_SUBJECT_MESSAGES.THE_CHECK */.bc.THE_CHECK, {
|
|
2451
3069
|
name
|
|
2452
3070
|
}));
|
|
2453
|
-
if (typeof check?.message !== 'string' || !check.message.trim()) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
3071
|
+
if (typeof check?.message !== 'string' || !check.message.trim()) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_CHECK_MESSAGE_REQUIRED */.qj.NODE_CHECK_MESSAGE_REQUIRED, {
|
|
2454
3072
|
...at,
|
|
2455
3073
|
name
|
|
2456
3074
|
}));
|
|
2457
|
-
if (check?.field !== undefined && (typeof check.field !== 'string' || !check.field.trim() || check.field.length > 100)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
3075
|
+
if (check?.field !== undefined && (typeof check.field !== 'string' || !check.field.trim() || check.field.length > 100)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.NODE_CHECK_FIELD_INVALID */.qj.NODE_CHECK_FIELD_INVALID, {
|
|
2458
3076
|
...at,
|
|
2459
3077
|
name
|
|
2460
3078
|
}));
|
|
@@ -2475,21 +3093,21 @@ function validateChecks(c, at, rule, err) {
|
|
|
2475
3093
|
for (const ref of refs){
|
|
2476
3094
|
const [scope, second] = ref.split('.');
|
|
2477
3095
|
if (!REF_SCOPES.has(scope)) {
|
|
2478
|
-
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
3096
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.REF_BAD_SCOPE */.qj.REF_BAD_SCOPE, {
|
|
2479
3097
|
node: (0,_flow_types_js__rspack_import_6/* .nodeLabel */.dA)(node),
|
|
2480
3098
|
ref
|
|
2481
3099
|
}));
|
|
2482
3100
|
} else if (scope === 'context' && second && !byId.has(second)) {
|
|
2483
|
-
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
3101
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.REF_NODE_MISSING */.qj.REF_NODE_MISSING, {
|
|
2484
3102
|
node: (0,_flow_types_js__rspack_import_6/* .nodeLabel */.dA)(node),
|
|
2485
3103
|
target: second
|
|
2486
3104
|
}));
|
|
2487
3105
|
} else if (scope === 'context' && second === node.id) {
|
|
2488
|
-
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
3106
|
+
err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.REF_SELF */.qj.REF_SELF, {
|
|
2489
3107
|
node: (0,_flow_types_js__rspack_import_6/* .nodeLabel */.dA)(node)
|
|
2490
3108
|
}));
|
|
2491
3109
|
} else if (scope === 'input' && second && namesKnown && !declaredInputs.has(second)) {
|
|
2492
|
-
warnings.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
3110
|
+
warnings.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.REF_INPUT_UNDECLARED */.qj.REF_INPUT_UNDECLARED, {
|
|
2493
3111
|
node: (0,_flow_types_js__rspack_import_6/* .nodeLabel */.dA)(node),
|
|
2494
3112
|
input: second
|
|
2495
3113
|
}));
|
|
@@ -2505,15 +3123,28 @@ function refsOf(value, refs = [], depth = 0) {
|
|
|
2505
3123
|
return refs;
|
|
2506
3124
|
}
|
|
2507
3125
|
/**
|
|
2508
|
-
* Writes that do not share a transaction, and Save progress steps that would not commit:
|
|
2509
|
-
* without the transaction setting, inside a loop (once per item), or in a flow
|
|
2510
|
-
* (inside its caller's transaction it is skipped).
|
|
2511
|
-
*/ function checkTransactionUse(flow,
|
|
2512
|
-
const
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
3126
|
+
* Writes that do not share a transaction, and Save progress steps that would not commit: reached
|
|
3127
|
+
* from a Request step without the transaction setting, inside a loop (once per item), or in a flow
|
|
3128
|
+
* other flows call (inside its caller's transaction it is skipped).
|
|
3129
|
+
*/ function checkTransactionUse(flow, runs, outgoing, context, warnings) {
|
|
3130
|
+
for (const { endpoint, label, steps } of runs){
|
|
3131
|
+
if (endpoint.isTransactional) continue;
|
|
3132
|
+
const writes = steps.filter((n)=>WRITE_NODE_TYPES.has(n.type)).length;
|
|
3133
|
+
if (writes >= 2) warnings.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.WRITES_NOT_TRANSACTIONAL */.qj.WRITES_NOT_TRANSACTIONAL, {
|
|
3134
|
+
count: writes,
|
|
3135
|
+
node: label
|
|
3136
|
+
}));
|
|
3137
|
+
for (const commit of steps)if (commit.type === 'commit') warnings.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.COMMIT_NOT_TRANSACTIONAL */.qj.COMMIT_NOT_TRANSACTIONAL, {
|
|
3138
|
+
node: (0,_flow_types_js__rspack_import_6/* .nodeLabel */.dA)(commit),
|
|
3139
|
+
endpoint: label
|
|
3140
|
+
}));
|
|
3141
|
+
}
|
|
3142
|
+
const live = [
|
|
3143
|
+
...new Map(runs.flatMap((run)=>run.steps).map((n)=>[
|
|
3144
|
+
n.id,
|
|
3145
|
+
n
|
|
3146
|
+
])).values()
|
|
3147
|
+
];
|
|
2517
3148
|
const commits = live.filter((n)=>n.type === 'commit');
|
|
2518
3149
|
if (!commits.length) return;
|
|
2519
3150
|
const loops = live.filter((n)=>n.type === 'foreach').map((n)=>({
|
|
@@ -2527,13 +3158,12 @@ function refsOf(value, refs = [], depth = 0) {
|
|
|
2527
3158
|
const at = {
|
|
2528
3159
|
node: (0,_flow_types_js__rspack_import_6/* .nodeLabel */.dA)(commit)
|
|
2529
3160
|
};
|
|
2530
|
-
if (!flow.isTransactional) warnings.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_7/* .FLOW_VALIDATION_MESSAGES.COMMIT_NOT_TRANSACTIONAL */.qj.COMMIT_NOT_TRANSACTIONAL, at));
|
|
2531
3161
|
const loop = loops.find((l)=>l.body.has(commit.id));
|
|
2532
|
-
if (loop) warnings.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
3162
|
+
if (loop) warnings.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.COMMIT_IN_LOOP */.qj.COMMIT_IN_LOOP, {
|
|
2533
3163
|
...at,
|
|
2534
3164
|
loop: (0,_flow_types_js__rspack_import_6/* .nodeLabel */.dA)(loop.node)
|
|
2535
3165
|
}));
|
|
2536
|
-
if (called) warnings.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
3166
|
+
if (called) warnings.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.COMMIT_IN_CALLED_FLOW */.qj.COMMIT_IN_CALLED_FLOW, at));
|
|
2537
3167
|
}
|
|
2538
3168
|
}
|
|
2539
3169
|
/** Every node a loop's `each` branch runs, nested loops included. */ function loopBody(loopId, outgoing) {
|
|
@@ -2636,14 +3266,14 @@ function refsOf(value, refs = [], depth = 0) {
|
|
|
2636
3266
|
const [scope, target, field] = segs;
|
|
2637
3267
|
if (scope === 'loop') {
|
|
2638
3268
|
const parents = segs.slice(1).findIndex((s)=>s !== 'parent');
|
|
2639
|
-
if (!depth) warn(
|
|
2640
|
-
else if ((parents < 0 ? segs.length - 1 : parents) >= depth) warn(
|
|
3269
|
+
if (!depth) warn(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.REF_LOOP_OUTSIDE */.qj.REF_LOOP_OUTSIDE, {});
|
|
3270
|
+
else if ((parents < 0 ? segs.length - 1 : parents) >= depth) warn(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.REF_LOOP_PARENT_MISSING */.qj.REF_LOOP_PARENT_MISSING, {});
|
|
2641
3271
|
}
|
|
2642
3272
|
if (scope !== 'context' || !target || target === node.id || !byId.has(target)) continue;
|
|
2643
|
-
if (!available.has(target)) warn(
|
|
3273
|
+
if (!available.has(target)) warn(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.REF_NODE_NOT_YET */.qj.REF_NODE_NOT_YET, {
|
|
2644
3274
|
target: nameOf(target)
|
|
2645
3275
|
});
|
|
2646
|
-
else if (field === 'results' && around.has(target)) warn(
|
|
3276
|
+
else if (field === 'results' && around.has(target)) warn(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.REF_LOOP_RESULTS_EARLY */.qj.REF_LOOP_RESULTS_EARLY, {
|
|
2647
3277
|
loop: nameOf(target)
|
|
2648
3278
|
});
|
|
2649
3279
|
}
|
|
@@ -2698,14 +3328,15 @@ function reach(start, outgoing) {
|
|
|
2698
3328
|
nesting.set(id, max);
|
|
2699
3329
|
return max;
|
|
2700
3330
|
};
|
|
2701
|
-
if (nodes.some((n)=>n.type === 'trigger' && nestingFrom(n.id) > _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_LOOP_DEPTH */.Or.MAX_LOOP_DEPTH)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
3331
|
+
if (nodes.some((n)=>n.type === 'trigger' && nestingFrom(n.id) > _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_LOOP_DEPTH */.Or.MAX_LOOP_DEPTH)) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_8/* .FLOW_VALIDATION_MESSAGES.LOOP_TOO_DEEP */.qj.LOOP_TOO_DEEP, {
|
|
2702
3332
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_LOOP_DEPTH */.Or.MAX_LOOP_DEPTH
|
|
2703
3333
|
}));
|
|
2704
3334
|
}
|
|
2705
3335
|
|
|
2706
3336
|
__webpack_require__.d(__webpack_exports__, {
|
|
2707
|
-
|
|
2708
|
-
|
|
3337
|
+
nC: () => (validateFlow),
|
|
3338
|
+
r7: () => (callProblems),
|
|
3339
|
+
u9: () => (usesPermissionFunction)
|
|
2709
3340
|
});
|
|
2710
3341
|
|
|
2711
3342
|
|
|
@@ -2908,6 +3539,19 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
2908
3539
|
});
|
|
2909
3540
|
|
|
2910
3541
|
|
|
3542
|
+
},
|
|
3543
|
+
8220(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
3544
|
+
const permissionAction = (code)=>({
|
|
3545
|
+
type: 'action',
|
|
3546
|
+
actionId: code
|
|
3547
|
+
});
|
|
3548
|
+
|
|
3549
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
3550
|
+
}, {
|
|
3551
|
+
s: permissionAction
|
|
3552
|
+
});
|
|
3553
|
+
|
|
3554
|
+
|
|
2911
3555
|
},
|
|
2912
3556
|
8542(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
2913
3557
|
/* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(6157);
|
|
@@ -2989,203 +3633,14 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
2989
3633
|
});
|
|
2990
3634
|
|
|
2991
3635
|
|
|
2992
|
-
},
|
|
2993
|
-
6256(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
2994
|
-
const FLOW_NODE_TYPES = [
|
|
2995
|
-
'trigger',
|
|
2996
|
-
'validate',
|
|
2997
|
-
'permission_check',
|
|
2998
|
-
'set',
|
|
2999
|
-
'condition',
|
|
3000
|
-
'switch',
|
|
3001
|
-
'foreach',
|
|
3002
|
-
'entity_insert',
|
|
3003
|
-
'entity_update',
|
|
3004
|
-
'entity_delete',
|
|
3005
|
-
'entity_get',
|
|
3006
|
-
'entity_query',
|
|
3007
|
-
'commit',
|
|
3008
|
-
'call_flow',
|
|
3009
|
-
'http_request',
|
|
3010
|
-
'publish_event',
|
|
3011
|
-
'respond',
|
|
3012
|
-
'code'
|
|
3013
|
-
];
|
|
3014
|
-
/** A failure of these always ends the run: checks can never be carried past, and Save progress cannot run in a savepoint. */ const NON_CONTINUABLE_NODE_TYPES = new Set([
|
|
3015
|
-
'validate',
|
|
3016
|
-
'permission_check',
|
|
3017
|
-
'commit'
|
|
3018
|
-
]);
|
|
3019
|
-
const FLOW_AUTH_MODES = [
|
|
3020
|
-
'public',
|
|
3021
|
-
'api_key',
|
|
3022
|
-
'jwt',
|
|
3023
|
-
'permission',
|
|
3024
|
-
'internal'
|
|
3025
|
-
];
|
|
3026
|
-
const FLOW_RUN_AS = [
|
|
3027
|
-
'caller',
|
|
3028
|
-
'system'
|
|
3029
|
-
];
|
|
3030
|
-
/** object: the body is one object and the fields are its keys (`input.<name>`). list: the body is a list and the fields describe each item (`input.0.<name>`). */ const FLOW_BODY_TYPES = [
|
|
3031
|
-
'object',
|
|
3032
|
-
'list'
|
|
3033
|
-
];
|
|
3034
|
-
const FLOW_INPUT_TYPES = [
|
|
3035
|
-
'string',
|
|
3036
|
-
'text',
|
|
3037
|
-
'number',
|
|
3038
|
-
'integer',
|
|
3039
|
-
'boolean',
|
|
3040
|
-
'date',
|
|
3041
|
-
'datetime',
|
|
3042
|
-
'email',
|
|
3043
|
-
'uuid',
|
|
3044
|
-
'object',
|
|
3045
|
-
'array',
|
|
3046
|
-
'choice'
|
|
3047
|
-
];
|
|
3048
|
-
/** How a step is named in messages: its name, or its id when it was left unnamed. */ const nodeLabel = (node)=>node.name || node.id;
|
|
3049
|
-
/**
|
|
3050
|
-
* Which records a write node touches. one (default): a single record. many: one per item of `items`,
|
|
3051
|
-
* whose per-record expressions read the item as `loop.item` (a loop around the node becomes
|
|
3052
|
-
* `loop.parent`). filter: every record matching `filter`, read as `loop.item`.
|
|
3053
|
-
*/ const RECORD_WRITE_TARGETS = [
|
|
3054
|
-
'one',
|
|
3055
|
-
'many',
|
|
3056
|
-
'filter'
|
|
3057
|
-
];
|
|
3058
|
-
const FLOW_LIMITS = {
|
|
3059
|
-
MAX_NODES: 100,
|
|
3060
|
-
MAX_EDGES: 300,
|
|
3061
|
-
/** Room for a full foreach (MAX_FOREACH_ITEMS) with a few steps per item. */ MAX_STEPS_PER_RUN: 5000,
|
|
3062
|
-
MAX_FOREACH_ITEMS: 1000,
|
|
3063
|
-
MAX_LOOP_DEPTH: 3,
|
|
3064
|
-
MAX_CALL_DEPTH: 5,
|
|
3065
|
-
MAX_HTTP_CALLS: 10,
|
|
3066
|
-
MAX_HTTP_TIMEOUT_MS: 15_000,
|
|
3067
|
-
MAX_HTTP_RESPONSE_BYTES: 1_000_000,
|
|
3068
|
-
MAX_QUERY_LIMIT: 200,
|
|
3069
|
-
MAX_WRITE_ITEMS: 1000,
|
|
3070
|
-
DEFAULT_WRITE_FILTER_LIMIT: 100,
|
|
3071
|
-
MAX_CHILD_INSERTS: 10,
|
|
3072
|
-
MAX_WRITES_PER_RUN: 5000,
|
|
3073
|
-
DEFAULT_TIMEOUT_MS: 30_000,
|
|
3074
|
-
MIN_TIMEOUT_MS: 1000,
|
|
3075
|
-
MAX_TIMEOUT_MS: 120_000,
|
|
3076
|
-
TRACE_PREVIEW_CHARS: 2000,
|
|
3077
|
-
MAX_INPUT_FIELDS: 50,
|
|
3078
|
-
/** How deep object/list-of-object fields may nest inside the request body. */ MAX_INPUT_DEPTH: 4,
|
|
3079
|
-
MAX_VALIDATE_CHECKS: 50,
|
|
3080
|
-
MAX_CODE_LENGTH: 20_000,
|
|
3081
|
-
DEFAULT_CODE_TIMEOUT_MS: 1000,
|
|
3082
|
-
MIN_CODE_TIMEOUT_MS: 10,
|
|
3083
|
-
MAX_CODE_TIMEOUT_MS: 5000,
|
|
3084
|
-
CODE_MEMORY_LIMIT_BYTES: 32 * 1024 * 1024,
|
|
3085
|
-
CODE_STACK_SIZE_BYTES: 512 * 1024,
|
|
3086
|
-
MAX_CODE_OUTPUT_BYTES: 1_000_000,
|
|
3087
|
-
MAX_CODE_LOG_LINES: 50,
|
|
3088
|
-
MAX_CODE_LOG_LINE_CHARS: 500
|
|
3089
|
-
};
|
|
3090
|
-
const FLOW_NODE_ID_PATTERN = /^[A-Za-z][A-Za-z0-9_]{0,39}$/;
|
|
3091
|
-
const FLOW_SLUG_PATTERN = /^[a-z][a-z0-9-]{2,62}$/;
|
|
3092
|
-
const FLOW_INPUT_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_]{0,59}$/;
|
|
3093
|
-
const FLOW_ENDPOINT_PATH_PATTERN = /^[a-z][a-z0-9-]{0,62}$/;
|
|
3094
|
-
/** A Request step's path, or null when it answers on the flow's own URL. */ function triggerPath(node) {
|
|
3095
|
-
const path = node.config?.path;
|
|
3096
|
-
return typeof path === 'string' && path.trim() ? path.trim() : null;
|
|
3097
|
-
}
|
|
3098
|
-
/** Every Request step of a flow as a URL. */ function flowEndpoints(flow) {
|
|
3099
|
-
return (flow.nodes ?? []).filter((node)=>node?.type === 'trigger').map((node)=>{
|
|
3100
|
-
const path = triggerPath(node);
|
|
3101
|
-
if (!path) return {
|
|
3102
|
-
nodeId: node.id,
|
|
3103
|
-
path,
|
|
3104
|
-
bodyType: flow.bodyType ?? 'object',
|
|
3105
|
-
inputSchema: flow.inputSchema ?? []
|
|
3106
|
-
};
|
|
3107
|
-
const config = node.config;
|
|
3108
|
-
return {
|
|
3109
|
-
nodeId: node.id,
|
|
3110
|
-
path,
|
|
3111
|
-
bodyType: config.bodyType ?? 'object',
|
|
3112
|
-
inputSchema: Array.isArray(config.inputSchema) ? config.inputSchema : []
|
|
3113
|
-
};
|
|
3114
|
-
});
|
|
3115
|
-
}
|
|
3116
|
-
/** The URL a call came in on: `path` of a Request step, or null / empty for the flow's own URL. */ function findEndpoint(flow, path) {
|
|
3117
|
-
const wanted = path?.trim() || null;
|
|
3118
|
-
return flowEndpoints(flow).find((endpoint)=>endpoint.path === wanted);
|
|
3119
|
-
}
|
|
3120
|
-
/** Output ports a node of this type can have (a `respond` node ends the flow: none). */ function portsOf(node) {
|
|
3121
|
-
switch(node.type){
|
|
3122
|
-
case 'condition':
|
|
3123
|
-
return [
|
|
3124
|
-
'true',
|
|
3125
|
-
'false'
|
|
3126
|
-
];
|
|
3127
|
-
case 'switch':
|
|
3128
|
-
return [
|
|
3129
|
-
...(node.config.cases ?? []).map((c)=>c.id),
|
|
3130
|
-
'default'
|
|
3131
|
-
];
|
|
3132
|
-
case 'foreach':
|
|
3133
|
-
return [
|
|
3134
|
-
'each',
|
|
3135
|
-
'done'
|
|
3136
|
-
];
|
|
3137
|
-
case 'permission_check':
|
|
3138
|
-
return node.config.onDenied === 'branch' ? [
|
|
3139
|
-
'allowed',
|
|
3140
|
-
'denied'
|
|
3141
|
-
] : [
|
|
3142
|
-
'out'
|
|
3143
|
-
];
|
|
3144
|
-
case 'respond':
|
|
3145
|
-
return [];
|
|
3146
|
-
case 'trigger':
|
|
3147
|
-
case 'validate':
|
|
3148
|
-
case 'set':
|
|
3149
|
-
case 'commit':
|
|
3150
|
-
return [
|
|
3151
|
-
'out'
|
|
3152
|
-
];
|
|
3153
|
-
default:
|
|
3154
|
-
return [
|
|
3155
|
-
'out',
|
|
3156
|
-
'error'
|
|
3157
|
-
];
|
|
3158
|
-
}
|
|
3159
|
-
}
|
|
3160
|
-
|
|
3161
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
3162
|
-
Xr: () => (flowEndpoints),
|
|
3163
|
-
a5: () => (portsOf),
|
|
3164
|
-
um: () => (triggerPath),
|
|
3165
|
-
vS: () => (findEndpoint)
|
|
3166
|
-
}, {
|
|
3167
|
-
At: NON_CONTINUABLE_NODE_TYPES,
|
|
3168
|
-
Dn: RECORD_WRITE_TARGETS,
|
|
3169
|
-
Or: FLOW_LIMITS,
|
|
3170
|
-
Q7: FLOW_INPUT_TYPES,
|
|
3171
|
-
Y3: FLOW_BODY_TYPES,
|
|
3172
|
-
YD: FLOW_SLUG_PATTERN,
|
|
3173
|
-
YO: FLOW_ENDPOINT_PATH_PATTERN,
|
|
3174
|
-
dA: nodeLabel,
|
|
3175
|
-
fO: FLOW_AUTH_MODES,
|
|
3176
|
-
fZ: FLOW_INPUT_NAME_PATTERN,
|
|
3177
|
-
gl: FLOW_RUN_AS,
|
|
3178
|
-
q2: FLOW_NODE_TYPES,
|
|
3179
|
-
z6: FLOW_NODE_ID_PATTERN
|
|
3180
|
-
});
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
3636
|
},
|
|
3184
3637
|
2678(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
3185
3638
|
const SENSITIVE_KEY = /pass(word)?|secret|token|authorization|api[-_]?key|cookie|credential|private[-_]?key/i;
|
|
3186
3639
|
/** Copy of `value` with the content of sensitive-looking keys replaced, safe to store in a log. */ function redactSensitive(value, depth = 0) {
|
|
3187
3640
|
if (depth > 8) return '[deep]';
|
|
3188
3641
|
if (Array.isArray(value)) return value.slice(0, 100).map((v)=>redactSensitive(v, depth + 1));
|
|
3642
|
+
// Dates (and anything else with its own JSON form) have no own keys: walked as objects they would log as `{}`.
|
|
3643
|
+
if (value && typeof value.toJSON === 'function') return redactSensitive(value.toJSON(), depth + 1);
|
|
3189
3644
|
if (value && typeof value === 'object') {
|
|
3190
3645
|
const out = {};
|
|
3191
3646
|
for (const [key, item] of Object.entries(value)){
|
|
@@ -3214,6 +3669,24 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
3214
3669
|
});
|
|
3215
3670
|
|
|
3216
3671
|
|
|
3672
|
+
},
|
|
3673
|
+
9609(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
3674
|
+
/** What a version holds and a draft edits: everything about a flow but its identity. */ const FLOW_VERSIONED_FIELDS = [
|
|
3675
|
+
'name',
|
|
3676
|
+
'slug',
|
|
3677
|
+
'description',
|
|
3678
|
+
'isActive',
|
|
3679
|
+
'retainExecutions',
|
|
3680
|
+
'nodes',
|
|
3681
|
+
'edges'
|
|
3682
|
+
];
|
|
3683
|
+
|
|
3684
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
3685
|
+
}, {
|
|
3686
|
+
v: FLOW_VERSIONED_FIELDS
|
|
3687
|
+
});
|
|
3688
|
+
|
|
3689
|
+
|
|
3217
3690
|
},
|
|
3218
3691
|
8323(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
3219
3692
|
/* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(6157);
|
|
@@ -3415,6 +3888,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
3415
3888
|
}
|
|
3416
3889
|
|
|
3417
3890
|
|
|
3891
|
+
const VARIABLE_ENV_PREFIX = 'ENTITY_BUILDER_VAR_';
|
|
3418
3892
|
class EntityBuilderConfigService {
|
|
3419
3893
|
options;
|
|
3420
3894
|
constructor(options){
|
|
@@ -3435,6 +3909,20 @@ class EntityBuilderConfigService {
|
|
|
3435
3909
|
getConfig() {
|
|
3436
3910
|
return this.options.config;
|
|
3437
3911
|
}
|
|
3912
|
+
/** `designer.readOnly`, else the `ENTITY_BUILDER_READ_ONLY=true` env variable (production). */ isDesignerReadOnly() {
|
|
3913
|
+
return this.getConfig()?.designer?.readOnly ?? process.env['ENTITY_BUILDER_READ_ONLY'] === 'true';
|
|
3914
|
+
}
|
|
3915
|
+
/** The values behind `${var:NAME}` in promoted flows: every non-empty `ENTITY_BUILDER_VAR_<NAME>` env variable, overridden by `bundles.variables`; names a placeholder cannot carry are left out. */ getBundleVariables() {
|
|
3916
|
+
const fromEnv = Object.entries(process.env).filter((entry)=>entry[0].startsWith(VARIABLE_ENV_PREFIX) && !!entry[1]).map(([key, value])=>[
|
|
3917
|
+
key.slice(VARIABLE_ENV_PREFIX.length),
|
|
3918
|
+
value
|
|
3919
|
+
]);
|
|
3920
|
+
const variables = {
|
|
3921
|
+
...Object.fromEntries(fromEnv),
|
|
3922
|
+
...this.getConfig()?.bundles?.variables
|
|
3923
|
+
};
|
|
3924
|
+
return Object.fromEntries(Object.entries(variables).filter((entry)=>_config_entity_builder_constants_js__rspack_import_1/* .BUNDLE_VARIABLE_NAME_PATTERN.test */.JI.test(entry[0]) && typeof entry[1] === 'string'));
|
|
3925
|
+
}
|
|
3438
3926
|
}
|
|
3439
3927
|
EntityBuilderConfigService = _ts_decorate([
|
|
3440
3928
|
(0,_nestjs_common__rspack_import_0.Injectable)(),
|
|
@@ -3840,54 +4328,24 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
3840
4328
|
|
|
3841
4329
|
|
|
3842
4330
|
},
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
__webpack_require__
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
var
|
|
3852
|
-
|
|
3853
|
-
var
|
|
3854
|
-
|
|
3855
|
-
var
|
|
3856
|
-
|
|
3857
|
-
var
|
|
3858
|
-
|
|
3859
|
-
var
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
const API_KEY_PREFIX_LENGTH = 11; // "fk_" + 8 hex
|
|
3863
|
-
/** A new key: `fk_<8 hex>_<32 hex>`. Shown once; only its hash is stored. */ function generateApiKey() {
|
|
3864
|
-
const key = `fk_${(0,external_node_crypto_.randomBytes)(4).toString('hex')}_${(0,external_node_crypto_.randomBytes)(16).toString('hex')}`;
|
|
3865
|
-
return {
|
|
3866
|
-
key,
|
|
3867
|
-
prefix: apiKeyPrefix(key),
|
|
3868
|
-
hash: hashApiKey(key)
|
|
3869
|
-
};
|
|
3870
|
-
}
|
|
3871
|
-
const hashApiKey = (key)=>(0,external_node_crypto_.createHash)('sha256').update(key).digest('hex');
|
|
3872
|
-
const apiKeyPrefix = (key)=>key.slice(0, API_KEY_PREFIX_LENGTH);
|
|
3873
|
-
function looksLikeApiKey(key) {
|
|
3874
|
-
return typeof key === 'string' && /^fk_[0-9a-f]{8}_[0-9a-f]{32}$/.test(key);
|
|
3875
|
-
}
|
|
3876
|
-
/** Constant-time comparison of a presented key against a stored hash. */ function apiKeyMatches(presented, storedHash) {
|
|
3877
|
-
const a = Buffer.from(hashApiKey(presented), 'hex');
|
|
3878
|
-
const b = Buffer.from(storedHash, 'hex');
|
|
3879
|
-
return a.length === b.length && (0,external_node_crypto_.timingSafeEqual)(a, b);
|
|
3880
|
-
}
|
|
3881
|
-
|
|
3882
|
-
// EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/entities/flow-definition.entity.ts
|
|
3883
|
-
var flow_definition_entity = __webpack_require__(3770);
|
|
3884
|
-
// EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/rule-engine/rule-values.ts
|
|
3885
|
-
var rule_values = __webpack_require__(6622);
|
|
3886
|
-
// EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/services/entity-builder-datasource.provider.ts
|
|
3887
|
-
var entity_builder_datasource_provider = __webpack_require__(424);
|
|
3888
|
-
// EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/services/flow-definition.service.ts
|
|
3889
|
-
var flow_definition_service = __webpack_require__(5229);
|
|
3890
|
-
;// CONCATENATED MODULE: ./projects/nestjs-entity-builder/src/services/flow-api-key.service.ts
|
|
4331
|
+
5229(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
4332
|
+
/* import */ var _flusys_nestjs_shared__rspack_import_0 = __webpack_require__(3422);
|
|
4333
|
+
/* import */ var _flusys_nestjs_shared_classes__rspack_import_1 = __webpack_require__(6937);
|
|
4334
|
+
/* import */ var _flusys_nestjs_shared_interfaces__rspack_import_2 = __webpack_require__(5103);
|
|
4335
|
+
/* import */ var _flusys_nestjs_shared_modules__rspack_import_3 = __webpack_require__(1236);
|
|
4336
|
+
/* import */ var _nestjs_common__rspack_import_4 = __webpack_require__(6157);
|
|
4337
|
+
/* import */ var typeorm__rspack_import_5 = __webpack_require__(7158);
|
|
4338
|
+
/* import */ var _config_event_actions_js__rspack_import_16 = __webpack_require__(982);
|
|
4339
|
+
/* import */ var _config_message_keys_js__rspack_import_14 = __webpack_require__(5732);
|
|
4340
|
+
/* import */ var _entities_entity_definition_entity_js__rspack_import_6 = __webpack_require__(3189);
|
|
4341
|
+
/* import */ var _entities_flow_definition_entity_js__rspack_import_7 = __webpack_require__(3770);
|
|
4342
|
+
/* import */ var _entities_flow_version_entity_js__rspack_import_8 = __webpack_require__(2399);
|
|
4343
|
+
/* import */ var _flow_engine_flow_api_key_js__rspack_import_9 = __webpack_require__(4816);
|
|
4344
|
+
/* import */ var _flow_engine_flow_permission_logic_js__rspack_import_13 = __webpack_require__(8220);
|
|
4345
|
+
/* import */ var _flow_engine_flow_graph_validator_js__rspack_import_10 = __webpack_require__(3186);
|
|
4346
|
+
/* import */ var _flow_engine_flow_types_js__rspack_import_11 = __webpack_require__(6256);
|
|
4347
|
+
/* import */ var _interfaces_flow_definition_interface_js__rspack_import_15 = __webpack_require__(9609);
|
|
4348
|
+
/* import */ var _entity_builder_datasource_provider_js__rspack_import_12 = __webpack_require__(424);
|
|
3891
4349
|
function _ts_decorate(decorators, target, key, desc) {
|
|
3892
4350
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3893
4351
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -3920,194 +4378,6 @@ function _ts_param(paramIndex, decorator) {
|
|
|
3920
4378
|
|
|
3921
4379
|
|
|
3922
4380
|
|
|
3923
|
-
const TOUCH_INTERVAL_MS = 60_000;
|
|
3924
|
-
class FlowApiKeyService {
|
|
3925
|
-
provider;
|
|
3926
|
-
constructor(provider){
|
|
3927
|
-
this.provider = provider;
|
|
3928
|
-
}
|
|
3929
|
-
async repo() {
|
|
3930
|
-
return this.provider.getRepository(flow_api_key_entity/* .FlowApiKey */.S);
|
|
3931
|
-
}
|
|
3932
|
-
async assertFlowExists(flowId) {
|
|
3933
|
-
const flow = await (await this.provider.getRepository(flow_definition_entity/* .FlowDefinition */.G)).findOne({
|
|
3934
|
-
where: {
|
|
3935
|
-
id: flowId
|
|
3936
|
-
},
|
|
3937
|
-
select: {
|
|
3938
|
-
id: true
|
|
3939
|
-
}
|
|
3940
|
-
});
|
|
3941
|
-
if (!flow) throw (0,flow_definition_service/* .flowNotFound */.YW)();
|
|
3942
|
-
}
|
|
3943
|
-
async findKey(id) {
|
|
3944
|
-
const key = await (await this.repo()).findOne({
|
|
3945
|
-
where: {
|
|
3946
|
-
id
|
|
3947
|
-
}
|
|
3948
|
-
});
|
|
3949
|
-
if (!key) throw new common_.NotFoundException({
|
|
3950
|
-
message: 'API key not found.',
|
|
3951
|
-
messageKey: message_keys/* .FLOW_MESSAGES.API_KEY_NOT_FOUND */.wu.API_KEY_NOT_FOUND
|
|
3952
|
-
});
|
|
3953
|
-
await this.assertFlowExists(key.flowId);
|
|
3954
|
-
return key;
|
|
3955
|
-
}
|
|
3956
|
-
/** The plain key is returned here and never again. */ async create(flowId, name, expiresAt, user) {
|
|
3957
|
-
const expiry = expiresAt ? (0,rule_values/* .parseDateText */.hz)(expiresAt) : null;
|
|
3958
|
-
if (expiry !== null && !(expiry > Date.now())) {
|
|
3959
|
-
throw new common_.BadRequestException({
|
|
3960
|
-
message: 'The expiry date of an API key must be in the future.',
|
|
3961
|
-
messageKey: message_keys/* .FLOW_MESSAGES.API_KEY_EXPIRY_IN_PAST */.wu.API_KEY_EXPIRY_IN_PAST
|
|
3962
|
-
});
|
|
3963
|
-
}
|
|
3964
|
-
await this.assertFlowExists(flowId);
|
|
3965
|
-
const { key, prefix, hash } = generateApiKey();
|
|
3966
|
-
const repo = await this.repo();
|
|
3967
|
-
const saved = await repo.save(repo.create({
|
|
3968
|
-
flowId,
|
|
3969
|
-
name,
|
|
3970
|
-
keyPrefix: prefix,
|
|
3971
|
-
keyHash: hash,
|
|
3972
|
-
isActive: true,
|
|
3973
|
-
expiresAt: expiry === null ? null : new Date(expiry),
|
|
3974
|
-
lastUsedAt: null,
|
|
3975
|
-
createdById: user?.id ?? null
|
|
3976
|
-
}));
|
|
3977
|
-
return {
|
|
3978
|
-
key,
|
|
3979
|
-
info: this.info(saved)
|
|
3980
|
-
};
|
|
3981
|
-
}
|
|
3982
|
-
async list(flowId) {
|
|
3983
|
-
await this.assertFlowExists(flowId);
|
|
3984
|
-
const rows = await (await this.repo()).find({
|
|
3985
|
-
where: {
|
|
3986
|
-
flowId
|
|
3987
|
-
},
|
|
3988
|
-
order: {
|
|
3989
|
-
createdAt: 'DESC'
|
|
3990
|
-
}
|
|
3991
|
-
});
|
|
3992
|
-
return rows.map((r)=>this.info(r));
|
|
3993
|
-
}
|
|
3994
|
-
async revoke(id) {
|
|
3995
|
-
const key = await this.findKey(id);
|
|
3996
|
-
await (await this.repo()).update({
|
|
3997
|
-
id: key.id
|
|
3998
|
-
}, {
|
|
3999
|
-
isActive: false
|
|
4000
|
-
});
|
|
4001
|
-
}
|
|
4002
|
-
async remove(id) {
|
|
4003
|
-
const key = await this.findKey(id);
|
|
4004
|
-
await (await this.repo()).softDelete({
|
|
4005
|
-
id: key.id
|
|
4006
|
-
});
|
|
4007
|
-
}
|
|
4008
|
-
/**
|
|
4009
|
-
* Checks `presented` against the unrevoked keys of this flow. Only the flow access guard calls
|
|
4010
|
-
* this, and only while the flow's authMode is `api_key`; revoking works in any authMode.
|
|
4011
|
-
*/ async verify(flowId, presented) {
|
|
4012
|
-
if (!looksLikeApiKey(presented)) return 'invalid';
|
|
4013
|
-
const repo = await this.repo();
|
|
4014
|
-
const candidates = await repo.find({
|
|
4015
|
-
where: {
|
|
4016
|
-
flowId,
|
|
4017
|
-
keyPrefix: apiKeyPrefix(presented),
|
|
4018
|
-
isActive: true,
|
|
4019
|
-
deletedAt: (0,external_typeorm_.IsNull)()
|
|
4020
|
-
},
|
|
4021
|
-
select: {
|
|
4022
|
-
id: true,
|
|
4023
|
-
keyHash: true,
|
|
4024
|
-
expiresAt: true,
|
|
4025
|
-
lastUsedAt: true
|
|
4026
|
-
}
|
|
4027
|
-
});
|
|
4028
|
-
const match = candidates.find((c)=>apiKeyMatches(presented, c.keyHash));
|
|
4029
|
-
if (!match) return 'invalid';
|
|
4030
|
-
if (isExpired(match.expiresAt)) return 'expired';
|
|
4031
|
-
if (!match.lastUsedAt || Date.now() - match.lastUsedAt.getTime() > TOUCH_INTERVAL_MS) {
|
|
4032
|
-
await repo.update({
|
|
4033
|
-
id: match.id
|
|
4034
|
-
}, {
|
|
4035
|
-
lastUsedAt: new Date()
|
|
4036
|
-
});
|
|
4037
|
-
}
|
|
4038
|
-
return 'valid';
|
|
4039
|
-
}
|
|
4040
|
-
info(row) {
|
|
4041
|
-
const status = !row.isActive ? 'revoked' : isExpired(row.expiresAt) ? 'expired' : 'active';
|
|
4042
|
-
return {
|
|
4043
|
-
id: row.id,
|
|
4044
|
-
flowId: row.flowId,
|
|
4045
|
-
name: row.name,
|
|
4046
|
-
keyPrefix: row.keyPrefix,
|
|
4047
|
-
isActive: row.isActive,
|
|
4048
|
-
status,
|
|
4049
|
-
expiresAt: row.expiresAt,
|
|
4050
|
-
lastUsedAt: row.lastUsedAt,
|
|
4051
|
-
createdAt: row.createdAt
|
|
4052
|
-
};
|
|
4053
|
-
}
|
|
4054
|
-
}
|
|
4055
|
-
FlowApiKeyService = _ts_decorate([
|
|
4056
|
-
(0,common_.Injectable)({
|
|
4057
|
-
scope: common_.Scope.REQUEST
|
|
4058
|
-
}),
|
|
4059
|
-
_ts_param(0, (0,common_.Inject)(entity_builder_datasource_provider/* .EntityBuilderDataSourceProvider */.D)),
|
|
4060
|
-
_ts_metadata("design:type", Function),
|
|
4061
|
-
_ts_metadata("design:paramtypes", [
|
|
4062
|
-
typeof entity_builder_datasource_provider/* .EntityBuilderDataSourceProvider */.D === "undefined" ? Object : entity_builder_datasource_provider/* .EntityBuilderDataSourceProvider */.D
|
|
4063
|
-
])
|
|
4064
|
-
], FlowApiKeyService);
|
|
4065
|
-
function isExpired(expiresAt) {
|
|
4066
|
-
return !!expiresAt && expiresAt.getTime() <= Date.now();
|
|
4067
|
-
}
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
},
|
|
4071
|
-
5229(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
4072
|
-
/* import */ var _flusys_nestjs_shared__rspack_import_0 = __webpack_require__(3422);
|
|
4073
|
-
/* import */ var _flusys_nestjs_shared_classes__rspack_import_1 = __webpack_require__(6937);
|
|
4074
|
-
/* import */ var _flusys_nestjs_shared_modules__rspack_import_2 = __webpack_require__(1236);
|
|
4075
|
-
/* import */ var _nestjs_common__rspack_import_3 = __webpack_require__(6157);
|
|
4076
|
-
/* import */ var typeorm__rspack_import_4 = __webpack_require__(7158);
|
|
4077
|
-
/* import */ var _config_event_actions_js__rspack_import_11 = __webpack_require__(982);
|
|
4078
|
-
/* import */ var _config_message_keys_js__rspack_import_10 = __webpack_require__(5732);
|
|
4079
|
-
/* import */ var _entities_entity_definition_entity_js__rspack_import_5 = __webpack_require__(3189);
|
|
4080
|
-
/* import */ var _entities_flow_definition_entity_js__rspack_import_6 = __webpack_require__(3770);
|
|
4081
|
-
/* import */ var _flow_engine_flow_graph_validator_js__rspack_import_7 = __webpack_require__(3186);
|
|
4082
|
-
/* import */ var _flow_engine_flow_types_js__rspack_import_8 = __webpack_require__(6256);
|
|
4083
|
-
/* import */ var _entity_builder_datasource_provider_js__rspack_import_9 = __webpack_require__(424);
|
|
4084
|
-
function _ts_decorate(decorators, target, key, desc) {
|
|
4085
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4086
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
4087
|
-
r = Reflect.decorate(decorators, target, key, desc);
|
|
4088
|
-
} else {
|
|
4089
|
-
for(var i = decorators.length - 1; i >= 0; i--){
|
|
4090
|
-
if (d = decorators[i]) {
|
|
4091
|
-
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
4092
|
-
}
|
|
4093
|
-
}
|
|
4094
|
-
}
|
|
4095
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
4096
|
-
}
|
|
4097
|
-
function _ts_metadata(metadataKey, metadataValue) {
|
|
4098
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
4099
|
-
return Reflect.metadata(metadataKey, metadataValue);
|
|
4100
|
-
}
|
|
4101
|
-
}
|
|
4102
|
-
function _ts_param(paramIndex, decorator) {
|
|
4103
|
-
return function(target, key) {
|
|
4104
|
-
decorator(target, key, paramIndex);
|
|
4105
|
-
};
|
|
4106
|
-
}
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
4381
|
|
|
4112
4382
|
|
|
4113
4383
|
|
|
@@ -4117,21 +4387,28 @@ function _ts_param(paramIndex, decorator) {
|
|
|
4117
4387
|
|
|
4118
4388
|
|
|
4119
4389
|
const defaultFlowPermissionCode = (slug)=>`entity_builder.flow.${slug}.execute`;
|
|
4120
|
-
const
|
|
4390
|
+
/** 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));
|
|
4391
|
+
const flowNotFound = ()=>new _nestjs_common__rspack_import_4.NotFoundException({
|
|
4121
4392
|
message: 'Flow not found.',
|
|
4122
|
-
messageKey:
|
|
4393
|
+
messageKey: _config_message_keys_js__rspack_import_14/* .FLOW_MESSAGES.NOT_FOUND */.wu.NOT_FOUND
|
|
4394
|
+
});
|
|
4395
|
+
/** A flow that has been published at least once: its columns are what callers run. */ const isPublished = (flow)=>flow.version > 0;
|
|
4396
|
+
/** The versioned part of a flow (or of a draft), in a fixed key order so two snapshots compare as text. */ function snapshotOf(source) {
|
|
4397
|
+
return Object.fromEntries(_interfaces_flow_definition_interface_js__rspack_import_15/* .FLOW_VERSIONED_FIELDS.filter */.v.filter((key)=>source[key] !== undefined).map((key)=>[
|
|
4398
|
+
key,
|
|
4399
|
+
source[key]
|
|
4400
|
+
]));
|
|
4401
|
+
}
|
|
4402
|
+
const sameSnapshot = (a, b)=>JSON.stringify(a) === JSON.stringify(b);
|
|
4403
|
+
/** What the designer edits: the saved draft, or the published flow when there is none. */ const workingCopy = (flow)=>({
|
|
4404
|
+
...snapshotOf(flow),
|
|
4405
|
+
...flow.draft
|
|
4123
4406
|
});
|
|
4124
|
-
/**
|
|
4407
|
+
/** What running a flow needs; everything about a run is on its Request steps. */ function toFlowSettings(dto) {
|
|
4125
4408
|
return {
|
|
4126
4409
|
slug: dto.slug,
|
|
4127
|
-
authMode: dto.authMode ?? 'jwt',
|
|
4128
|
-
runAs: dto.runAs ?? 'caller',
|
|
4129
|
-
isTransactional: dto.isTransactional ?? false,
|
|
4130
|
-
bodyType: dto.bodyType ?? 'object',
|
|
4131
|
-
inputSchema: dto.inputSchema ?? [],
|
|
4132
4410
|
nodes: dto.nodes ?? [],
|
|
4133
|
-
edges: dto.edges ?? []
|
|
4134
|
-
timeoutMs: dto.timeoutMs ?? _flow_engine_flow_types_js__rspack_import_8/* .FLOW_LIMITS.DEFAULT_TIMEOUT_MS */.Or.DEFAULT_TIMEOUT_MS
|
|
4411
|
+
edges: dto.edges ?? []
|
|
4135
4412
|
};
|
|
4136
4413
|
}
|
|
4137
4414
|
class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import_1.ApiService {
|
|
@@ -4140,11 +4417,14 @@ class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import
|
|
|
4140
4417
|
provider;
|
|
4141
4418
|
permissionCache;
|
|
4142
4419
|
actionRegistry;
|
|
4143
|
-
|
|
4144
|
-
|
|
4420
|
+
notifications;
|
|
4421
|
+
email;
|
|
4422
|
+
companyAccess;
|
|
4423
|
+
constructor(cacheManager, utilsService, provider, permissionCache, actionRegistry, notifications, email, companyAccess){
|
|
4424
|
+
super(_config_event_actions_js__rspack_import_16/* .ENTITY_BUILDER_EVENT_ENTITIES.FLOW_DEFINITION */.P.FLOW_DEFINITION, cacheManager, utilsService, FlowDefinitionService.name, true, _config_event_actions_js__rspack_import_16/* .ENTITY_BUILDER_EVENT_MODULE */.S, provider, _entities_flow_definition_entity_js__rspack_import_7/* .FlowDefinition */.G), this.cacheManager = cacheManager, this.utilsService = utilsService, this.provider = provider, this.permissionCache = permissionCache, this.actionRegistry = actionRegistry, this.notifications = notifications, this.email = email, this.companyAccess = companyAccess;
|
|
4145
4425
|
}
|
|
4146
4426
|
async findOrFail(id) {
|
|
4147
|
-
const flow = await (await this.provider.getRepository(
|
|
4427
|
+
const flow = await (await this.provider.getRepository(_entities_flow_definition_entity_js__rspack_import_7/* .FlowDefinition */.G)).findOne({
|
|
4148
4428
|
where: {
|
|
4149
4429
|
id
|
|
4150
4430
|
}
|
|
@@ -4152,28 +4432,28 @@ class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import
|
|
|
4152
4432
|
if (!flow) throw flowNotFound();
|
|
4153
4433
|
return flow;
|
|
4154
4434
|
}
|
|
4155
|
-
/** Validation with the real entity and flow lists. Returns errors and warnings without throwing. */ async validate(settings) {
|
|
4156
|
-
const entities = await (await this.provider.getRepository(
|
|
4435
|
+
/** Validation with the real entity and flow lists and the modules this app runs. Returns errors and warnings without throwing. */ async validate(settings) {
|
|
4436
|
+
const entities = await (await this.provider.getRepository(_entities_entity_definition_entity_js__rspack_import_6/* .EntityDefinition */.f)).find({
|
|
4157
4437
|
select: {
|
|
4158
4438
|
code: true
|
|
4159
4439
|
}
|
|
4160
4440
|
});
|
|
4161
|
-
const flows = await (await this.provider.getRepository(
|
|
4162
|
-
return (0,
|
|
4441
|
+
const flows = await (await this.provider.getRepository(_entities_flow_definition_entity_js__rspack_import_7/* .FlowDefinition */.G)).find();
|
|
4442
|
+
return (0,_flow_engine_flow_graph_validator_js__rspack_import_10/* .validateFlow */.nC)(settings, {
|
|
4163
4443
|
knownEntityCodes: new Set(entities.map((e)=>e.code)),
|
|
4164
4444
|
knownFlows: new Map(flows.map((flow)=>[
|
|
4165
4445
|
flow.slug,
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4446
|
+
callableOf(flow)
|
|
4447
|
+
])),
|
|
4448
|
+
messageServices: {
|
|
4449
|
+
notification: !!this.notifications,
|
|
4450
|
+
email: !!this.email
|
|
4451
|
+
},
|
|
4452
|
+
companyMembers: !!this.companyAccess
|
|
4173
4453
|
});
|
|
4174
4454
|
}
|
|
4175
4455
|
/** Names of the other flows whose `call_flow` nodes run `slug`. */ async callersOf(slug, excludeIds) {
|
|
4176
|
-
const flows = await (await this.provider.getRepository(
|
|
4456
|
+
const flows = await (await this.provider.getRepository(_entities_flow_definition_entity_js__rspack_import_7/* .FlowDefinition */.G)).find({
|
|
4177
4457
|
select: {
|
|
4178
4458
|
id: true,
|
|
4179
4459
|
name: true,
|
|
@@ -4185,20 +4465,83 @@ class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import
|
|
|
4185
4465
|
async assertNotCalled(slug, excludeIds) {
|
|
4186
4466
|
const callers = await this.callersOf(slug, excludeIds);
|
|
4187
4467
|
if (!callers.length) return;
|
|
4188
|
-
throw new
|
|
4468
|
+
throw new _nestjs_common__rspack_import_4.ConflictException({
|
|
4189
4469
|
message: `The flow '${slug}' is called by: ${callers.join(', ')}. Change those flows first.`,
|
|
4190
|
-
messageKey:
|
|
4470
|
+
messageKey: _config_message_keys_js__rspack_import_14/* .FLOW_MESSAGES.CALLED_BY_OTHER_FLOWS */.wu.CALLED_BY_OTHER_FLOWS,
|
|
4191
4471
|
messageVariables: {
|
|
4192
4472
|
slug,
|
|
4193
4473
|
flows: callers.join(', ')
|
|
4194
4474
|
}
|
|
4195
4475
|
});
|
|
4196
4476
|
}
|
|
4477
|
+
/**
|
|
4478
|
+
* Other flows' Call flow steps keep working: the URL name they call is not renamed, the paths they
|
|
4479
|
+
* start at are not dropped, and nothing else they rely on changes under them - access, body,
|
|
4480
|
+
* required inputs, the flow staying on, the call chain staying loop-free and within depth.
|
|
4481
|
+
*/ async assertCallersKept(before, after, live) {
|
|
4482
|
+
if (after.slug !== before.slug) return this.assertNotCalled(before.slug, [
|
|
4483
|
+
before.id
|
|
4484
|
+
]);
|
|
4485
|
+
await this.assertEndpointsNotCalled(before, after);
|
|
4486
|
+
await this.assertCallsStillValid(before, {
|
|
4487
|
+
...after,
|
|
4488
|
+
...live
|
|
4489
|
+
});
|
|
4490
|
+
}
|
|
4491
|
+
/**
|
|
4492
|
+
* Checks each running flow that calls this one, directly or through other flows, against the flows
|
|
4493
|
+
* as they are and as this change leaves them, and refuses the change when it adds a problem. A
|
|
4494
|
+
* caller already broken for another reason does not block it; only what this change breaks does.
|
|
4495
|
+
*/ async assertCallsStillValid(before, after) {
|
|
4496
|
+
const flows = await (await this.provider.getRepository(_entities_flow_definition_entity_js__rspack_import_7/* .FlowDefinition */.G)).find();
|
|
4497
|
+
const running = flows.filter((flow)=>flow.id !== before.id && flow.isActive && isPublished(flow) && calledSlugs(flow.nodes).length);
|
|
4498
|
+
if (!running.length) return;
|
|
4499
|
+
const now = new Map(flows.map((flow)=>[
|
|
4500
|
+
flow.slug,
|
|
4501
|
+
callableOf(flow)
|
|
4502
|
+
]));
|
|
4503
|
+
const next = new Map(now).set(before.slug, callableOf(after));
|
|
4504
|
+
const broken = [];
|
|
4505
|
+
for (const caller of running){
|
|
4506
|
+
const settings = toFlowSettings(caller);
|
|
4507
|
+
// Counted, not a set: two steps with the same label can share a problem, and only the new one is added.
|
|
4508
|
+
const existing = new Map();
|
|
4509
|
+
for (const problem of (0,_flow_engine_flow_graph_validator_js__rspack_import_10/* .callProblems */.r7)(settings, before.slug, now)){
|
|
4510
|
+
const key = JSON.stringify(problem);
|
|
4511
|
+
existing.set(key, (existing.get(key) ?? 0) + 1);
|
|
4512
|
+
}
|
|
4513
|
+
const added = (0,_flow_engine_flow_graph_validator_js__rspack_import_10/* .callProblems */.r7)(settings, before.slug, next).filter((problem)=>{
|
|
4514
|
+
const key = JSON.stringify(problem);
|
|
4515
|
+
const left = existing.get(key) ?? 0;
|
|
4516
|
+
existing.set(key, left - 1);
|
|
4517
|
+
return left <= 0;
|
|
4518
|
+
});
|
|
4519
|
+
if (added.length) broken.push({
|
|
4520
|
+
flow: caller.name,
|
|
4521
|
+
problems: added
|
|
4522
|
+
});
|
|
4523
|
+
}
|
|
4524
|
+
if (!broken.length) return;
|
|
4525
|
+
const names = broken.map((b)=>b.flow).join(', ');
|
|
4526
|
+
throw new _nestjs_common__rspack_import_4.ConflictException({
|
|
4527
|
+
message: `This change breaks flows that call '${before.slug}': ${names}. Change those flows first.`,
|
|
4528
|
+
messageKey: _config_message_keys_js__rspack_import_14/* .FLOW_MESSAGES.CALLERS_BROKEN */.wu.CALLERS_BROKEN,
|
|
4529
|
+
messageVariables: {
|
|
4530
|
+
slug: before.slug,
|
|
4531
|
+
flows: names
|
|
4532
|
+
},
|
|
4533
|
+
errors: broken.flatMap((b)=>b.problems.map((problem)=>({
|
|
4534
|
+
field: 'flow',
|
|
4535
|
+
flow: b.flow,
|
|
4536
|
+
...problem
|
|
4537
|
+
})))
|
|
4538
|
+
});
|
|
4539
|
+
}
|
|
4197
4540
|
/** A URL other flows' Call flow steps start at cannot be removed or renamed from under them. */ async assertEndpointsNotCalled(before, after) {
|
|
4198
|
-
const kept = new Set((0,
|
|
4199
|
-
const removed = (0,
|
|
4541
|
+
const kept = new Set((0,_flow_engine_flow_types_js__rspack_import_11/* .flowEndpoints */.Xr)(after).map((e)=>e.path));
|
|
4542
|
+
const removed = (0,_flow_engine_flow_types_js__rspack_import_11/* .flowEndpoints */.Xr)(before).map((e)=>e.path).filter((path)=>!kept.has(path));
|
|
4200
4543
|
if (!removed.length) return;
|
|
4201
|
-
const flows = await (await this.provider.getRepository(
|
|
4544
|
+
const flows = await (await this.provider.getRepository(_entities_flow_definition_entity_js__rspack_import_7/* .FlowDefinition */.G)).find({
|
|
4202
4545
|
select: {
|
|
4203
4546
|
id: true,
|
|
4204
4547
|
name: true,
|
|
@@ -4209,9 +4552,9 @@ class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import
|
|
|
4209
4552
|
const callers = flows.filter((flow)=>flow.id !== before.id && calledTargets(flow.nodes).some((t)=>t.slug === before.slug && t.endpoint === path)).map((flow)=>flow.name);
|
|
4210
4553
|
if (!callers.length) continue;
|
|
4211
4554
|
const url = `api-flows/${before.slug}${path ? `/${path}` : ''}`;
|
|
4212
|
-
throw new
|
|
4555
|
+
throw new _nestjs_common__rspack_import_4.ConflictException({
|
|
4213
4556
|
message: `The URL ${url} is called by: ${callers.join(', ')}. Change those flows first.`,
|
|
4214
|
-
messageKey:
|
|
4557
|
+
messageKey: _config_message_keys_js__rspack_import_14/* .FLOW_MESSAGES.ENDPOINT_CALLED_BY_OTHER_FLOWS */.wu.ENDPOINT_CALLED_BY_OTHER_FLOWS,
|
|
4215
4558
|
messageVariables: {
|
|
4216
4559
|
url,
|
|
4217
4560
|
flows: callers.join(', ')
|
|
@@ -4222,9 +4565,9 @@ class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import
|
|
|
4222
4565
|
async assertSaveable(settings, user, selfId) {
|
|
4223
4566
|
const { errors, warnings } = await this.validate(settings);
|
|
4224
4567
|
if (errors.length) {
|
|
4225
|
-
throw new
|
|
4568
|
+
throw new _nestjs_common__rspack_import_4.BadRequestException({
|
|
4226
4569
|
message: 'The flow has problems.',
|
|
4227
|
-
messageKey:
|
|
4570
|
+
messageKey: _config_message_keys_js__rspack_import_14/* .FLOW_MESSAGES.INVALID */.wu.INVALID,
|
|
4228
4571
|
errors: errors.map((error)=>({
|
|
4229
4572
|
field: 'flow',
|
|
4230
4573
|
...error
|
|
@@ -4232,16 +4575,16 @@ class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import
|
|
|
4232
4575
|
warnings
|
|
4233
4576
|
});
|
|
4234
4577
|
}
|
|
4235
|
-
const clash = await (await this.provider.getRepository(
|
|
4578
|
+
const clash = await (await this.provider.getRepository(_entities_flow_definition_entity_js__rspack_import_7/* .FlowDefinition */.G)).findOne({
|
|
4236
4579
|
where: {
|
|
4237
4580
|
slug: settings.slug
|
|
4238
4581
|
},
|
|
4239
4582
|
withDeleted: true
|
|
4240
4583
|
});
|
|
4241
4584
|
if (clash && clash.id !== selfId) {
|
|
4242
|
-
throw new
|
|
4585
|
+
throw new _nestjs_common__rspack_import_4.ConflictException({
|
|
4243
4586
|
message: `The URL name '${settings.slug}' is already used by another flow.`,
|
|
4244
|
-
messageKey:
|
|
4587
|
+
messageKey: _config_message_keys_js__rspack_import_14/* .FLOW_MESSAGES.SLUG_TAKEN */.wu.SLUG_TAKEN,
|
|
4245
4588
|
messageVariables: {
|
|
4246
4589
|
slug: settings.slug
|
|
4247
4590
|
}
|
|
@@ -4250,7 +4593,6 @@ class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import
|
|
|
4250
4593
|
await this.assertMayAuthor(settings, user);
|
|
4251
4594
|
}
|
|
4252
4595
|
/** The extra permissions a flow needs from whoever writes it: saving it, or test-running it as an unsaved draft. */ async assertMayAuthor(settings, user) {
|
|
4253
|
-
if (settings.runAs === 'system') await this.assertHasPermission(user, _flusys_nestjs_shared__rspack_import_0.FLOW_DEFINITION_PERMISSIONS.SYSTEM);
|
|
4254
4596
|
if (settings.nodes.some((node)=>node?.type === 'code')) await this.assertHasPermission(user, _flusys_nestjs_shared__rspack_import_0.FLOW_DEFINITION_PERMISSIONS.CODE);
|
|
4255
4597
|
}
|
|
4256
4598
|
async assertMayCreate(user) {
|
|
@@ -4258,13 +4600,13 @@ class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import
|
|
|
4258
4600
|
}
|
|
4259
4601
|
/**
|
|
4260
4602
|
* A test run needs what running the flow for real would: the author permissions for its
|
|
4261
|
-
*
|
|
4262
|
-
* real - a draft the permission to save it, a permission
|
|
4263
|
-
*/ async assertMayTest(settings, user, run) {
|
|
4603
|
+
* code nodes (a saved flow as much as a draft). A live run also needs what makes it
|
|
4604
|
+
* real - a draft the permission to save it, a permission URL its own execute permission.
|
|
4605
|
+
*/ async assertMayTest(settings, endpoint, user, run) {
|
|
4264
4606
|
await this.assertMayAuthor(settings, user);
|
|
4265
4607
|
if (run.mode !== 'live') return;
|
|
4266
4608
|
if (run.draft) await this.assertHasPermission(user, run.saved ? _flusys_nestjs_shared__rspack_import_0.FLOW_DEFINITION_PERMISSIONS.UPDATE : _flusys_nestjs_shared__rspack_import_0.FLOW_DEFINITION_PERMISSIONS.CREATE);
|
|
4267
|
-
if (
|
|
4609
|
+
if (endpoint?.authMode === 'permission') await this.permissionCache.assertPermissionLogic(user, flowPermissions(endpoint, settings.slug));
|
|
4268
4610
|
}
|
|
4269
4611
|
assertHasPermission(user, permission) {
|
|
4270
4612
|
return this.permissionCache.assertPermission(user, permission);
|
|
@@ -4274,37 +4616,171 @@ class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import
|
|
|
4274
4616
|
dto
|
|
4275
4617
|
]){
|
|
4276
4618
|
await this.assertSaveable(toFlowSettings(d), user);
|
|
4277
|
-
|
|
4278
|
-
d.
|
|
4279
|
-
d.bodyType ??= 'object';
|
|
4280
|
-
d.authMode ??= 'jwt';
|
|
4281
|
-
d.runAs ??= 'caller';
|
|
4619
|
+
d.nodes = (0,_flow_engine_flow_api_key_js__rspack_import_9/* .sealApiKeys */.ue)(d.nodes);
|
|
4620
|
+
d.version = 0;
|
|
4282
4621
|
}
|
|
4283
4622
|
}
|
|
4284
|
-
|
|
4623
|
+
/**
|
|
4624
|
+
* Checked against what the save produces: the draft of a published flow, the flow itself before its
|
|
4625
|
+
* first publish. An unpublished flow changes in place, so its callers are protected now, not at publish.
|
|
4626
|
+
*/ async beforeUpdateOperation(dto, user, _qr) {
|
|
4285
4627
|
for (const d of Array.isArray(dto) ? dto : [
|
|
4286
4628
|
dto
|
|
4287
4629
|
]){
|
|
4288
4630
|
const existing = await this.findOrFail(d.id);
|
|
4289
|
-
const
|
|
4290
|
-
...existing,
|
|
4631
|
+
const settings = toFlowSettings({
|
|
4632
|
+
...workingCopy(existing),
|
|
4291
4633
|
...stripUndefined(d)
|
|
4292
4634
|
});
|
|
4293
|
-
await this.assertSaveable(
|
|
4294
|
-
if (
|
|
4295
|
-
existing.
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
d.
|
|
4635
|
+
await this.assertSaveable(settings, user, existing.id);
|
|
4636
|
+
if (!isPublished(existing)) await this.assertCallersKept(existing, settings, {
|
|
4637
|
+
isActive: d.isActive ?? existing.isActive,
|
|
4638
|
+
version: existing.version
|
|
4639
|
+
});
|
|
4640
|
+
if (d.nodes) d.nodes = (0,_flow_engine_flow_api_key_js__rspack_import_9/* .sealApiKeys */.ue)(d.nodes);
|
|
4299
4641
|
}
|
|
4300
4642
|
}
|
|
4643
|
+
/** A published flow keeps running as published: the edits go to its draft (none when they match what is live). */ async convertSingleDtoToEntity(dto, user) {
|
|
4644
|
+
const id = dto.id;
|
|
4645
|
+
if (!id) return super.convertSingleDtoToEntity(dto, user);
|
|
4646
|
+
const existing = await this.findOrFail(id);
|
|
4647
|
+
if (!isPublished(existing)) return super.convertSingleDtoToEntity(dto, user);
|
|
4648
|
+
const draft = snapshotOf({
|
|
4649
|
+
...workingCopy(existing),
|
|
4650
|
+
...stripUndefined(dto)
|
|
4651
|
+
});
|
|
4652
|
+
existing.draft = sameSnapshot(draft, snapshotOf(existing)) ? null : draft;
|
|
4653
|
+
return existing;
|
|
4654
|
+
}
|
|
4655
|
+
/**
|
|
4656
|
+
* Makes the draft (or, before the first publish, the flow as saved) what callers run, as the next
|
|
4657
|
+
* version. It is checked like a save, plus what only going live can break: other flows calling
|
|
4658
|
+
* this one by a URL name or path it no longer has.
|
|
4659
|
+
*/ async publish(id, note, user) {
|
|
4660
|
+
const existing = await this.findOrFail(id);
|
|
4661
|
+
const published = isPublished(existing);
|
|
4662
|
+
if (published && !existing.draft) throw new _nestjs_common__rspack_import_4.BadRequestException({
|
|
4663
|
+
message: 'There are no changes to publish.',
|
|
4664
|
+
messageKey: _config_message_keys_js__rspack_import_14/* .FLOW_MESSAGES.NOTHING_TO_PUBLISH */.wu.NOTHING_TO_PUBLISH
|
|
4665
|
+
});
|
|
4666
|
+
const next = workingCopy(existing);
|
|
4667
|
+
const settings = toFlowSettings(next);
|
|
4668
|
+
await this.assertSaveable(settings, user, existing.id);
|
|
4669
|
+
await this.assertCallersKept(existing, settings, {
|
|
4670
|
+
isActive: next.isActive ?? existing.isActive,
|
|
4671
|
+
version: existing.version + 1
|
|
4672
|
+
});
|
|
4673
|
+
const qr = await this.provider.getQueryRunner();
|
|
4674
|
+
try {
|
|
4675
|
+
await qr.connect();
|
|
4676
|
+
await qr.startTransaction();
|
|
4677
|
+
const versions = qr.manager.getRepository(_entities_flow_version_entity_js__rspack_import_8/* .FlowVersion */.p);
|
|
4678
|
+
Object.assign(existing, next, {
|
|
4679
|
+
draft: null,
|
|
4680
|
+
version: existing.version + 1,
|
|
4681
|
+
updatedById: user?.id ?? null
|
|
4682
|
+
});
|
|
4683
|
+
await qr.manager.getRepository(_entities_flow_definition_entity_js__rspack_import_7/* .FlowDefinition */.G).save(existing);
|
|
4684
|
+
await versions.save(versions.create({
|
|
4685
|
+
flowId: existing.id,
|
|
4686
|
+
version: existing.version,
|
|
4687
|
+
definition: next,
|
|
4688
|
+
note: note?.trim() || null,
|
|
4689
|
+
publishedAt: new Date(),
|
|
4690
|
+
publishedById: user?.id ?? null
|
|
4691
|
+
}));
|
|
4692
|
+
await qr.commitTransaction();
|
|
4693
|
+
} catch (error) {
|
|
4694
|
+
await qr.rollbackTransaction().catch(()=>undefined);
|
|
4695
|
+
throw error;
|
|
4696
|
+
} finally{
|
|
4697
|
+
await qr.release().catch(()=>undefined);
|
|
4698
|
+
}
|
|
4699
|
+
await this.clearCaches(existing);
|
|
4700
|
+
await this.provisionPermissions([
|
|
4701
|
+
existing
|
|
4702
|
+
]);
|
|
4703
|
+
return existing;
|
|
4704
|
+
}
|
|
4705
|
+
/** Newest first, without the definitions (`getVersion` returns one in full). */ async listVersions(flowId) {
|
|
4706
|
+
await this.findOrFail(flowId);
|
|
4707
|
+
return (await this.provider.getRepository(_entities_flow_version_entity_js__rspack_import_8/* .FlowVersion */.p)).find({
|
|
4708
|
+
where: {
|
|
4709
|
+
flowId
|
|
4710
|
+
},
|
|
4711
|
+
order: {
|
|
4712
|
+
version: 'DESC'
|
|
4713
|
+
},
|
|
4714
|
+
select: {
|
|
4715
|
+
id: true,
|
|
4716
|
+
flowId: true,
|
|
4717
|
+
version: true,
|
|
4718
|
+
note: true,
|
|
4719
|
+
publishedAt: true,
|
|
4720
|
+
publishedById: true
|
|
4721
|
+
}
|
|
4722
|
+
});
|
|
4723
|
+
}
|
|
4724
|
+
async getVersion(flowId, version) {
|
|
4725
|
+
const row = await (await this.provider.getRepository(_entities_flow_version_entity_js__rspack_import_8/* .FlowVersion */.p)).findOne({
|
|
4726
|
+
where: {
|
|
4727
|
+
flowId,
|
|
4728
|
+
version
|
|
4729
|
+
}
|
|
4730
|
+
});
|
|
4731
|
+
if (!row) throw new _nestjs_common__rspack_import_4.NotFoundException({
|
|
4732
|
+
message: `Version ${version} of this flow was not found.`,
|
|
4733
|
+
messageKey: _config_message_keys_js__rspack_import_14/* .FLOW_MESSAGES.VERSION_NOT_FOUND */.wu.VERSION_NOT_FOUND,
|
|
4734
|
+
messageVariables: {
|
|
4735
|
+
version
|
|
4736
|
+
}
|
|
4737
|
+
});
|
|
4738
|
+
return row;
|
|
4739
|
+
}
|
|
4740
|
+
/**
|
|
4741
|
+
* Puts an old version back into the draft; callers keep the published flow until it is published
|
|
4742
|
+
* again. Not checked like a save (the entities it names may have changed since), but the author
|
|
4743
|
+
* still needs the permissions its code steps call for.
|
|
4744
|
+
*/ async restoreVersion(flowId, version, user) {
|
|
4745
|
+
const flow = await this.findOrFail(flowId);
|
|
4746
|
+
const snapshot = snapshotOf((await this.getVersion(flowId, version)).definition);
|
|
4747
|
+
await this.assertMayAuthor(toFlowSettings(snapshot), user);
|
|
4748
|
+
flow.draft = sameSnapshot(snapshot, snapshotOf(flow)) ? null : snapshot;
|
|
4749
|
+
return this.saveDraft(flow, user);
|
|
4750
|
+
}
|
|
4751
|
+
async discardDraft(flowId, user) {
|
|
4752
|
+
const flow = await this.findOrFail(flowId);
|
|
4753
|
+
if (!flow.draft) throw new _nestjs_common__rspack_import_4.BadRequestException({
|
|
4754
|
+
message: 'This flow has no unpublished changes.',
|
|
4755
|
+
messageKey: _config_message_keys_js__rspack_import_14/* .FLOW_MESSAGES.NO_DRAFT */.wu.NO_DRAFT
|
|
4756
|
+
});
|
|
4757
|
+
flow.draft = null;
|
|
4758
|
+
return this.saveDraft(flow, user);
|
|
4759
|
+
}
|
|
4760
|
+
async saveDraft(flow, user) {
|
|
4761
|
+
await (await this.provider.getRepository(_entities_flow_definition_entity_js__rspack_import_7/* .FlowDefinition */.G)).update(flow.id, {
|
|
4762
|
+
draft: flow.draft,
|
|
4763
|
+
updatedById: user?.id ?? null
|
|
4764
|
+
});
|
|
4765
|
+
await this.clearCaches(flow);
|
|
4766
|
+
return flow;
|
|
4767
|
+
}
|
|
4768
|
+
async clearCaches(flow) {
|
|
4769
|
+
if (!this.isCacheable) return;
|
|
4770
|
+
await Promise.all([
|
|
4771
|
+
this.clearCacheForAll(),
|
|
4772
|
+
this.clearCacheForId([
|
|
4773
|
+
flow
|
|
4774
|
+
])
|
|
4775
|
+
]);
|
|
4776
|
+
}
|
|
4301
4777
|
async beforeDeleteOperation(dto, user, _qr) {
|
|
4302
4778
|
const ids = Array.isArray(dto.id) ? dto.id : [
|
|
4303
4779
|
dto.id
|
|
4304
4780
|
];
|
|
4305
|
-
const flows = await (await this.provider.getRepository(
|
|
4781
|
+
const flows = await (await this.provider.getRepository(_entities_flow_definition_entity_js__rspack_import_7/* .FlowDefinition */.G)).find({
|
|
4306
4782
|
where: {
|
|
4307
|
-
id: (0,
|
|
4783
|
+
id: (0,typeorm__rspack_import_5.In)(ids)
|
|
4308
4784
|
},
|
|
4309
4785
|
withDeleted: true
|
|
4310
4786
|
});
|
|
@@ -4312,39 +4788,50 @@ class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import
|
|
|
4312
4788
|
if (dto.type === 'restore') return;
|
|
4313
4789
|
for (const flow of flows)await this.assertNotCalled(flow.slug, ids);
|
|
4314
4790
|
}
|
|
4315
|
-
async
|
|
4316
|
-
await this.provisionPermissions(entities);
|
|
4317
|
-
}
|
|
4318
|
-
async afterUpdateOperation(entities) {
|
|
4319
|
-
await this.provisionPermissions(entities);
|
|
4320
|
-
}
|
|
4321
|
-
async provisionPermissions(flows) {
|
|
4322
|
-
const needing = flows.filter((f)=>f.authMode === 'permission');
|
|
4323
|
-
if (!needing.length) return;
|
|
4791
|
+
/** The flow's execute permission, registered so it can be granted, when a published URL asks for it (a URL with its own rule names existing permissions). */ async provisionPermissions(flows) {
|
|
4324
4792
|
if (!this.actionRegistry) return;
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4793
|
+
const actions = new Map();
|
|
4794
|
+
for (const flow of flows){
|
|
4795
|
+
for (const endpoint of (0,_flow_engine_flow_types_js__rspack_import_11/* .flowEndpoints */.Xr)(flow)){
|
|
4796
|
+
if (endpoint.authMode !== 'permission' || endpoint.permissions) continue;
|
|
4797
|
+
const code = defaultFlowPermissionCode(flow.slug);
|
|
4798
|
+
if (!actions.has(code)) actions.set(code, endpoint.path ? `Run ${flow.name} (${endpoint.path})` : `Run ${flow.name}`);
|
|
4799
|
+
}
|
|
4800
|
+
}
|
|
4801
|
+
if (actions.size) await this.actionRegistry.registerActions([
|
|
4802
|
+
...actions
|
|
4803
|
+
].map(([code, name])=>({
|
|
4804
|
+
code,
|
|
4805
|
+
name
|
|
4328
4806
|
})));
|
|
4329
4807
|
}
|
|
4330
4808
|
}
|
|
4331
4809
|
FlowDefinitionService = _ts_decorate([
|
|
4332
|
-
(0,
|
|
4333
|
-
scope:
|
|
4810
|
+
(0,_nestjs_common__rspack_import_4.Injectable)({
|
|
4811
|
+
scope: _nestjs_common__rspack_import_4.Scope.REQUEST
|
|
4334
4812
|
}),
|
|
4335
|
-
_ts_param(0, (0,
|
|
4336
|
-
_ts_param(1, (0,
|
|
4337
|
-
_ts_param(2, (0,
|
|
4338
|
-
_ts_param(3, (0,
|
|
4339
|
-
_ts_param(4, (0,
|
|
4340
|
-
_ts_param(4, (0,
|
|
4813
|
+
_ts_param(0, (0,_nestjs_common__rspack_import_4.Inject)('CACHE_INSTANCE')),
|
|
4814
|
+
_ts_param(1, (0,_nestjs_common__rspack_import_4.Inject)(_flusys_nestjs_shared_modules__rspack_import_3.UtilsService)),
|
|
4815
|
+
_ts_param(2, (0,_nestjs_common__rspack_import_4.Inject)(_entity_builder_datasource_provider_js__rspack_import_12/* .EntityBuilderDataSourceProvider */.D)),
|
|
4816
|
+
_ts_param(3, (0,_nestjs_common__rspack_import_4.Inject)(_flusys_nestjs_shared_modules__rspack_import_3.SharedPermissionCacheService)),
|
|
4817
|
+
_ts_param(4, (0,_nestjs_common__rspack_import_4.Optional)()),
|
|
4818
|
+
_ts_param(4, (0,_nestjs_common__rspack_import_4.Inject)(_flusys_nestjs_shared__rspack_import_0.PERMISSION_ACTION_REGISTRY)),
|
|
4819
|
+
_ts_param(5, (0,_nestjs_common__rspack_import_4.Optional)()),
|
|
4820
|
+
_ts_param(5, (0,_nestjs_common__rspack_import_4.Inject)(_flusys_nestjs_shared_interfaces__rspack_import_2.NOTIFICATION_ADAPTER)),
|
|
4821
|
+
_ts_param(6, (0,_nestjs_common__rspack_import_4.Optional)()),
|
|
4822
|
+
_ts_param(6, (0,_nestjs_common__rspack_import_4.Inject)(_flusys_nestjs_shared_interfaces__rspack_import_2.EMAIL_ADAPTER)),
|
|
4823
|
+
_ts_param(7, (0,_nestjs_common__rspack_import_4.Optional)()),
|
|
4824
|
+
_ts_param(7, (0,_nestjs_common__rspack_import_4.Inject)(_flusys_nestjs_shared_interfaces__rspack_import_2.COMPANY_ACCESS_RESOLVER)),
|
|
4341
4825
|
_ts_metadata("design:type", Function),
|
|
4342
4826
|
_ts_metadata("design:paramtypes", [
|
|
4343
4827
|
typeof _flusys_nestjs_shared_classes__rspack_import_1.HybridCache === "undefined" ? Object : _flusys_nestjs_shared_classes__rspack_import_1.HybridCache,
|
|
4344
|
-
typeof
|
|
4345
|
-
typeof
|
|
4346
|
-
typeof
|
|
4347
|
-
typeof IPermissionActionRegistry === "undefined" ? Object : IPermissionActionRegistry
|
|
4828
|
+
typeof _flusys_nestjs_shared_modules__rspack_import_3.UtilsService === "undefined" ? Object : _flusys_nestjs_shared_modules__rspack_import_3.UtilsService,
|
|
4829
|
+
typeof _entity_builder_datasource_provider_js__rspack_import_12/* .EntityBuilderDataSourceProvider */.D === "undefined" ? Object : _entity_builder_datasource_provider_js__rspack_import_12/* .EntityBuilderDataSourceProvider */.D,
|
|
4830
|
+
typeof _flusys_nestjs_shared_modules__rspack_import_3.SharedPermissionCacheService === "undefined" ? Object : _flusys_nestjs_shared_modules__rspack_import_3.SharedPermissionCacheService,
|
|
4831
|
+
typeof IPermissionActionRegistry === "undefined" ? Object : IPermissionActionRegistry,
|
|
4832
|
+
typeof INotificationAdapter === "undefined" ? Object : INotificationAdapter,
|
|
4833
|
+
typeof IEmailAdapter === "undefined" ? Object : IEmailAdapter,
|
|
4834
|
+
typeof ICompanyAccessResolver === "undefined" ? Object : ICompanyAccessResolver
|
|
4348
4835
|
])
|
|
4349
4836
|
], FlowDefinitionService);
|
|
4350
4837
|
/** What the `call_flow` nodes of a flow run: a slug, and the path of the Request step they start at (null: the flow's own URL). */ function calledTargets(nodes) {
|
|
@@ -4356,6 +4843,13 @@ FlowDefinitionService = _ts_decorate([
|
|
|
4356
4843
|
};
|
|
4357
4844
|
});
|
|
4358
4845
|
}
|
|
4846
|
+
/** What a Call flow step checks about a flow: it runs only once published and switched on. */ function callableOf(flow) {
|
|
4847
|
+
return {
|
|
4848
|
+
isActive: flow.isActive && isPublished(flow),
|
|
4849
|
+
endpoints: (0,_flow_engine_flow_types_js__rspack_import_11/* .flowEndpoints */.Xr)(flow),
|
|
4850
|
+
calls: calledSlugs(flow.nodes)
|
|
4851
|
+
};
|
|
4852
|
+
}
|
|
4359
4853
|
/** Slugs the `call_flow` nodes of a flow run. */ function calledSlugs(nodes) {
|
|
4360
4854
|
return calledTargets(nodes).map((target)=>target.slug);
|
|
4361
4855
|
}
|
|
@@ -4365,10 +4859,14 @@ function stripUndefined(value) {
|
|
|
4365
4859
|
|
|
4366
4860
|
__webpack_require__.d(__webpack_exports__, {
|
|
4367
4861
|
RK: () => (toFlowSettings),
|
|
4368
|
-
Tk: () => (FlowDefinitionService)
|
|
4862
|
+
Tk: () => (FlowDefinitionService),
|
|
4863
|
+
eY: () => (snapshotOf)
|
|
4369
4864
|
}, {
|
|
4370
4865
|
Er: defaultFlowPermissionCode,
|
|
4371
|
-
|
|
4866
|
+
HF: isPublished,
|
|
4867
|
+
YW: flowNotFound,
|
|
4868
|
+
j4: flowPermissions,
|
|
4869
|
+
lw: workingCopy
|
|
4372
4870
|
});
|
|
4373
4871
|
|
|
4374
4872
|
|
|
@@ -4428,8 +4926,11 @@ class FlowExecutionService {
|
|
|
4428
4926
|
await repo.save(repo.create({
|
|
4429
4927
|
flowId: entry.flowId,
|
|
4430
4928
|
flowSlug: entry.flowSlug,
|
|
4929
|
+
flowVersion: entry.flowVersion,
|
|
4431
4930
|
status: entry.result.status,
|
|
4432
4931
|
trigger: entry.trigger,
|
|
4932
|
+
endpointNodeId: entry.endpoint?.nodeId ?? null,
|
|
4933
|
+
endpointPath: entry.endpoint?.path ?? null,
|
|
4433
4934
|
mode: entry.mode,
|
|
4434
4935
|
statusCode: entry.result.statusCode,
|
|
4435
4936
|
input: inputText.length > INPUT_LIMIT_CHARS ? {
|
|
@@ -4480,6 +4981,8 @@ class FlowExecutionService {
|
|
|
4480
4981
|
const where = {};
|
|
4481
4982
|
if (query.flowId) where.flowId = query.flowId;
|
|
4482
4983
|
if (query.status) where.status = query.status;
|
|
4984
|
+
if (query.trigger) where.trigger = query.trigger;
|
|
4985
|
+
if (query.endpointNodeId) where.endpointNodeId = query.endpointNodeId;
|
|
4483
4986
|
const [rows, total] = await repo.findAndCount({
|
|
4484
4987
|
where,
|
|
4485
4988
|
order: {
|
|
@@ -4492,8 +4995,11 @@ class FlowExecutionService {
|
|
|
4492
4995
|
id: true,
|
|
4493
4996
|
flowId: true,
|
|
4494
4997
|
flowSlug: true,
|
|
4998
|
+
flowVersion: true,
|
|
4495
4999
|
status: true,
|
|
4496
5000
|
trigger: true,
|
|
5001
|
+
endpointNodeId: true,
|
|
5002
|
+
endpointPath: true,
|
|
4497
5003
|
mode: true,
|
|
4498
5004
|
statusCode: true,
|
|
4499
5005
|
durationMs: true,
|
|
@@ -4538,7 +5044,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
4538
5044
|
|
|
4539
5045
|
|
|
4540
5046
|
},
|
|
4541
|
-
|
|
5047
|
+
3908(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
4542
5048
|
|
|
4543
5049
|
// EXPORTS
|
|
4544
5050
|
__webpack_require__.d(__webpack_exports__, {
|
|
@@ -4548,10 +5054,14 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
4548
5054
|
|
|
4549
5055
|
// EXTERNAL MODULE: external "@flusys/nestjs-shared/classes"
|
|
4550
5056
|
var classes_ = __webpack_require__(6937);
|
|
4551
|
-
|
|
4552
|
-
|
|
5057
|
+
;// CONCATENATED MODULE: external "@flusys/nestjs-shared/exceptions"
|
|
5058
|
+
|
|
5059
|
+
// EXTERNAL MODULE: external "@flusys/nestjs-shared/interfaces"
|
|
5060
|
+
var interfaces_ = __webpack_require__(5103);
|
|
4553
5061
|
// EXTERNAL MODULE: external "@flusys/nestjs-shared/modules"
|
|
4554
5062
|
var modules_ = __webpack_require__(1236);
|
|
5063
|
+
// EXTERNAL MODULE: external "@flusys/nestjs-shared/utils"
|
|
5064
|
+
var utils_ = __webpack_require__(9216);
|
|
4555
5065
|
// EXTERNAL MODULE: external "@nestjs/common"
|
|
4556
5066
|
var common_ = __webpack_require__(6157);
|
|
4557
5067
|
// EXTERNAL MODULE: external "@nestjs/core"
|
|
@@ -4789,8 +5299,8 @@ const BLOCKED_REQUEST_HEADERS = new Set([
|
|
|
4789
5299
|
});
|
|
4790
5300
|
}
|
|
4791
5301
|
|
|
4792
|
-
// EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/rule-engine/index.ts +
|
|
4793
|
-
var rule_engine = __webpack_require__(
|
|
5302
|
+
// EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/rule-engine/index.ts + 1 modules
|
|
5303
|
+
var rule_engine = __webpack_require__(8429);
|
|
4794
5304
|
// EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/services/entity-builder-config.service.ts
|
|
4795
5305
|
var entity_builder_config_service = __webpack_require__(4281);
|
|
4796
5306
|
// EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/services/entity-builder-datasource.provider.ts
|
|
@@ -4843,6 +5353,8 @@ function _ts_param(paramIndex, decorator) {
|
|
|
4843
5353
|
|
|
4844
5354
|
|
|
4845
5355
|
|
|
5356
|
+
|
|
5357
|
+
|
|
4846
5358
|
|
|
4847
5359
|
|
|
4848
5360
|
|
|
@@ -4853,27 +5365,32 @@ const publishFlowEvent = (eventName, payload, user)=>(0,classes_.publishDomainEv
|
|
|
4853
5365
|
metadata: payload,
|
|
4854
5366
|
user
|
|
4855
5367
|
});
|
|
4856
|
-
/** The run's time budget, whatever a
|
|
5368
|
+
/** The run's time budget, whatever a Request step asks for. */ const flowTimeout = (timeoutMs)=>typeof timeoutMs === 'number' && Number.isFinite(timeoutMs) ? Math.min(Math.max(timeoutMs, flow_types/* .FLOW_LIMITS.MIN_TIMEOUT_MS */.Or.MIN_TIMEOUT_MS), flow_types/* .FLOW_LIMITS.MAX_TIMEOUT_MS */.Or.MAX_TIMEOUT_MS) : flow_types/* .FLOW_LIMITS.DEFAULT_TIMEOUT_MS */.Or.DEFAULT_TIMEOUT_MS;
|
|
4857
5369
|
class FlowExecutorService {
|
|
4858
5370
|
provider;
|
|
4859
5371
|
ruleEngine;
|
|
4860
5372
|
moduleRef;
|
|
4861
5373
|
permissionCache;
|
|
4862
5374
|
config;
|
|
5375
|
+
companyAccess;
|
|
5376
|
+
notifications;
|
|
5377
|
+
email;
|
|
5378
|
+
branchHierarchy;
|
|
4863
5379
|
logger = new common_.Logger(FlowExecutorService.name);
|
|
4864
|
-
constructor(provider, ruleEngine, moduleRef, permissionCache, config){
|
|
5380
|
+
constructor(provider, ruleEngine, moduleRef, permissionCache, config, companyAccess, notifications, email, branchHierarchy){
|
|
4865
5381
|
this.provider = provider;
|
|
4866
5382
|
this.ruleEngine = ruleEngine;
|
|
4867
5383
|
this.moduleRef = moduleRef;
|
|
4868
5384
|
this.permissionCache = permissionCache;
|
|
4869
5385
|
this.config = config;
|
|
5386
|
+
this.companyAccess = companyAccess;
|
|
5387
|
+
this.notifications = notifications;
|
|
5388
|
+
this.email = email;
|
|
5389
|
+
this.branchHierarchy = branchHierarchy;
|
|
4870
5390
|
}
|
|
4871
|
-
async run(
|
|
5391
|
+
async run(flow, options) {
|
|
4872
5392
|
const startedAt = Date.now();
|
|
4873
|
-
const
|
|
4874
|
-
...definition,
|
|
4875
|
-
timeoutMs: flowTimeout(definition.timeoutMs)
|
|
4876
|
-
};
|
|
5393
|
+
const start = (0,flow_types/* .startEndpoint */.IE)(flow, options.startAt);
|
|
4877
5394
|
const state = {
|
|
4878
5395
|
startAt: options.startAt,
|
|
4879
5396
|
input: options.input,
|
|
@@ -4881,14 +5398,14 @@ class FlowExecutorService {
|
|
|
4881
5398
|
context: {},
|
|
4882
5399
|
request: options.request,
|
|
4883
5400
|
user: options.user,
|
|
5401
|
+
authorization: options.authorization,
|
|
4884
5402
|
permissions: this.ruleEngine.createPermissionResolver(options.user),
|
|
4885
5403
|
mode: options.mode,
|
|
4886
|
-
runAs: flow.runAs,
|
|
4887
|
-
systemAuthorized: flow.runAs === 'system' && options.systemAuthorized === true,
|
|
4888
5404
|
steps: 0,
|
|
4889
5405
|
httpCalls: 0,
|
|
5406
|
+
messages: 0,
|
|
4890
5407
|
writes: 0,
|
|
4891
|
-
deadline: startedAt +
|
|
5408
|
+
deadline: startedAt + flowTimeout(start?.timeoutMs),
|
|
4892
5409
|
callStack: [
|
|
4893
5410
|
flow.slug
|
|
4894
5411
|
],
|
|
@@ -4896,15 +5413,7 @@ class FlowExecutorService {
|
|
|
4896
5413
|
trace: []
|
|
4897
5414
|
};
|
|
4898
5415
|
try {
|
|
4899
|
-
|
|
4900
|
-
throw new flow_errors/* .FlowHttpError */.hk(403, 'This flow is not allowed to run.', undefined, {
|
|
4901
|
-
messageKey: message_keys/* .FLOW_ERROR_MESSAGES.RUN_AS_NOT_ALLOWED */.zr.RUN_AS_NOT_ALLOWED,
|
|
4902
|
-
messageVariables: {
|
|
4903
|
-
runAs: String(flow.runAs)
|
|
4904
|
-
}
|
|
4905
|
-
});
|
|
4906
|
-
}
|
|
4907
|
-
await this.execute(flow, state, this.createEnv());
|
|
5416
|
+
await this.execute(flow, start?.isTransactional === true, state, this.createEnv());
|
|
4908
5417
|
return {
|
|
4909
5418
|
...(0,flow_engine/* .successResult */.JK)(state, startedAt),
|
|
4910
5419
|
...state.savedUpTo ? {
|
|
@@ -4934,10 +5443,10 @@ class FlowExecutorService {
|
|
|
4934
5443
|
}
|
|
4935
5444
|
}
|
|
4936
5445
|
/**
|
|
4937
|
-
* Walks `flow`. A flow called from inside a transaction joins it; otherwise a
|
|
4938
|
-
*
|
|
4939
|
-
*/ async execute(flow, state, env) {
|
|
4940
|
-
if (state.qr || !(
|
|
5446
|
+
* Walks `flow`. A flow called from inside a transaction joins it; otherwise a run whose Request step
|
|
5447
|
+
* is transactional (or any test run) gets its own, and its held-back events are published after the commit.
|
|
5448
|
+
*/ async execute(flow, transactional, state, env) {
|
|
5449
|
+
if (state.qr || !(transactional || state.mode === 'dry_run')) {
|
|
4941
5450
|
await new flow_engine/* .FlowEngine */.$I(flow, env).walk(state);
|
|
4942
5451
|
return;
|
|
4943
5452
|
}
|
|
@@ -5016,7 +5525,6 @@ class FlowExecutorService {
|
|
|
5016
5525
|
max: flow_types/* .FLOW_LIMITS.MAX_CALL_DEPTH */.Or.MAX_CALL_DEPTH
|
|
5017
5526
|
});
|
|
5018
5527
|
const flow = await this.findCallable(slug, parent.qr);
|
|
5019
|
-
await this.assertMayCall(flow, parent, env);
|
|
5020
5528
|
const settings = (0,flow_definition_service/* .toFlowSettings */.RK)(flow);
|
|
5021
5529
|
const start = (0,flow_types/* .findEndpoint */.vS)(settings, endpoint);
|
|
5022
5530
|
if (!start) {
|
|
@@ -5025,6 +5533,7 @@ class FlowExecutorService {
|
|
|
5025
5533
|
endpoint: endpoint ?? ''
|
|
5026
5534
|
}, `Flow '${slug}' has no URL '${endpoint ?? ''}'.`);
|
|
5027
5535
|
}
|
|
5536
|
+
await this.assertMayCall(flow, start, parent, env);
|
|
5028
5537
|
const checked = (0,flow_input_validator/* .validateFlowInput */.v)(start.inputSchema, input, start.bodyType);
|
|
5029
5538
|
if (checked.errors.length) {
|
|
5030
5539
|
throw new flow_errors/* .FlowHttpError */.hk(400, 'Validation failed', checked.errors, {
|
|
@@ -5041,15 +5550,14 @@ class FlowExecutorService {
|
|
|
5041
5550
|
context: {},
|
|
5042
5551
|
request: parent.request,
|
|
5043
5552
|
user: parent.user,
|
|
5553
|
+
authorization: parent.authorization,
|
|
5044
5554
|
permissions: parent.permissions,
|
|
5045
5555
|
mode: parent.mode,
|
|
5046
|
-
runAs: flow.authMode === 'internal' ? parent.runAs : settings.runAs,
|
|
5047
|
-
// A function inherits the caller's grant; any other called flow is a saved flow whose own run-as was checked when it was saved.
|
|
5048
|
-
systemAuthorized: flow.authMode === 'internal' ? parent.systemAuthorized === true : settings.runAs === 'system',
|
|
5049
5556
|
steps: parent.steps,
|
|
5050
5557
|
httpCalls: parent.httpCalls,
|
|
5558
|
+
messages: parent.messages,
|
|
5051
5559
|
writes: parent.writes,
|
|
5052
|
-
deadline: Math.min(parent.deadline, Date.now() + flowTimeout(
|
|
5560
|
+
deadline: Math.min(parent.deadline, Date.now() + flowTimeout(start.timeoutMs)),
|
|
5053
5561
|
qr: parent.qr,
|
|
5054
5562
|
callStack: [
|
|
5055
5563
|
...parent.callStack,
|
|
@@ -5064,13 +5572,14 @@ class FlowExecutorService {
|
|
|
5064
5572
|
if (child.pendingEvents === parent.pendingEvents) parent.pendingEvents.length = queued;
|
|
5065
5573
|
};
|
|
5066
5574
|
try {
|
|
5067
|
-
await this.execute(settings, child, env);
|
|
5575
|
+
await this.execute(settings, start.isTransactional, child, env);
|
|
5068
5576
|
} catch (error) {
|
|
5069
5577
|
dropQueued();
|
|
5070
5578
|
throw calledFlowFailure(flow, error);
|
|
5071
5579
|
} finally{
|
|
5072
5580
|
parent.steps = child.steps;
|
|
5073
5581
|
parent.httpCalls = child.httpCalls;
|
|
5582
|
+
parent.messages = child.messages;
|
|
5074
5583
|
parent.writes = child.writes;
|
|
5075
5584
|
}
|
|
5076
5585
|
if (child.response) {
|
|
@@ -5089,7 +5598,8 @@ class FlowExecutorService {
|
|
|
5089
5598
|
where: {
|
|
5090
5599
|
slug,
|
|
5091
5600
|
isActive: true,
|
|
5092
|
-
deletedAt: (0,external_typeorm_.IsNull)()
|
|
5601
|
+
deletedAt: (0,external_typeorm_.IsNull)(),
|
|
5602
|
+
version: (0,external_typeorm_.MoreThan)(0)
|
|
5093
5603
|
}
|
|
5094
5604
|
});
|
|
5095
5605
|
if (!flow) throw new flow_errors/* .FlowKeyedError */.Hp(message_keys/* .FLOW_ERROR_MESSAGES.CALLED_FLOW_NOT_FOUND */.zr.CALLED_FLOW_NOT_FOUND, {
|
|
@@ -5098,21 +5608,23 @@ class FlowExecutorService {
|
|
|
5098
5608
|
return flow;
|
|
5099
5609
|
}
|
|
5100
5610
|
/**
|
|
5101
|
-
*
|
|
5102
|
-
*
|
|
5103
|
-
*
|
|
5104
|
-
*/ async assertMayCall(flow, parent, env) {
|
|
5105
|
-
|
|
5106
|
-
if (
|
|
5611
|
+
* The called URL's own access, checked against the run's user: any flow may call a function or a
|
|
5612
|
+
* public URL; a signed-in one needs a user, a permission one the user holding it. An API-key URL
|
|
5613
|
+
* is never called from a flow, which has no key to send.
|
|
5614
|
+
*/ async assertMayCall(flow, endpoint, parent, env) {
|
|
5615
|
+
const mode = endpoint.authMode;
|
|
5616
|
+
if (mode === 'public' || mode === 'internal') return;
|
|
5617
|
+
if (mode === 'api_key' || !parent.user) {
|
|
5107
5618
|
throw new flow_errors/* .FlowKeyedError */.Hp(message_keys/* .FLOW_ERROR_MESSAGES.CALLED_FLOW_NOT_ALLOWED */.zr.CALLED_FLOW_NOT_ALLOWED, {
|
|
5108
5619
|
flow: flow.slug,
|
|
5109
|
-
authMode:
|
|
5110
|
-
}, `Flow '${flow.slug}' (${
|
|
5620
|
+
authMode: mode
|
|
5621
|
+
}, `Flow '${flow.slug}' (${mode}) cannot be called by this caller.`);
|
|
5111
5622
|
}
|
|
5112
|
-
if (
|
|
5623
|
+
if (mode === 'permission') await env.assertPermissions((0,flow_definition_service/* .flowPermissions */.j4)(endpoint, flow.slug), parent.user);
|
|
5113
5624
|
}
|
|
5114
5625
|
createEnv() {
|
|
5115
5626
|
const entityServices = new Map();
|
|
5627
|
+
/** One lookup per user for the whole run, however many steps ask. */ const access = new Map();
|
|
5116
5628
|
let permissions;
|
|
5117
5629
|
const env = {
|
|
5118
5630
|
ruleEngine: this.ruleEngine,
|
|
@@ -5135,29 +5647,48 @@ class FlowExecutorService {
|
|
|
5135
5647
|
atomic: (state, work)=>this.atomic(state, work),
|
|
5136
5648
|
commit: (state)=>this.commitProgress(state),
|
|
5137
5649
|
http: flowHttpRequest,
|
|
5650
|
+
notifications: this.notifications,
|
|
5651
|
+
email: this.email,
|
|
5652
|
+
...this.companyAccess ? {
|
|
5653
|
+
companyMembers: (companyId, branchIds)=>this.companyAccess.getCompanyMembers(companyId, branchIds)
|
|
5654
|
+
} : {},
|
|
5655
|
+
...this.branchHierarchy ? {
|
|
5656
|
+
branchTree: (branchIds)=>this.branchHierarchy.getDescendantIds(branchIds, {
|
|
5657
|
+
includeSelf: true
|
|
5658
|
+
})
|
|
5659
|
+
} : {},
|
|
5660
|
+
companyAccess: (userId)=>{
|
|
5661
|
+
if (!access.has(userId)) access.set(userId, this.companyAccess ? this.companyAccess.getUserAccess(userId) : Promise.resolve({
|
|
5662
|
+
companies: [],
|
|
5663
|
+
branches: []
|
|
5664
|
+
}));
|
|
5665
|
+
return access.get(userId);
|
|
5666
|
+
},
|
|
5138
5667
|
publish: (eventName, payload, user)=>publishFlowEvent(eventName, payload, user),
|
|
5139
|
-
|
|
5668
|
+
assertPermissions: async (logic, user)=>{
|
|
5140
5669
|
if (!user) throw new common_.UnauthorizedException({
|
|
5141
5670
|
message: 'Authentication required',
|
|
5142
5671
|
messageKey: constants_.ERROR_MESSAGES.UNAUTHORIZED
|
|
5143
5672
|
});
|
|
5144
|
-
if (!this.permissionCache.isCacheConfigured()) throw new
|
|
5673
|
+
if (!this.permissionCache.isCacheConfigured()) throw new __rspack_external__flusys_nestjs_shared_exceptions_3edf22e9.PermissionSystemUnavailableException();
|
|
5145
5674
|
permissions ??= this.permissionCache.getPermissions({
|
|
5146
5675
|
userId: user.id,
|
|
5147
5676
|
companyId: user.companyId,
|
|
5148
5677
|
branchId: user.branchId
|
|
5149
5678
|
});
|
|
5150
|
-
const
|
|
5151
|
-
if (!
|
|
5152
|
-
code
|
|
5153
|
-
], 'AND');
|
|
5679
|
+
const result = (0,utils_.evaluatePermissionLogic)(logic, await permissions);
|
|
5680
|
+
if (!result.passed) throw new __rspack_external__flusys_nestjs_shared_exceptions_3edf22e9.InsufficientPermissionsException(result.missingPermissions, result.operator);
|
|
5154
5681
|
}
|
|
5155
5682
|
};
|
|
5156
5683
|
return env;
|
|
5157
5684
|
}
|
|
5158
|
-
/** After commit, so listeners see committed data. A failing publish never turns a completed run into an error. */ async publishPendingEvents(events, user) {
|
|
5685
|
+
/** After commit, so listeners see committed data and messages go out only for what was saved. A failing publish or send never turns a completed run into an error. */ async publishPendingEvents(events, user) {
|
|
5159
5686
|
for (const event of events){
|
|
5160
5687
|
try {
|
|
5688
|
+
if ('delivery' in event) {
|
|
5689
|
+
await event.send();
|
|
5690
|
+
continue;
|
|
5691
|
+
}
|
|
5161
5692
|
if ('eventName' in event) {
|
|
5162
5693
|
await publishFlowEvent(event.eventName, event.payload, user);
|
|
5163
5694
|
continue;
|
|
@@ -5176,6 +5707,10 @@ class FlowExecutorService {
|
|
|
5176
5707
|
user
|
|
5177
5708
|
});
|
|
5178
5709
|
} catch (error) {
|
|
5710
|
+
if ('delivery' in event) {
|
|
5711
|
+
this.logger.error(`Could not send the message of "${event.delivery}" after the commit: ${error.message}`);
|
|
5712
|
+
continue;
|
|
5713
|
+
}
|
|
5179
5714
|
const name = 'eventName' in event ? event.eventName : `${event.entityCode}.${event.action}`;
|
|
5180
5715
|
this.logger.error(`Could not publish ${name}: ${error.message}`);
|
|
5181
5716
|
}
|
|
@@ -5189,13 +5724,25 @@ FlowExecutorService = _ts_decorate([
|
|
|
5189
5724
|
_ts_param(2, (0,common_.Inject)(core_.ModuleRef)),
|
|
5190
5725
|
_ts_param(3, (0,common_.Inject)(modules_.SharedPermissionCacheService)),
|
|
5191
5726
|
_ts_param(4, (0,common_.Inject)(entity_builder_config_service/* .EntityBuilderConfigService */.E)),
|
|
5727
|
+
_ts_param(5, (0,common_.Optional)()),
|
|
5728
|
+
_ts_param(5, (0,common_.Inject)(interfaces_.COMPANY_ACCESS_RESOLVER)),
|
|
5729
|
+
_ts_param(6, (0,common_.Optional)()),
|
|
5730
|
+
_ts_param(6, (0,common_.Inject)(interfaces_.NOTIFICATION_ADAPTER)),
|
|
5731
|
+
_ts_param(7, (0,common_.Optional)()),
|
|
5732
|
+
_ts_param(7, (0,common_.Inject)(interfaces_.EMAIL_ADAPTER)),
|
|
5733
|
+
_ts_param(8, (0,common_.Optional)()),
|
|
5734
|
+
_ts_param(8, (0,common_.Inject)(interfaces_.BRANCH_HIERARCHY_RESOLVER)),
|
|
5192
5735
|
_ts_metadata("design:type", Function),
|
|
5193
5736
|
_ts_metadata("design:paramtypes", [
|
|
5194
5737
|
typeof entity_builder_datasource_provider/* .EntityBuilderDataSourceProvider */.D === "undefined" ? Object : entity_builder_datasource_provider/* .EntityBuilderDataSourceProvider */.D,
|
|
5195
5738
|
typeof rule_engine/* .RuleEngineService */.iI === "undefined" ? Object : rule_engine/* .RuleEngineService */.iI,
|
|
5196
5739
|
typeof core_.ModuleRef === "undefined" ? Object : core_.ModuleRef,
|
|
5197
5740
|
typeof modules_.SharedPermissionCacheService === "undefined" ? Object : modules_.SharedPermissionCacheService,
|
|
5198
|
-
typeof entity_builder_config_service/* .EntityBuilderConfigService */.E === "undefined" ? Object : entity_builder_config_service/* .EntityBuilderConfigService */.E
|
|
5741
|
+
typeof entity_builder_config_service/* .EntityBuilderConfigService */.E === "undefined" ? Object : entity_builder_config_service/* .EntityBuilderConfigService */.E,
|
|
5742
|
+
typeof ICompanyAccessResolver === "undefined" ? Object : ICompanyAccessResolver,
|
|
5743
|
+
typeof INotificationAdapter === "undefined" ? Object : INotificationAdapter,
|
|
5744
|
+
typeof IEmailAdapter === "undefined" ? Object : IEmailAdapter,
|
|
5745
|
+
typeof IBranchHierarchyResolver === "undefined" ? Object : IBranchHierarchyResolver
|
|
5199
5746
|
])
|
|
5200
5747
|
], FlowExecutorService);
|
|
5201
5748
|
/** A rejection or a limit inside the called flow is passed on as it is; anything else fails the calling node with the reason. */ function calledFlowFailure(flow, error) {
|
|
@@ -5238,7 +5785,7 @@ FlowExecutorService = _ts_decorate([
|
|
|
5238
5785
|
/* import */ var _entity_builder_datasource_provider_js__rspack_import_5 = __webpack_require__(424);
|
|
5239
5786
|
/* import */ var _flow_definition_service_js__rspack_import_6 = __webpack_require__(5229);
|
|
5240
5787
|
/* import */ var _flow_execution_service_js__rspack_import_7 = __webpack_require__(7810);
|
|
5241
|
-
/* import */ var _flow_executor_service_js__rspack_import_8 = __webpack_require__(
|
|
5788
|
+
/* import */ var _flow_executor_service_js__rspack_import_8 = __webpack_require__(3908);
|
|
5242
5789
|
function _ts_decorate(decorators, target, key, desc) {
|
|
5243
5790
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
5244
5791
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -5308,6 +5855,11 @@ const MAX_QUERY_VALUE_LENGTH = 2000;
|
|
|
5308
5855
|
receivedAt: new Date().toISOString()
|
|
5309
5856
|
};
|
|
5310
5857
|
}
|
|
5858
|
+
/** The caller's own `Authorization` header, kept for Request steps that forward it: only for a signed-in (verified) caller. */ function callerAuthorization(caller, user) {
|
|
5859
|
+
if (!user) return undefined;
|
|
5860
|
+
const value = Object.entries(caller.headers).find(([key])=>key.toLowerCase() === 'authorization')?.[1];
|
|
5861
|
+
return typeof value === 'string' && value ? value : undefined;
|
|
5862
|
+
}
|
|
5311
5863
|
/** A test run's request: the designer's own, with the headers / query / IP the author chose to simulate on top. */ function simulatedCaller(caller, simulated) {
|
|
5312
5864
|
if (!simulated) return caller;
|
|
5313
5865
|
const headers = {
|
|
@@ -5347,13 +5899,13 @@ class FlowRuntimeService {
|
|
|
5347
5899
|
this.executions = executions;
|
|
5348
5900
|
this.definitions = definitions;
|
|
5349
5901
|
}
|
|
5350
|
-
/** A
|
|
5902
|
+
/** A flow never published is not live yet: it looks the same as an unknown one. */ async findActive(slug) {
|
|
5351
5903
|
return (await this.provider.getRepository(_entities_flow_definition_entity_js__rspack_import_2/* .FlowDefinition */.G)).findOne({
|
|
5352
5904
|
where: {
|
|
5353
5905
|
slug,
|
|
5354
5906
|
isActive: true,
|
|
5355
5907
|
deletedAt: (0,typeorm__rspack_import_1.IsNull)(),
|
|
5356
|
-
|
|
5908
|
+
version: (0,typeorm__rspack_import_1.MoreThan)(0)
|
|
5357
5909
|
}
|
|
5358
5910
|
});
|
|
5359
5911
|
}
|
|
@@ -5362,25 +5914,23 @@ class FlowRuntimeService {
|
|
|
5362
5914
|
const checked = (0,_flow_engine_flow_input_validator_js__rspack_import_3/* .validateFlowInput */.v)(endpoint.inputSchema, body, endpoint.bodyType);
|
|
5363
5915
|
if (checked.errors.length) {
|
|
5364
5916
|
const result = inputRejected(checked.errors);
|
|
5365
|
-
await this.logWebhook(flow, body, result, startedAt, user, caller);
|
|
5917
|
+
await this.logWebhook(flow, endpoint, body, result, startedAt, user, caller);
|
|
5366
5918
|
return result;
|
|
5367
5919
|
}
|
|
5368
|
-
// A saved flow: saving it as `runAs: system` needed the system permission.
|
|
5369
5920
|
const result = await this.executor.run((0,_flow_definition_service_js__rspack_import_6/* .toFlowSettings */.RK)(flow), {
|
|
5370
5921
|
mode: 'live',
|
|
5371
5922
|
user,
|
|
5372
5923
|
input: checked.values,
|
|
5373
5924
|
startAt: endpoint.nodeId,
|
|
5374
5925
|
request: requestInfo(caller),
|
|
5375
|
-
|
|
5376
|
-
|
|
5926
|
+
authorization: callerAuthorization(caller, user),
|
|
5927
|
+
exposeDetails: false
|
|
5377
5928
|
});
|
|
5378
|
-
await this.logWebhook(flow, checked.values, result, startedAt, user, caller);
|
|
5929
|
+
await this.logWebhook(flow, endpoint, checked.values, result, startedAt, user, caller);
|
|
5379
5930
|
return result;
|
|
5380
5931
|
}
|
|
5381
5932
|
/** The designer's "Test run": a saved flow or an unsaved draft. */ async testRun(dto, user, caller) {
|
|
5382
5933
|
let settings;
|
|
5383
|
-
let permissionCode;
|
|
5384
5934
|
let flow = null;
|
|
5385
5935
|
if (dto.flowId) {
|
|
5386
5936
|
flow = await this.definitions.findOrFail(dto.flowId);
|
|
@@ -5388,10 +5938,8 @@ class FlowRuntimeService {
|
|
|
5388
5938
|
if (dto.definition) {
|
|
5389
5939
|
// The designer's current draft, even for a saved flow: `flow` above is kept only to attribute the run.
|
|
5390
5940
|
settings = (0,_flow_definition_service_js__rspack_import_6/* .toFlowSettings */.RK)(dto.definition);
|
|
5391
|
-
permissionCode = dto.definition.permissionCode;
|
|
5392
5941
|
} else if (flow) {
|
|
5393
5942
|
settings = (0,_flow_definition_service_js__rspack_import_6/* .toFlowSettings */.RK)(flow);
|
|
5394
|
-
permissionCode = flow.permissionCode;
|
|
5395
5943
|
} else {
|
|
5396
5944
|
throw new _nestjs_common__rspack_import_0.BadRequestException({
|
|
5397
5945
|
message: 'Send a flowId or a definition to test.',
|
|
@@ -5399,15 +5947,22 @@ class FlowRuntimeService {
|
|
|
5399
5947
|
});
|
|
5400
5948
|
}
|
|
5401
5949
|
const mode = dto.mode ?? 'dry_run';
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
permissionCode
|
|
5406
|
-
}, user, {
|
|
5950
|
+
const endpoint = (0,_flow_engine_flow_types_js__rspack_import_4/* .findEndpoint */.vS)(settings, dto.endpoint);
|
|
5951
|
+
// Checked before anything runs.
|
|
5952
|
+
await this.definitions.assertMayTest(settings, endpoint, user, {
|
|
5407
5953
|
mode,
|
|
5408
5954
|
draft: !!dto.definition,
|
|
5409
5955
|
saved: !!flow
|
|
5410
5956
|
});
|
|
5957
|
+
if (!endpoint) {
|
|
5958
|
+
throw new _nestjs_common__rspack_import_0.BadRequestException({
|
|
5959
|
+
message: `This flow has no URL '${dto.endpoint ?? ''}'.`,
|
|
5960
|
+
messageKey: _config_message_keys_js__rspack_import_9/* .FLOW_MESSAGES.ENDPOINT_NOT_FOUND */.wu.ENDPOINT_NOT_FOUND,
|
|
5961
|
+
messageVariables: {
|
|
5962
|
+
endpoint: dto.endpoint ?? ''
|
|
5963
|
+
}
|
|
5964
|
+
});
|
|
5965
|
+
}
|
|
5411
5966
|
const validation = await this.definitions.validate(settings);
|
|
5412
5967
|
if (validation.errors.length) {
|
|
5413
5968
|
throw new _nestjs_common__rspack_import_0.BadRequestException({
|
|
@@ -5419,16 +5974,6 @@ class FlowRuntimeService {
|
|
|
5419
5974
|
}))
|
|
5420
5975
|
});
|
|
5421
5976
|
}
|
|
5422
|
-
const endpoint = (0,_flow_engine_flow_types_js__rspack_import_4/* .findEndpoint */.vS)(settings, dto.endpoint);
|
|
5423
|
-
if (!endpoint) {
|
|
5424
|
-
throw new _nestjs_common__rspack_import_0.BadRequestException({
|
|
5425
|
-
message: `This flow has no URL '${dto.endpoint ?? ''}'.`,
|
|
5426
|
-
messageKey: _config_message_keys_js__rspack_import_9/* .FLOW_MESSAGES.ENDPOINT_NOT_FOUND */.wu.ENDPOINT_NOT_FOUND,
|
|
5427
|
-
messageVariables: {
|
|
5428
|
-
endpoint: dto.endpoint ?? ''
|
|
5429
|
-
}
|
|
5430
|
-
});
|
|
5431
|
-
}
|
|
5432
5977
|
const startedAt = new Date();
|
|
5433
5978
|
const simulated = simulatedCaller(caller, dto.request);
|
|
5434
5979
|
const body = dto.input ?? (endpoint.bodyType === 'list' ? [] : {});
|
|
@@ -5439,13 +5984,15 @@ class FlowRuntimeService {
|
|
|
5439
5984
|
input: checked.values,
|
|
5440
5985
|
startAt: endpoint.nodeId,
|
|
5441
5986
|
request: requestInfo(simulated),
|
|
5442
|
-
|
|
5443
|
-
|
|
5987
|
+
authorization: callerAuthorization(caller, user),
|
|
5988
|
+
exposeDetails: true
|
|
5444
5989
|
});
|
|
5445
5990
|
await this.executions.record({
|
|
5446
5991
|
flowId: flow?.id ?? null,
|
|
5447
5992
|
flowSlug: settings.slug,
|
|
5993
|
+
flowVersion: dto.definition ? null : flow?.version ?? null,
|
|
5448
5994
|
trigger: 'test',
|
|
5995
|
+
endpoint,
|
|
5449
5996
|
mode,
|
|
5450
5997
|
input: body,
|
|
5451
5998
|
result,
|
|
@@ -5459,11 +6006,13 @@ class FlowRuntimeService {
|
|
|
5459
6006
|
warnings: validation.warnings
|
|
5460
6007
|
};
|
|
5461
6008
|
}
|
|
5462
|
-
async logWebhook(flow, input, result, startedAt, user, caller) {
|
|
6009
|
+
async logWebhook(flow, endpoint, input, result, startedAt, user, caller) {
|
|
5463
6010
|
await this.executions.record({
|
|
5464
6011
|
flowId: flow.id,
|
|
5465
6012
|
flowSlug: flow.slug,
|
|
6013
|
+
flowVersion: flow.version,
|
|
5466
6014
|
trigger: 'webhook',
|
|
6015
|
+
endpoint,
|
|
5467
6016
|
mode: 'live',
|
|
5468
6017
|
input,
|
|
5469
6018
|
result,
|
|
@@ -5865,6 +6414,7 @@ const FILTER_COMPARISON_SQL = {
|
|
|
5865
6414
|
/** Soft-deletes the record, or deletes it for good when the entity has soft delete turned off. */ async delete(id, user, options = {}) {
|
|
5866
6415
|
this.ensureActive();
|
|
5867
6416
|
const repository = await this.ensureRepository();
|
|
6417
|
+
const soft = this.definition.isSoftDeleteEnabled;
|
|
5868
6418
|
await this.withTransaction(options, async (queryRunner)=>{
|
|
5869
6419
|
const existing = await queryRunner.manager.findOne(repository.target, {
|
|
5870
6420
|
where: {
|
|
@@ -5872,7 +6422,6 @@ const FILTER_COMPARISON_SQL = {
|
|
|
5872
6422
|
}
|
|
5873
6423
|
});
|
|
5874
6424
|
if (!existing) throw this.notFound(id);
|
|
5875
|
-
const soft = this.definition.isSoftDeleteEnabled;
|
|
5876
6425
|
if (soft) {
|
|
5877
6426
|
await queryRunner.manager.softDelete(repository.target, [
|
|
5878
6427
|
id
|
|
@@ -5898,6 +6447,7 @@ const FILTER_COMPARISON_SQL = {
|
|
|
5898
6447
|
]
|
|
5899
6448
|
};
|
|
5900
6449
|
}, user);
|
|
6450
|
+
return soft ? 'deleted' : 'purged';
|
|
5901
6451
|
}
|
|
5902
6452
|
async findById(id, options = {}) {
|
|
5903
6453
|
const repository = await this.repositoryFor(options.queryRunner);
|
|
@@ -6100,181 +6650,6 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
6100
6650
|
});
|
|
6101
6651
|
|
|
6102
6652
|
|
|
6103
|
-
},
|
|
6104
|
-
5313(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
6105
|
-
/* import */ var node_crypto__rspack_import_0 = __webpack_require__(2561);
|
|
6106
|
-
/* import */ var typeorm__rspack_import_1 = __webpack_require__(7158);
|
|
6107
|
-
/* import */ var _enums_field_type_enum_js__rspack_import_2 = __webpack_require__(9614);
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
/** Columns every dynamic table may carry (the `Identity` contract). Everything else is a designed field. */ const SYSTEM_COLUMN_NAMES = [
|
|
6112
|
-
'id',
|
|
6113
|
-
'created_at',
|
|
6114
|
-
'updated_at',
|
|
6115
|
-
'deleted_at',
|
|
6116
|
-
'created_by_id',
|
|
6117
|
-
'updated_by_id',
|
|
6118
|
-
'deleted_by_id'
|
|
6119
|
-
];
|
|
6120
|
-
/** Field types stored as unbounded text or JSON: an index or unique constraint on them fails (MySQL) or breaks on large values (PostgreSQL). */ const NON_INDEXABLE_FIELD_TYPES = [
|
|
6121
|
-
_enums_field_type_enum_js__rspack_import_2/* .FieldType.LONG_TEXT */.P.LONG_TEXT,
|
|
6122
|
-
_enums_field_type_enum_js__rspack_import_2/* .FieldType.JSON */.P.JSON,
|
|
6123
|
-
_enums_field_type_enum_js__rspack_import_2/* .FieldType.MULTI_SELECT */.P.MULTI_SELECT
|
|
6124
|
-
];
|
|
6125
|
-
const isIndexableFieldType = (fieldType)=>!NON_INDEXABLE_FIELD_TYPES.includes(fieldType);
|
|
6126
|
-
const uuidColumn = (name, driver, options = {})=>new typeorm__rspack_import_1.TableColumn({
|
|
6127
|
-
name,
|
|
6128
|
-
...driver === 'postgres' ? {
|
|
6129
|
-
type: 'uuid'
|
|
6130
|
-
} : {
|
|
6131
|
-
type: 'char',
|
|
6132
|
-
length: '36'
|
|
6133
|
-
},
|
|
6134
|
-
...options
|
|
6135
|
-
});
|
|
6136
|
-
function buildSystemColumns(flags, driver) {
|
|
6137
|
-
const columns = [
|
|
6138
|
-
uuidColumn('id', driver, {
|
|
6139
|
-
isPrimary: true,
|
|
6140
|
-
isGenerated: true,
|
|
6141
|
-
generationStrategy: 'uuid'
|
|
6142
|
-
}),
|
|
6143
|
-
new typeorm__rspack_import_1.TableColumn({
|
|
6144
|
-
name: 'created_at',
|
|
6145
|
-
type: 'timestamp',
|
|
6146
|
-
isNullable: false,
|
|
6147
|
-
default: 'CURRENT_TIMESTAMP'
|
|
6148
|
-
}),
|
|
6149
|
-
new typeorm__rspack_import_1.TableColumn({
|
|
6150
|
-
name: 'updated_at',
|
|
6151
|
-
type: 'timestamp',
|
|
6152
|
-
isNullable: false,
|
|
6153
|
-
default: 'CURRENT_TIMESTAMP'
|
|
6154
|
-
})
|
|
6155
|
-
];
|
|
6156
|
-
if (flags.isSoftDeleteEnabled) columns.push(softDeleteColumn());
|
|
6157
|
-
if (flags.isAuditEnabled) columns.push(...auditColumns(driver));
|
|
6158
|
-
return columns;
|
|
6159
|
-
}
|
|
6160
|
-
const softDeleteColumn = ()=>new typeorm__rspack_import_1.TableColumn({
|
|
6161
|
-
name: 'deleted_at',
|
|
6162
|
-
type: 'timestamp',
|
|
6163
|
-
isNullable: true
|
|
6164
|
-
});
|
|
6165
|
-
const auditColumns = (driver)=>[
|
|
6166
|
-
uuidColumn('created_by_id', driver, {
|
|
6167
|
-
isNullable: true
|
|
6168
|
-
}),
|
|
6169
|
-
uuidColumn('updated_by_id', driver, {
|
|
6170
|
-
isNullable: true
|
|
6171
|
-
}),
|
|
6172
|
-
uuidColumn('deleted_by_id', driver, {
|
|
6173
|
-
isNullable: true
|
|
6174
|
-
})
|
|
6175
|
-
];
|
|
6176
|
-
const sameColumns = (columnNames, expected)=>columnNames.length === expected.length && expected.every((c)=>columnNames.includes(c));
|
|
6177
|
-
const NAME_HASH_LENGTH = 8;
|
|
6178
|
-
/**
|
|
6179
|
-
* Deterministic index/constraint name within the driver's identifier limit. The hash of
|
|
6180
|
-
* `table.column` keeps names distinct when the readable part is cut short, and when two
|
|
6181
|
-
* table/column pairs would read the same (`eb_a_b` + `c` vs `eb_a` + `b_c`).
|
|
6182
|
-
*/ function indexName(prefix, table, column, maxLength) {
|
|
6183
|
-
const hash = (0,node_crypto__rspack_import_0.createHash)('sha256').update(`${table}.${column}`).digest('hex').slice(0, NAME_HASH_LENGTH);
|
|
6184
|
-
const room = maxLength - prefix.length - hash.length - 2;
|
|
6185
|
-
return `${prefix}_${`${table}_${column}`.slice(0, room)}_${hash}`;
|
|
6186
|
-
}
|
|
6187
|
-
const plainIndex = (table, column, driver, adapter)=>new typeorm__rspack_import_1.TableIndex({
|
|
6188
|
-
name: indexName('idx', table, column, adapter.maxIdentifierLength(driver)),
|
|
6189
|
-
columnNames: [
|
|
6190
|
-
column
|
|
6191
|
-
]
|
|
6192
|
-
});
|
|
6193
|
-
const tableUnique = (table, column, driver, adapter)=>new typeorm__rspack_import_1.TableUnique({
|
|
6194
|
-
name: indexName('uq', table, column, adapter.maxIdentifierLength(driver)),
|
|
6195
|
-
columnNames: [
|
|
6196
|
-
column
|
|
6197
|
-
]
|
|
6198
|
-
});
|
|
6199
|
-
/** MySQL has no unique constraints (TypeORM refuses them), only unique indexes. */ async function addUnique(qr, table, column, driver, adapter) {
|
|
6200
|
-
const name = indexName('uq', table.name, column, adapter.maxIdentifierLength(driver));
|
|
6201
|
-
if (driver === 'mysql') {
|
|
6202
|
-
await qr.createIndex(table, new typeorm__rspack_import_1.TableIndex({
|
|
6203
|
-
name,
|
|
6204
|
-
columnNames: [
|
|
6205
|
-
column
|
|
6206
|
-
],
|
|
6207
|
-
isUnique: true
|
|
6208
|
-
}));
|
|
6209
|
-
return;
|
|
6210
|
-
}
|
|
6211
|
-
await qr.createUniqueConstraint(table, new typeorm__rspack_import_1.TableUnique({
|
|
6212
|
-
name,
|
|
6213
|
-
columnNames: [
|
|
6214
|
-
column
|
|
6215
|
-
]
|
|
6216
|
-
}));
|
|
6217
|
-
}
|
|
6218
|
-
/** The stored column type, with a `uuid` stored before MySQL support became char(36) resolved to what MySQL accepts. */ function columnType(field, driver, adapter) {
|
|
6219
|
-
const type = field.dbType || adapter.mapFieldType(field.fieldType, driver);
|
|
6220
|
-
return driver === 'mysql' && type === 'uuid' ? 'char' : type;
|
|
6221
|
-
}
|
|
6222
|
-
/**
|
|
6223
|
-
* Column for a field. `enforceNotNull` controls whether the DB column is NOT NULL: true when
|
|
6224
|
-
* the table is brand new (no rows can violate it); false when adding to a table that already
|
|
6225
|
-
* has rows (the NOT NULL is applied afterwards, once the column has been backfilled).
|
|
6226
|
-
*/ function buildFieldColumn(field, driver, adapter, options) {
|
|
6227
|
-
const sizing = adapter.getColumnSizing(field.fieldType, driver);
|
|
6228
|
-
return new typeorm__rspack_import_1.TableColumn({
|
|
6229
|
-
name: field.code,
|
|
6230
|
-
type: columnType(field, driver, adapter),
|
|
6231
|
-
length: sizing.length,
|
|
6232
|
-
precision: sizing.precision ?? undefined,
|
|
6233
|
-
scale: sizing.scale,
|
|
6234
|
-
isNullable: options.enforceNotNull ? field.nullable : true,
|
|
6235
|
-
isUnique: options.withUnique ? field.unique : false
|
|
6236
|
-
});
|
|
6237
|
-
}
|
|
6238
|
-
/** The SQL type text for a field type on a driver, e.g. `varchar(255)`, `numeric(18,4)`, `char(36)`. */ function sqlTypeFor(fieldType, driver, adapter) {
|
|
6239
|
-
const base = adapter.mapFieldType(fieldType, driver);
|
|
6240
|
-
const sizing = adapter.getColumnSizing(fieldType, driver);
|
|
6241
|
-
if (sizing.length) return `${base}(${sizing.length})`;
|
|
6242
|
-
if (sizing.precision !== undefined) return `${base}(${sizing.precision},${sizing.scale ?? 0})`;
|
|
6243
|
-
return base;
|
|
6244
|
-
}
|
|
6245
|
-
/** Coarse type family, so `character varying` (pg) and `varchar` (mysql) compare equal. */ function typeFamily(type) {
|
|
6246
|
-
const t = type.toLowerCase();
|
|
6247
|
-
if (t === 'uuid') return 'uuid';
|
|
6248
|
-
if (t.includes('json')) return 'json';
|
|
6249
|
-
if (t.includes('timestamp') || t === 'datetime') return 'timestamp';
|
|
6250
|
-
if (t === 'date') return 'date';
|
|
6251
|
-
if (t.includes('bool') || t === 'tinyint') return 'boolean';
|
|
6252
|
-
if (t.includes('int') && !t.includes('point')) return 'integer';
|
|
6253
|
-
if (t.includes('numeric') || t.includes('decimal')) return 'numeric';
|
|
6254
|
-
if (t.includes('char') || t === 'varchar') return 'varchar';
|
|
6255
|
-
if (t.includes('text')) return 'text';
|
|
6256
|
-
return t;
|
|
6257
|
-
}
|
|
6258
|
-
|
|
6259
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
6260
|
-
$6: () => (addUnique),
|
|
6261
|
-
Rm: () => (buildSystemColumns),
|
|
6262
|
-
cg: () => (sqlTypeFor),
|
|
6263
|
-
fu: () => (buildFieldColumn),
|
|
6264
|
-
jp: () => (typeFamily),
|
|
6265
|
-
mo: () => (indexName)
|
|
6266
|
-
}, {
|
|
6267
|
-
G7: sameColumns,
|
|
6268
|
-
HK: auditColumns,
|
|
6269
|
-
OG: softDeleteColumn,
|
|
6270
|
-
d4: isIndexableFieldType,
|
|
6271
|
-
gW: NON_INDEXABLE_FIELD_TYPES,
|
|
6272
|
-
mq: SYSTEM_COLUMN_NAMES,
|
|
6273
|
-
uy: tableUnique,
|
|
6274
|
-
v7: plainIndex
|
|
6275
|
-
});
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
6653
|
},
|
|
6279
6654
|
7259(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
6280
6655
|
/* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(6157);
|