@flusys/nestjs-entity-builder 9.1.0-rc.1 → 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 -23
- package/config/entity-builder.constants.d.ts +2 -0
- package/config/message-keys.d.ts +102 -13
- package/controllers/definition-bundle.controller.d.ts +15 -0
- package/controllers/flow-definition.controller.d.ts +7 -1
- package/controllers/flow-runtime.controller.d.ts +16 -8
- package/controllers/index.d.ts +1 -1
- package/dtos/definition-bundle.dto.d.ts +57 -0
- package/dtos/flow.dto.d.ts +13 -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 +105 -15
- package/fesm/458.js +695 -0
- package/fesm/{489.js → 582.js} +22 -30
- package/fesm/{996.js → 677.js} +1562 -1064
- package/fesm/794.js +135 -240
- package/fesm/{719.js → 870.js} +2065 -324
- package/fesm/{362.js → 897.js} +572 -8
- package/fesm/{606.js → 946.js} +621 -296
- 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 +106 -22
- package/fesm/index.js +429 -937
- package/fesm/interfaces/index.js +19 -2
- package/fesm/modules/index.js +10 -627
- package/fesm/rule-engine/index.js +12 -3
- package/fesm/services/index.js +101 -29
- package/flow-engine/flow-api-key.d.ts +3 -7
- package/flow-engine/flow-graph.validator.d.ts +5 -4
- package/flow-engine/flow-permission-logic.d.ts +2 -0
- package/flow-engine/flow-run.types.d.ts +19 -9
- package/flow-engine/flow.types.d.ts +115 -11
- 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 +4 -3
- package/services/flow-definition.service.d.ts +26 -12
- package/services/flow-execution.service.d.ts +7 -0
- package/services/flow-executor.service.d.ts +9 -8
- package/services/flow-runtime.service.d.ts +2 -1
- 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 +6 -2
- 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;
|
|
@@ -1034,7 +1460,7 @@ async function insertChildren(node, child, parentId, env, state) {
|
|
|
1034
1460
|
const cfg = c;
|
|
1035
1461
|
const input = cfg.inputList !== undefined ? await env.ruleEngine.resolveExpression(cfg.inputList, evaluationContext(state, env)) : await mapValues(cfg.input, env, state);
|
|
1036
1462
|
return {
|
|
1037
|
-
output: await env.callFlow(cfg.flowSlug, input, state)
|
|
1463
|
+
output: await env.callFlow(cfg.flowSlug, input, state, cfg.endpoint || undefined)
|
|
1038
1464
|
};
|
|
1039
1465
|
}
|
|
1040
1466
|
case 'http_request':
|
|
@@ -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;
|
|
@@ -1128,7 +1559,8 @@ async function insertChildren(node, child, parentId, env, state) {
|
|
|
1128
1559
|
|
|
1129
1560
|
const errorMessage = (error)=>error instanceof Error ? error.message : String(error);
|
|
1130
1561
|
/**
|
|
1131
|
-
* Walks a flow graph from
|
|
1562
|
+
* Walks a flow graph from the Request step the call came in on (`state.startAt`; left out, the one
|
|
1563
|
+
* on the flow's own URL): runs a node, follows the output port it chose, repeats.
|
|
1132
1564
|
* `foreach` runs its `each` branch once per item and then continues on `done`; inside a nested
|
|
1133
1565
|
* loop the outer loop's scope stays reachable as `loop.parent`. A `respond` node
|
|
1134
1566
|
* ends the whole run. Limits (steps, time) are checked before every node.
|
|
@@ -1147,7 +1579,7 @@ const errorMessage = (error)=>error instanceof Error ? error.message : String(er
|
|
|
1147
1579
|
/** Runs to completion or throws (FlowNodeError wraps whatever a node threw). */ async walk(state) {
|
|
1148
1580
|
const trigger = [
|
|
1149
1581
|
...this.nodes.values()
|
|
1150
|
-
].find((n)=>n.type === 'trigger');
|
|
1582
|
+
].find((n)=>n.type === 'trigger' && (state.startAt ? n.id === state.startAt : !(0,flow_types/* .triggerPath */.um)(n)));
|
|
1151
1583
|
if (!trigger) throw new flow_errors/* .FlowLimitError */.IM(message_keys/* .FLOW_ERROR_MESSAGES.NO_TRIGGER */.zr.NO_TRIGGER);
|
|
1152
1584
|
await this.run(trigger.id, state);
|
|
1153
1585
|
}
|
|
@@ -1378,14 +1810,16 @@ function successResult(state, startedAt) {
|
|
|
1378
1810
|
},
|
|
1379
1811
|
3186(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
1380
1812
|
/* import */ var _flusys_nestjs_shared_utils__rspack_import_0 = __webpack_require__(9216);
|
|
1381
|
-
/* import */ var
|
|
1382
|
-
/* 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);
|
|
1383
1815
|
/* import */ var _interfaces_generic_record_interface_js__rspack_import_1 = __webpack_require__(3372);
|
|
1384
|
-
/* import */ var _rule_engine_index_js__rspack_import_2 = __webpack_require__(
|
|
1816
|
+
/* import */ var _rule_engine_index_js__rspack_import_2 = __webpack_require__(8429);
|
|
1385
1817
|
/* import */ var _rule_engine_rule_ip_js__rspack_import_3 = __webpack_require__(809);
|
|
1386
1818
|
/* import */ var _rule_engine_rule_permission_js__rspack_import_4 = __webpack_require__(5191);
|
|
1387
1819
|
/* import */ var _rule_engine_rule_regex_js__rspack_import_5 = __webpack_require__(6308);
|
|
1388
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
|
+
|
|
1389
1823
|
|
|
1390
1824
|
|
|
1391
1825
|
|
|
@@ -1566,37 +2000,37 @@ function isExpression(value) {
|
|
|
1566
2000
|
return !!value && typeof value === 'object' && typeof value.type === 'string';
|
|
1567
2001
|
}
|
|
1568
2002
|
/** Expression shape check with the engine's limits (no evaluation). */ function expressionProblem(value, depth = 0, options = {}) {
|
|
1569
|
-
if (!isExpression(value)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
1570
|
-
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);
|
|
1571
2005
|
switch(value.type){
|
|
1572
2006
|
case 'literal':
|
|
1573
2007
|
return null;
|
|
1574
2008
|
case 'field_ref':
|
|
1575
|
-
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);
|
|
1576
2010
|
case 'template':
|
|
1577
|
-
if (typeof value.template !== 'string') return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
1578
|
-
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);
|
|
1579
2013
|
case 'arithmetic':
|
|
1580
|
-
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);
|
|
1581
2015
|
case 'concat':
|
|
1582
|
-
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);
|
|
1583
2017
|
case 'function':
|
|
1584
2018
|
return functionProblem(value, depth, options);
|
|
1585
2019
|
case 'lookup':
|
|
1586
2020
|
return lookupProblem(value, depth, options);
|
|
1587
2021
|
default:
|
|
1588
|
-
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, {
|
|
1589
2023
|
type: value.type
|
|
1590
2024
|
});
|
|
1591
2025
|
}
|
|
1592
2026
|
}
|
|
1593
2027
|
function functionProblem(value, depth, options) {
|
|
1594
|
-
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);
|
|
1595
2029
|
const arity = FUNCTION_ARITY[value.name];
|
|
1596
|
-
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, {
|
|
1597
2031
|
name: String(value.name)
|
|
1598
2032
|
});
|
|
1599
|
-
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, {
|
|
1600
2034
|
name: value.name,
|
|
1601
2035
|
min: arity[0],
|
|
1602
2036
|
max: arity[1]
|
|
@@ -1604,7 +2038,7 @@ function functionProblem(value, depth, options) {
|
|
|
1604
2038
|
const unitAt = DURATION_ARG[value.name];
|
|
1605
2039
|
const unit = unitAt === undefined ? undefined : value.args[unitAt];
|
|
1606
2040
|
if (unit?.type === 'literal' && !_rule_engine_index_js__rspack_import_2/* .RULE_DURATION_UNITS.includes */.qO.includes(unit.value)) {
|
|
1607
|
-
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, {
|
|
1608
2042
|
units: _rule_engine_index_js__rspack_import_2/* .RULE_DURATION_UNITS.join */.qO.join(', ')
|
|
1609
2043
|
});
|
|
1610
2044
|
}
|
|
@@ -1627,18 +2061,18 @@ function functionProblem(value, depth, options) {
|
|
|
1627
2061
|
try {
|
|
1628
2062
|
parsed = (0,_rule_engine_rule_permission_js__rspack_import_4/* .parsePermissionCodes */.PS)(codes.value);
|
|
1629
2063
|
} catch {
|
|
1630
|
-
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, {
|
|
1631
2065
|
max: _rule_engine_index_js__rspack_import_2/* .RULE_ENGINE_LIMITS.MAX_PERMISSION_CODES */.bw.MAX_PERMISSION_CODES
|
|
1632
2066
|
});
|
|
1633
2067
|
}
|
|
1634
|
-
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, {
|
|
1635
2069
|
name: value.name
|
|
1636
2070
|
});
|
|
1637
2071
|
}
|
|
1638
2072
|
if (value.name === 'IP_IN_RANGE') {
|
|
1639
2073
|
const ranges = literal(1);
|
|
1640
2074
|
const invalid = ranges.ok ? (0,_rule_engine_rule_ip_js__rspack_import_3/* .invalidIpRange */.I8)(ranges.value) : null;
|
|
1641
|
-
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, {
|
|
1642
2076
|
range: invalid
|
|
1643
2077
|
}) : null;
|
|
1644
2078
|
}
|
|
@@ -1652,13 +2086,13 @@ function functionProblem(value, depth, options) {
|
|
|
1652
2086
|
function patternProblem(pattern) {
|
|
1653
2087
|
switch((0,_rule_engine_rule_regex_js__rspack_import_5/* .rulePatternProblem */._V)(pattern)){
|
|
1654
2088
|
case 'too_long':
|
|
1655
|
-
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, {
|
|
1656
2090
|
max: _rule_engine_index_js__rspack_import_2/* .RULE_ENGINE_LIMITS.MAX_REGEX_PATTERN_LENGTH */.bw.MAX_REGEX_PATTERN_LENGTH
|
|
1657
2091
|
});
|
|
1658
2092
|
case 'invalid':
|
|
1659
|
-
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);
|
|
1660
2094
|
case 'too_complex':
|
|
1661
|
-
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, {
|
|
1662
2096
|
max: _rule_engine_index_js__rspack_import_2/* .RULE_ENGINE_LIMITS.MAX_REGEX_REPEAT */.bw.MAX_REGEX_REPEAT
|
|
1663
2097
|
});
|
|
1664
2098
|
default:
|
|
@@ -1666,20 +2100,20 @@ function patternProblem(pattern) {
|
|
|
1666
2100
|
}
|
|
1667
2101
|
}
|
|
1668
2102
|
function lookupProblem(value, depth, options) {
|
|
1669
|
-
if (typeof value.entity !== 'string' || !
|
|
1670
|
-
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, {
|
|
1671
2105
|
entity: value.entity
|
|
1672
2106
|
});
|
|
1673
2107
|
if (![
|
|
1674
2108
|
'exists',
|
|
1675
2109
|
'count',
|
|
1676
2110
|
'first'
|
|
1677
|
-
].includes(value.mode)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
1678
|
-
if (value.field !== undefined && (typeof value.field !== 'string' || !COLUMN_CODE.test(value.field))) return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
1679
|
-
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)(
|
|
1680
|
-
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);
|
|
1681
2115
|
for (const [key, item] of Object.entries(value.filter)){
|
|
1682
|
-
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);
|
|
1683
2117
|
const problem = filterValueProblem(item, depth, options);
|
|
1684
2118
|
if (problem) return problem;
|
|
1685
2119
|
}
|
|
@@ -1688,13 +2122,13 @@ function lookupProblem(value, depth, options) {
|
|
|
1688
2122
|
/** A filter entry: an expression (eq) or `{ op, value? }` with an expression value. */ function filterValueProblem(item, depth, options) {
|
|
1689
2123
|
if (!(0,_interfaces_generic_record_interface_js__rspack_import_1/* .isRecordFilterCondition */.t1)(item)) {
|
|
1690
2124
|
const op = item && typeof item === 'object' && !Array.isArray(item) && !('type' in item) ? item.op : undefined;
|
|
1691
|
-
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, {
|
|
1692
2126
|
op
|
|
1693
2127
|
});
|
|
1694
2128
|
return expressionProblem(item, depth + 1, options);
|
|
1695
2129
|
}
|
|
1696
2130
|
if (item.op === 'is_null' || item.op === 'not_null') return null;
|
|
1697
|
-
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, {
|
|
1698
2132
|
op: item.op
|
|
1699
2133
|
});
|
|
1700
2134
|
return expressionProblem(item.value, depth + 1, options);
|
|
@@ -1708,8 +2142,8 @@ function firstProblem(items, depth, options) {
|
|
|
1708
2142
|
}
|
|
1709
2143
|
function conditionProblem(node, options) {
|
|
1710
2144
|
const hasLeft = node?.left !== undefined;
|
|
1711
|
-
if (!node || !hasLeft && (typeof node.field !== 'string' || !node.field) || typeof node.comparison !== 'string') return (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
1712
|
-
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, {
|
|
1713
2147
|
comparison: node.comparison
|
|
1714
2148
|
});
|
|
1715
2149
|
if (hasLeft) {
|
|
@@ -1725,15 +2159,15 @@ function conditionProblem(node, options) {
|
|
|
1725
2159
|
return null;
|
|
1726
2160
|
}
|
|
1727
2161
|
/** Rule group shape check with the engine's limits (no evaluation). */ function groupProblem(group, depth = 0, options = {}) {
|
|
1728
|
-
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);
|
|
1729
2163
|
const g = group;
|
|
1730
|
-
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)(
|
|
1731
|
-
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);
|
|
1732
2166
|
if (![
|
|
1733
2167
|
'AND',
|
|
1734
2168
|
'OR',
|
|
1735
2169
|
'NOT'
|
|
1736
|
-
].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);
|
|
1737
2171
|
for (const node of g.conditions){
|
|
1738
2172
|
const problem = node && (0,_rule_engine_index_js__rspack_import_2/* .isRuleGroup */.GD)(node) ? groupProblem(node, depth + 1, options) : conditionProblem(node, options);
|
|
1739
2173
|
if (problem) return problem;
|
|
@@ -1741,32 +2175,22 @@ function conditionProblem(node, options) {
|
|
|
1741
2175
|
return null;
|
|
1742
2176
|
}
|
|
1743
2177
|
/**
|
|
1744
|
-
* Save-time check of a whole flow: structure (
|
|
2178
|
+
* Save-time check of a whole flow: structure (Request steps with distinct URLs, valid ids/ports, no cycles),
|
|
1745
2179
|
* every node's configuration, every reference to another node, and the combination of
|
|
1746
|
-
* settings (
|
|
2180
|
+
* settings (auth / transaction). Pure: no I/O, so the same result is what the
|
|
1747
2181
|
* designer shows and what the server enforces.
|
|
1748
2182
|
*/ function validateFlow(flow, context = {}) {
|
|
1749
2183
|
const errors = [];
|
|
1750
2184
|
const warnings = [];
|
|
1751
2185
|
const err = (message)=>errors.push(message);
|
|
1752
|
-
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)(
|
|
1753
|
-
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, {
|
|
1754
|
-
runAs: String(flow.runAs)
|
|
1755
|
-
}));
|
|
1756
|
-
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, {
|
|
1757
|
-
authMode: String(flow.authMode)
|
|
1758
|
-
}));
|
|
1759
|
-
if (flow.runAs === 'caller' && flow.authMode !== 'jwt' && flow.authMode !== 'permission' && flow.authMode !== 'internal') {
|
|
1760
|
-
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));
|
|
1761
|
-
}
|
|
1762
|
-
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));
|
|
1763
2187
|
const nodes = Array.isArray(flow.nodes) ? flow.nodes : [];
|
|
1764
2188
|
const edges = Array.isArray(flow.edges) ? flow.edges : [];
|
|
1765
|
-
if (!nodes.length) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
1766
|
-
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, {
|
|
1767
2191
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_NODES */.Or.MAX_NODES
|
|
1768
2192
|
}));
|
|
1769
|
-
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, {
|
|
1770
2194
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_EDGES */.Or.MAX_EDGES
|
|
1771
2195
|
}));
|
|
1772
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 {
|
|
@@ -1776,48 +2200,46 @@ function conditionProblem(node, options) {
|
|
|
1776
2200
|
const byId = new Map();
|
|
1777
2201
|
for (const node of nodes){
|
|
1778
2202
|
if (!_flow_types_js__rspack_import_6/* .FLOW_NODE_ID_PATTERN.test */.z6.test(node?.id ?? '')) {
|
|
1779
|
-
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, {
|
|
1780
2204
|
id: node?.id
|
|
1781
2205
|
}));
|
|
1782
2206
|
continue;
|
|
1783
2207
|
}
|
|
1784
|
-
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, {
|
|
1785
2209
|
id: node.id
|
|
1786
2210
|
}));
|
|
1787
2211
|
byId.set(node.id, node);
|
|
1788
|
-
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, {
|
|
1789
2213
|
id: node.id,
|
|
1790
2214
|
type: node.type
|
|
1791
2215
|
}));
|
|
1792
2216
|
}
|
|
1793
2217
|
const triggers = nodes.filter((n)=>n.type === 'trigger');
|
|
1794
|
-
|
|
1795
|
-
count: triggers.length
|
|
1796
|
-
}));
|
|
2218
|
+
checkTriggers(triggers, err);
|
|
1797
2219
|
for (const node of nodes){
|
|
1798
2220
|
if (byId.get(node.id) === node) validateNodeConfig(node, flow, context, err, warnings);
|
|
1799
2221
|
}
|
|
1800
2222
|
const outgoing = new Map();
|
|
1801
2223
|
const edgeIds = new Set();
|
|
1802
2224
|
for (const edge of edges){
|
|
1803
|
-
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, {
|
|
1804
2226
|
id: edge.id
|
|
1805
2227
|
}));
|
|
1806
2228
|
edgeIds.add(edge.id);
|
|
1807
2229
|
const from = byId.get(edge.from);
|
|
1808
2230
|
const to = byId.get(edge.to);
|
|
1809
2231
|
if (!from || !to) {
|
|
1810
|
-
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, {
|
|
1811
2233
|
from: edge.from,
|
|
1812
2234
|
to: edge.to
|
|
1813
2235
|
}));
|
|
1814
2236
|
continue;
|
|
1815
2237
|
}
|
|
1816
|
-
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, {
|
|
1817
2239
|
id: edge.from
|
|
1818
2240
|
}));
|
|
1819
|
-
if (to.type === 'trigger') err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
1820
|
-
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, {
|
|
1821
2243
|
id: from.id,
|
|
1822
2244
|
port: edge.port
|
|
1823
2245
|
}));
|
|
@@ -1833,87 +2255,191 @@ function conditionProblem(node, options) {
|
|
|
1833
2255
|
const seenPairs = new Set();
|
|
1834
2256
|
for (const edge of edges){
|
|
1835
2257
|
const key = `${edge.from}|${edge.port}|${edge.to}`;
|
|
1836
|
-
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, {
|
|
1837
2259
|
from: edge.from,
|
|
1838
2260
|
to: edge.to
|
|
1839
2261
|
}));
|
|
1840
2262
|
seenPairs.add(key);
|
|
1841
2263
|
}
|
|
1842
2264
|
const cyclic = hasCycle(nodes, outgoing);
|
|
1843
|
-
if (cyclic) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
1844
|
-
const reachable = triggers.length
|
|
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));
|
|
2266
|
+
const reachable = triggers.length ? new Set(triggers.flatMap((trigger)=>[
|
|
2267
|
+
...reach(trigger.id, outgoing)
|
|
2268
|
+
])) : null;
|
|
1845
2269
|
for (const node of nodes){
|
|
1846
|
-
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, {
|
|
1847
2271
|
node: (0,_flow_types_js__rspack_import_6/* .nodeLabel */.dA)(node)
|
|
1848
2272
|
}));
|
|
1849
2273
|
}
|
|
1850
2274
|
checkNodeReferences(nodes, byId, flow, err, warnings);
|
|
1851
2275
|
if (!cyclic && reachable) checkReferenceTiming(nodes, edges, byId, reachable, warnings);
|
|
1852
2276
|
if (!cyclic) checkLoopDepth(nodes, outgoing, err);
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
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);
|
|
1863
2290
|
return {
|
|
1864
2291
|
errors,
|
|
1865
2292
|
warnings
|
|
1866
2293
|
};
|
|
1867
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
|
+
}
|
|
2342
|
+
/** At least one Request step; at most one on the flow's own URL, the others on distinct paths. */ function checkTriggers(triggers, err) {
|
|
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));
|
|
2344
|
+
const main = triggers.filter((trigger)=>!(0,_flow_types_js__rspack_import_6/* .triggerPath */.um)(trigger));
|
|
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, {
|
|
2346
|
+
count: main.length
|
|
2347
|
+
}));
|
|
2348
|
+
const paths = new Set();
|
|
2349
|
+
for (const trigger of triggers){
|
|
2350
|
+
const path = (0,_flow_types_js__rspack_import_6/* .triggerPath */.um)(trigger);
|
|
2351
|
+
if (!path) continue;
|
|
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, {
|
|
2353
|
+
path
|
|
2354
|
+
}));
|
|
2355
|
+
paths.add(path);
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
1868
2358
|
/**
|
|
1869
|
-
* What the runtime would always refuse, caught on save: an API-key flow
|
|
1870
|
-
*
|
|
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
|
|
1871
2361
|
* than the limit. An inactive flow and an input the called flow does not declare are warnings.
|
|
1872
|
-
*/ 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
|
+
};
|
|
1873
2367
|
const target = known.get(slug);
|
|
1874
2368
|
const vars = {
|
|
1875
2369
|
...at,
|
|
1876
2370
|
flow: slug
|
|
1877
2371
|
};
|
|
1878
|
-
if (!target.isActive) warn.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
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));
|
|
2373
|
+
const path = typeof endpoint === 'string' && endpoint ? endpoint : null;
|
|
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));
|
|
2377
|
+
if (!entry) {
|
|
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, {
|
|
2379
|
+
...vars,
|
|
2380
|
+
endpoint: path ?? ''
|
|
2381
|
+
}));
|
|
2382
|
+
} else if (entry.bodyType === 'list') {
|
|
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));
|
|
1886
2384
|
} else if (inputList !== undefined) {
|
|
1887
|
-
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));
|
|
1888
2386
|
} else {
|
|
1889
|
-
checkCalledInputs(input,
|
|
2387
|
+
checkCalledInputs(input, entry.inputSchema, vars, err, warn);
|
|
1890
2388
|
}
|
|
1891
2389
|
const loop = callPathTo(slug, flow.slug, known, new Set());
|
|
1892
|
-
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, {
|
|
1893
2391
|
...at,
|
|
1894
2392
|
chain: [
|
|
1895
2393
|
flow.slug,
|
|
1896
2394
|
...loop
|
|
1897
2395
|
].join(' > ')
|
|
1898
2396
|
}));
|
|
1899
|
-
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, {
|
|
1900
2398
|
...at,
|
|
1901
2399
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_CALL_DEPTH */.Or.MAX_CALL_DEPTH
|
|
1902
2400
|
}));
|
|
1903
2401
|
}
|
|
1904
|
-
/**
|
|
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
|
+
}
|
|
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) {
|
|
1905
2432
|
const given = input && typeof input === 'object' && !Array.isArray(input) ? Object.keys(input) : [];
|
|
1906
|
-
const schema = target.inputSchema ?? [];
|
|
1907
2433
|
if (schema.length) {
|
|
1908
2434
|
const declared = new Set(schema.map((field)=>field.name));
|
|
1909
|
-
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, {
|
|
1910
2436
|
...vars,
|
|
1911
2437
|
input: name
|
|
1912
2438
|
}));
|
|
1913
2439
|
}
|
|
1914
2440
|
for (const field of schema){
|
|
1915
2441
|
if (field.required && (field.default === undefined || field.default === null) && !given.includes(field.name)) {
|
|
1916
|
-
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, {
|
|
1917
2443
|
...vars,
|
|
1918
2444
|
input: field.name
|
|
1919
2445
|
}));
|
|
@@ -1943,42 +2469,36 @@ function conditionProblem(node, options) {
|
|
|
1943
2469
|
running.delete(slug);
|
|
1944
2470
|
return deepest;
|
|
1945
2471
|
}
|
|
1946
|
-
function validateInputSchema(flow, err) {
|
|
1947
|
-
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, {
|
|
1948
|
-
type: String(flow.bodyType)
|
|
1949
|
-
}));
|
|
1950
|
-
validateInputFields(flow.inputSchema ?? [], '', 1, err);
|
|
1951
|
-
}
|
|
1952
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) {
|
|
1953
|
-
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, {
|
|
1954
2474
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_INPUT_FIELDS */.Or.MAX_INPUT_FIELDS
|
|
1955
2475
|
}));
|
|
1956
2476
|
const seen = new Set();
|
|
1957
2477
|
for (const field of fields){
|
|
1958
2478
|
const name = `${prefix}${field?.name ?? ''}`;
|
|
1959
|
-
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, {
|
|
1960
2480
|
name
|
|
1961
2481
|
}));
|
|
1962
|
-
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, {
|
|
1963
2483
|
name
|
|
1964
2484
|
}));
|
|
1965
2485
|
seen.add(field?.name);
|
|
1966
|
-
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, {
|
|
1967
2487
|
name,
|
|
1968
2488
|
type: field?.type
|
|
1969
2489
|
}));
|
|
1970
2490
|
const itemType = field?.type === 'array' ? field.itemType : undefined;
|
|
1971
|
-
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, {
|
|
1972
2492
|
name,
|
|
1973
2493
|
type: itemType
|
|
1974
2494
|
}));
|
|
1975
|
-
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, {
|
|
1976
2496
|
name
|
|
1977
2497
|
}));
|
|
1978
2498
|
const holdsFields = field?.type === 'object' || itemType === 'object';
|
|
1979
2499
|
if (!holdsFields || !Array.isArray(field.fields) || !field.fields.length) continue;
|
|
1980
2500
|
if (depth >= _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_INPUT_DEPTH */.Or.MAX_INPUT_DEPTH) {
|
|
1981
|
-
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, {
|
|
1982
2502
|
name,
|
|
1983
2503
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_INPUT_DEPTH */.Or.MAX_INPUT_DEPTH
|
|
1984
2504
|
}));
|
|
@@ -1997,7 +2517,7 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
1997
2517
|
};
|
|
1998
2518
|
const expr = (value, what)=>{
|
|
1999
2519
|
const problem = expressionProblem(value, 0, shape);
|
|
2000
|
-
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, {
|
|
2001
2521
|
...at,
|
|
2002
2522
|
what,
|
|
2003
2523
|
problem
|
|
@@ -2005,7 +2525,7 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2005
2525
|
};
|
|
2006
2526
|
const exprMap = (value, kind)=>{
|
|
2007
2527
|
if (value === undefined) return;
|
|
2008
|
-
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, {
|
|
2009
2529
|
...at,
|
|
2010
2530
|
what: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(kind.list)
|
|
2011
2531
|
}));
|
|
@@ -2015,13 +2535,13 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2015
2535
|
};
|
|
2016
2536
|
const filterMap = (value, kind)=>{
|
|
2017
2537
|
if (value === undefined) return;
|
|
2018
|
-
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, {
|
|
2019
2539
|
...at,
|
|
2020
2540
|
what: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(kind.list)
|
|
2021
2541
|
}));
|
|
2022
2542
|
for (const [key, item] of Object.entries(value)){
|
|
2023
2543
|
const problem = filterValueProblem(item, -1, shape);
|
|
2024
|
-
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, {
|
|
2025
2545
|
...at,
|
|
2026
2546
|
what: (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(kind.item, {
|
|
2027
2547
|
name: key
|
|
@@ -2032,106 +2552,172 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2032
2552
|
};
|
|
2033
2553
|
const rule = (value, what)=>{
|
|
2034
2554
|
const problem = groupProblem(value, 0, shape);
|
|
2035
|
-
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, {
|
|
2036
2556
|
...at,
|
|
2037
2557
|
what,
|
|
2038
2558
|
problem
|
|
2039
2559
|
}));
|
|
2040
2560
|
};
|
|
2041
2561
|
const entity = (value)=>{
|
|
2042
|
-
if (typeof value !== 'string' || !
|
|
2043
|
-
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, {
|
|
2044
2564
|
...at,
|
|
2045
2565
|
entity: value
|
|
2046
2566
|
}));
|
|
2047
2567
|
};
|
|
2048
2568
|
const KIND = {
|
|
2049
2569
|
variable: {
|
|
2050
|
-
list:
|
|
2051
|
-
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
|
|
2052
2572
|
},
|
|
2053
2573
|
field: {
|
|
2054
|
-
list:
|
|
2055
|
-
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
|
|
2056
2576
|
},
|
|
2057
2577
|
filter: {
|
|
2058
|
-
list:
|
|
2059
|
-
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
|
|
2060
2580
|
},
|
|
2061
2581
|
input: {
|
|
2062
|
-
list:
|
|
2063
|
-
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
|
|
2064
2584
|
},
|
|
2065
2585
|
header: {
|
|
2066
|
-
list:
|
|
2067
|
-
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
|
|
2068
2588
|
},
|
|
2069
2589
|
body: {
|
|
2070
|
-
list:
|
|
2071
|
-
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
|
|
2072
2592
|
},
|
|
2073
2593
|
payload: {
|
|
2074
|
-
list:
|
|
2075
|
-
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
|
|
2076
2596
|
},
|
|
2077
2597
|
response: {
|
|
2078
|
-
list:
|
|
2079
|
-
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
|
|
2080
2608
|
}
|
|
2081
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
|
+
};
|
|
2082
2624
|
switch(node.type){
|
|
2083
2625
|
case 'trigger':
|
|
2084
|
-
|
|
2626
|
+
{
|
|
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.
|
|
2648
|
+
const path = (0,_flow_types_js__rspack_import_6/* .triggerPath */.um)(node);
|
|
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, {
|
|
2650
|
+
type: String(c.bodyType)
|
|
2651
|
+
}));
|
|
2652
|
+
validateInputFields(Array.isArray(c.inputSchema) ? c.inputSchema : [], path ? `${path}: ` : '', 1, err);
|
|
2653
|
+
break;
|
|
2654
|
+
}
|
|
2085
2655
|
case 'validate':
|
|
2086
2656
|
validateChecks(c, at, rule, err);
|
|
2087
|
-
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));
|
|
2088
2658
|
if (c.statusCode !== undefined && !(Number.isInteger(c.statusCode) && c.statusCode >= 400 && c.statusCode <= 499)) {
|
|
2089
|
-
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));
|
|
2090
2660
|
}
|
|
2091
2661
|
break;
|
|
2092
2662
|
case 'permission_check':
|
|
2093
2663
|
{
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
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));
|
|
2680
|
+
}
|
|
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));
|
|
2100
2684
|
}
|
|
2101
|
-
if (c.
|
|
2102
|
-
if (c.
|
|
2103
|
-
if (c.
|
|
2104
|
-
|
|
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));
|
|
2105
2691
|
if (c.statusCode !== undefined && !(Number.isInteger(c.statusCode) && c.statusCode >= 400 && c.statusCode <= 499)) {
|
|
2106
|
-
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));
|
|
2107
2693
|
}
|
|
2108
2694
|
break;
|
|
2109
2695
|
}
|
|
2110
2696
|
case 'set':
|
|
2111
2697
|
exprMap(c.values, KIND.variable);
|
|
2112
|
-
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));
|
|
2113
2699
|
for (const key of Object.keys(c.values ?? {})){
|
|
2114
|
-
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, {
|
|
2115
2701
|
...at,
|
|
2116
2702
|
name: key
|
|
2117
2703
|
}));
|
|
2118
2704
|
}
|
|
2119
2705
|
break;
|
|
2120
2706
|
case 'condition':
|
|
2121
|
-
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));
|
|
2122
2708
|
break;
|
|
2123
2709
|
case 'switch':
|
|
2124
2710
|
{
|
|
2125
|
-
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));
|
|
2126
2712
|
const cases = Array.isArray(c.cases) ? c.cases : [];
|
|
2127
|
-
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));
|
|
2128
2714
|
const ids = new Set();
|
|
2129
2715
|
for (const item of cases){
|
|
2130
|
-
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, {
|
|
2131
2717
|
...at,
|
|
2132
2718
|
name: String(item.id)
|
|
2133
2719
|
}));
|
|
2134
|
-
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, {
|
|
2135
2721
|
...at,
|
|
2136
2722
|
name: item.id
|
|
2137
2723
|
}));
|
|
@@ -2140,10 +2726,10 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2140
2726
|
break;
|
|
2141
2727
|
}
|
|
2142
2728
|
case 'foreach':
|
|
2143
|
-
expr(c.items, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2144
|
-
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));
|
|
2145
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)) {
|
|
2146
|
-
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, {
|
|
2147
2733
|
...at,
|
|
2148
2734
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_FOREACH_ITEMS */.Or.MAX_FOREACH_ITEMS
|
|
2149
2735
|
}));
|
|
@@ -2196,29 +2782,34 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2196
2782
|
break;
|
|
2197
2783
|
case 'entity_get':
|
|
2198
2784
|
entity(c.entityCode);
|
|
2199
|
-
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));
|
|
2200
2786
|
break;
|
|
2201
2787
|
case 'entity_query':
|
|
2202
2788
|
entity(c.entityCode);
|
|
2203
2789
|
filterMap(c.filter, KIND.filter);
|
|
2204
|
-
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
|
+
}
|
|
2205
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)) {
|
|
2206
|
-
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, {
|
|
2207
2797
|
...at,
|
|
2208
2798
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_QUERY_LIMIT */.Or.MAX_QUERY_LIMIT
|
|
2209
2799
|
}));
|
|
2210
2800
|
}
|
|
2211
2801
|
break;
|
|
2212
2802
|
case 'call_flow':
|
|
2213
|
-
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)(
|
|
2214
|
-
else if (c.flowSlug === flow.slug) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2215
|
-
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, {
|
|
2216
2806
|
...at,
|
|
2217
2807
|
flow: c.flowSlug
|
|
2218
2808
|
}));
|
|
2219
|
-
else if (context.knownFlows) checkCalledFlow(
|
|
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));
|
|
2220
2811
|
exprMap(c.input, KIND.input);
|
|
2221
|
-
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));
|
|
2222
2813
|
break;
|
|
2223
2814
|
case 'http_request':
|
|
2224
2815
|
{
|
|
@@ -2228,12 +2819,13 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2228
2819
|
'PUT',
|
|
2229
2820
|
'PATCH',
|
|
2230
2821
|
'DELETE'
|
|
2231
|
-
].includes(String(c.method))) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2232
|
-
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));
|
|
2233
2824
|
exprMap(c.headers, KIND.header);
|
|
2234
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));
|
|
2235
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)) {
|
|
2236
|
-
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, {
|
|
2237
2829
|
...at,
|
|
2238
2830
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_HTTP_TIMEOUT_MS */.Or.MAX_HTTP_TIMEOUT_MS
|
|
2239
2831
|
}));
|
|
@@ -2241,28 +2833,71 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2241
2833
|
break;
|
|
2242
2834
|
}
|
|
2243
2835
|
case 'publish_event':
|
|
2244
|
-
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));
|
|
2245
2837
|
exprMap(c.payload, KIND.payload);
|
|
2246
2838
|
break;
|
|
2247
|
-
case '
|
|
2839
|
+
case 'send_notification':
|
|
2248
2840
|
{
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
if (
|
|
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));
|
|
2253
2858
|
break;
|
|
2254
2859
|
}
|
|
2255
|
-
case '
|
|
2256
|
-
|
|
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
|
+
}
|
|
2882
|
+
case 'respond':
|
|
2883
|
+
{
|
|
2884
|
+
const status = c.statusCode;
|
|
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));
|
|
2886
|
+
exprMap(c.body, KIND.response);
|
|
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));
|
|
2888
|
+
break;
|
|
2889
|
+
}
|
|
2890
|
+
case 'commit':
|
|
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));
|
|
2257
2892
|
break;
|
|
2258
2893
|
case 'code':
|
|
2259
|
-
if (typeof c.code !== 'string' || !c.code.trim()) err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2260
|
-
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, {
|
|
2261
2896
|
...at,
|
|
2262
2897
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_CODE_LENGTH */.Or.MAX_CODE_LENGTH
|
|
2263
2898
|
}));
|
|
2264
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)) {
|
|
2265
|
-
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, {
|
|
2266
2901
|
...at,
|
|
2267
2902
|
min: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MIN_CODE_TIMEOUT_MS */.Or.MIN_CODE_TIMEOUT_MS,
|
|
2268
2903
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_CODE_TIMEOUT_MS */.Or.MAX_CODE_TIMEOUT_MS
|
|
@@ -2273,19 +2908,19 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2273
2908
|
}
|
|
2274
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 }) {
|
|
2275
2910
|
const target = c.target ?? 'one';
|
|
2276
|
-
if (typeof target !== 'string' || !targets.includes(target)) return err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2277
|
-
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));
|
|
2278
2913
|
const needsId = notFound.length > 0;
|
|
2279
|
-
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));
|
|
2280
2915
|
if (target === 'many') {
|
|
2281
|
-
expr(c.items, (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2282
|
-
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));
|
|
2283
2918
|
}
|
|
2284
2919
|
if (target === 'filter') {
|
|
2285
2920
|
filterMap(c.filter);
|
|
2286
|
-
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));
|
|
2287
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)) {
|
|
2288
|
-
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, {
|
|
2289
2924
|
...at,
|
|
2290
2925
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_WRITE_ITEMS */.Or.MAX_WRITE_ITEMS
|
|
2291
2926
|
}));
|
|
@@ -2294,45 +2929,45 @@ function validateNodeConfig(node, flow, context, err, warn) {
|
|
|
2294
2929
|
}
|
|
2295
2930
|
function childInserts(value, { at, entity, expr, err }) {
|
|
2296
2931
|
if (value === undefined) return;
|
|
2297
|
-
if (!Array.isArray(value)) return err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2298
|
-
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, {
|
|
2299
2934
|
...at,
|
|
2300
2935
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_CHILD_INSERTS */.Or.MAX_CHILD_INSERTS
|
|
2301
2936
|
}));
|
|
2302
2937
|
const names = new Set();
|
|
2303
2938
|
for (const child of value){
|
|
2304
2939
|
if (!child || typeof child !== 'object') {
|
|
2305
|
-
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));
|
|
2306
2941
|
continue;
|
|
2307
2942
|
}
|
|
2308
2943
|
const name = String(child.as ?? '');
|
|
2309
|
-
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, {
|
|
2310
2945
|
...at,
|
|
2311
2946
|
name
|
|
2312
2947
|
}));
|
|
2313
|
-
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, {
|
|
2314
2949
|
...at,
|
|
2315
2950
|
name
|
|
2316
2951
|
}));
|
|
2317
2952
|
names.add(name);
|
|
2318
2953
|
entity(child.entityCode);
|
|
2319
|
-
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, {
|
|
2320
2955
|
...at,
|
|
2321
2956
|
name
|
|
2322
2957
|
}));
|
|
2323
|
-
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, {
|
|
2324
2959
|
name
|
|
2325
2960
|
}));
|
|
2326
2961
|
const fields = child.fields;
|
|
2327
2962
|
if (fields === undefined) continue;
|
|
2328
2963
|
if (!fields || typeof fields !== 'object' || Array.isArray(fields)) {
|
|
2329
|
-
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, {
|
|
2330
2965
|
...at,
|
|
2331
|
-
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)
|
|
2332
2967
|
}));
|
|
2333
2968
|
continue;
|
|
2334
2969
|
}
|
|
2335
|
-
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, {
|
|
2336
2971
|
name: `${name}.${key}`
|
|
2337
2972
|
}));
|
|
2338
2973
|
}
|
|
@@ -2340,7 +2975,8 @@ function childInserts(value, { at, entity, expr, err }) {
|
|
|
2340
2975
|
/**
|
|
2341
2976
|
* How many loop levels each part of a node's config runs inside, beyond the loops around the node:
|
|
2342
2977
|
* a foreach's `collect` runs in its own loop; a many / filter write's per-record expressions in one
|
|
2343
|
-
* 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.
|
|
2344
2980
|
*/ function configScopes(node) {
|
|
2345
2981
|
const config = node.config ?? {};
|
|
2346
2982
|
if (node.type === 'foreach') {
|
|
@@ -2358,6 +2994,21 @@ function childInserts(value, { at, entity, expr, err }) {
|
|
|
2358
2994
|
}
|
|
2359
2995
|
];
|
|
2360
2996
|
}
|
|
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
|
+
}
|
|
2361
3012
|
if (!WRITE_NODE_TYPES.has(node.type)) return [
|
|
2362
3013
|
{
|
|
2363
3014
|
value: config,
|
|
@@ -2396,39 +3047,42 @@ function childInserts(value, { at, entity, expr, err }) {
|
|
|
2396
3047
|
return scopes;
|
|
2397
3048
|
}
|
|
2398
3049
|
function validateChecks(c, at, rule, err) {
|
|
2399
|
-
if (!Array.isArray(c.checks) || !c.checks.length) return err((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
2400
|
-
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, {
|
|
2401
3052
|
...at,
|
|
2402
3053
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_VALIDATE_CHECKS */.Or.MAX_VALIDATE_CHECKS
|
|
2403
3054
|
}));
|
|
2404
3055
|
const ids = new Set();
|
|
2405
3056
|
for (const check of c.checks){
|
|
2406
3057
|
const id = check?.id;
|
|
2407
|
-
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, {
|
|
2408
3059
|
...at,
|
|
2409
3060
|
name: String(id)
|
|
2410
3061
|
}));
|
|
2411
|
-
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, {
|
|
2412
3063
|
...at,
|
|
2413
3064
|
name: id
|
|
2414
3065
|
}));
|
|
2415
3066
|
else ids.add(id);
|
|
2416
3067
|
const name = String(id);
|
|
2417
|
-
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, {
|
|
2418
3069
|
name
|
|
2419
3070
|
}));
|
|
2420
|
-
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, {
|
|
2421
3072
|
...at,
|
|
2422
3073
|
name
|
|
2423
3074
|
}));
|
|
2424
|
-
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, {
|
|
2425
3076
|
...at,
|
|
2426
3077
|
name
|
|
2427
3078
|
}));
|
|
2428
3079
|
}
|
|
2429
3080
|
}
|
|
2430
|
-
/** Every `context.<node>` must name a node of this flow; `input.<name>` should be
|
|
2431
|
-
const
|
|
3081
|
+
/** Every `context.<node>` must name a node of this flow; `input.<name>` should be an input some Request step declares. */ function checkNodeReferences(nodes, byId, flow, err, warnings) {
|
|
3082
|
+
const endpoints = (0,_flow_types_js__rspack_import_6/* .flowEndpoints */.Xr)(flow);
|
|
3083
|
+
const declaredInputs = new Set(endpoints.flatMap((endpoint)=>endpoint.inputSchema.map((f)=>f.name)));
|
|
3084
|
+
// A list body is read by index, and an object body without fields takes anything: neither has names to check.
|
|
3085
|
+
const namesKnown = endpoints.length > 0 && endpoints.every((endpoint)=>endpoint.bodyType !== 'list' && endpoint.inputSchema.length > 0);
|
|
2432
3086
|
for (const node of nodes){
|
|
2433
3087
|
let refs;
|
|
2434
3088
|
try {
|
|
@@ -2439,21 +3093,21 @@ function validateChecks(c, at, rule, err) {
|
|
|
2439
3093
|
for (const ref of refs){
|
|
2440
3094
|
const [scope, second] = ref.split('.');
|
|
2441
3095
|
if (!REF_SCOPES.has(scope)) {
|
|
2442
|
-
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, {
|
|
2443
3097
|
node: (0,_flow_types_js__rspack_import_6/* .nodeLabel */.dA)(node),
|
|
2444
3098
|
ref
|
|
2445
3099
|
}));
|
|
2446
3100
|
} else if (scope === 'context' && second && !byId.has(second)) {
|
|
2447
|
-
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, {
|
|
2448
3102
|
node: (0,_flow_types_js__rspack_import_6/* .nodeLabel */.dA)(node),
|
|
2449
3103
|
target: second
|
|
2450
3104
|
}));
|
|
2451
3105
|
} else if (scope === 'context' && second === node.id) {
|
|
2452
|
-
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, {
|
|
2453
3107
|
node: (0,_flow_types_js__rspack_import_6/* .nodeLabel */.dA)(node)
|
|
2454
3108
|
}));
|
|
2455
|
-
} else if (scope === 'input' && second &&
|
|
2456
|
-
warnings.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(
|
|
3109
|
+
} else if (scope === 'input' && second && namesKnown && !declaredInputs.has(second)) {
|
|
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, {
|
|
2457
3111
|
node: (0,_flow_types_js__rspack_import_6/* .nodeLabel */.dA)(node),
|
|
2458
3112
|
input: second
|
|
2459
3113
|
}));
|
|
@@ -2469,15 +3123,28 @@ function refsOf(value, refs = [], depth = 0) {
|
|
|
2469
3123
|
return refs;
|
|
2470
3124
|
}
|
|
2471
3125
|
/**
|
|
2472
|
-
* Writes that do not share a transaction, and Save progress steps that would not commit:
|
|
2473
|
-
* without the transaction setting, inside a loop (once per item), or in a flow
|
|
2474
|
-
* (inside its caller's transaction it is skipped).
|
|
2475
|
-
*/ function checkTransactionUse(flow,
|
|
2476
|
-
const
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
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
|
+
];
|
|
2481
3148
|
const commits = live.filter((n)=>n.type === 'commit');
|
|
2482
3149
|
if (!commits.length) return;
|
|
2483
3150
|
const loops = live.filter((n)=>n.type === 'foreach').map((n)=>({
|
|
@@ -2491,13 +3158,12 @@ function refsOf(value, refs = [], depth = 0) {
|
|
|
2491
3158
|
const at = {
|
|
2492
3159
|
node: (0,_flow_types_js__rspack_import_6/* .nodeLabel */.dA)(commit)
|
|
2493
3160
|
};
|
|
2494
|
-
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));
|
|
2495
3161
|
const loop = loops.find((l)=>l.body.has(commit.id));
|
|
2496
|
-
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, {
|
|
2497
3163
|
...at,
|
|
2498
3164
|
loop: (0,_flow_types_js__rspack_import_6/* .nodeLabel */.dA)(loop.node)
|
|
2499
3165
|
}));
|
|
2500
|
-
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));
|
|
2501
3167
|
}
|
|
2502
3168
|
}
|
|
2503
3169
|
/** Every node a loop's `each` branch runs, nested loops included. */ function loopBody(loopId, outgoing) {
|
|
@@ -2600,14 +3266,14 @@ function refsOf(value, refs = [], depth = 0) {
|
|
|
2600
3266
|
const [scope, target, field] = segs;
|
|
2601
3267
|
if (scope === 'loop') {
|
|
2602
3268
|
const parents = segs.slice(1).findIndex((s)=>s !== 'parent');
|
|
2603
|
-
if (!depth) warn(
|
|
2604
|
-
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, {});
|
|
2605
3271
|
}
|
|
2606
3272
|
if (scope !== 'context' || !target || target === node.id || !byId.has(target)) continue;
|
|
2607
|
-
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, {
|
|
2608
3274
|
target: nameOf(target)
|
|
2609
3275
|
});
|
|
2610
|
-
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, {
|
|
2611
3277
|
loop: nameOf(target)
|
|
2612
3278
|
});
|
|
2613
3279
|
}
|
|
@@ -2662,15 +3328,15 @@ function reach(start, outgoing) {
|
|
|
2662
3328
|
nesting.set(id, max);
|
|
2663
3329
|
return max;
|
|
2664
3330
|
};
|
|
2665
|
-
|
|
2666
|
-
if (start && nestingFrom(start.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_7/* .FLOW_VALIDATION_MESSAGES.LOOP_TOO_DEEP */.qj.LOOP_TOO_DEEP, {
|
|
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, {
|
|
2667
3332
|
max: _flow_types_js__rspack_import_6/* .FLOW_LIMITS.MAX_LOOP_DEPTH */.Or.MAX_LOOP_DEPTH
|
|
2668
3333
|
}));
|
|
2669
3334
|
}
|
|
2670
3335
|
|
|
2671
3336
|
__webpack_require__.d(__webpack_exports__, {
|
|
2672
|
-
|
|
2673
|
-
|
|
3337
|
+
nC: () => (validateFlow),
|
|
3338
|
+
r7: () => (callProblems),
|
|
3339
|
+
u9: () => (usesPermissionFunction)
|
|
2674
3340
|
});
|
|
2675
3341
|
|
|
2676
3342
|
|
|
@@ -2873,6 +3539,19 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
2873
3539
|
});
|
|
2874
3540
|
|
|
2875
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
|
+
|
|
2876
3555
|
},
|
|
2877
3556
|
8542(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
2878
3557
|
/* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(6157);
|
|
@@ -2954,172 +3633,14 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
2954
3633
|
});
|
|
2955
3634
|
|
|
2956
3635
|
|
|
2957
|
-
},
|
|
2958
|
-
6256(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
2959
|
-
const FLOW_NODE_TYPES = [
|
|
2960
|
-
'trigger',
|
|
2961
|
-
'validate',
|
|
2962
|
-
'permission_check',
|
|
2963
|
-
'set',
|
|
2964
|
-
'condition',
|
|
2965
|
-
'switch',
|
|
2966
|
-
'foreach',
|
|
2967
|
-
'entity_insert',
|
|
2968
|
-
'entity_update',
|
|
2969
|
-
'entity_delete',
|
|
2970
|
-
'entity_get',
|
|
2971
|
-
'entity_query',
|
|
2972
|
-
'commit',
|
|
2973
|
-
'call_flow',
|
|
2974
|
-
'http_request',
|
|
2975
|
-
'publish_event',
|
|
2976
|
-
'respond',
|
|
2977
|
-
'code'
|
|
2978
|
-
];
|
|
2979
|
-
/** 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([
|
|
2980
|
-
'validate',
|
|
2981
|
-
'permission_check',
|
|
2982
|
-
'commit'
|
|
2983
|
-
]);
|
|
2984
|
-
const FLOW_AUTH_MODES = [
|
|
2985
|
-
'public',
|
|
2986
|
-
'api_key',
|
|
2987
|
-
'jwt',
|
|
2988
|
-
'permission',
|
|
2989
|
-
'internal'
|
|
2990
|
-
];
|
|
2991
|
-
const FLOW_RUN_AS = [
|
|
2992
|
-
'caller',
|
|
2993
|
-
'system'
|
|
2994
|
-
];
|
|
2995
|
-
/** 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 = [
|
|
2996
|
-
'object',
|
|
2997
|
-
'list'
|
|
2998
|
-
];
|
|
2999
|
-
const FLOW_INPUT_TYPES = [
|
|
3000
|
-
'string',
|
|
3001
|
-
'text',
|
|
3002
|
-
'number',
|
|
3003
|
-
'integer',
|
|
3004
|
-
'boolean',
|
|
3005
|
-
'date',
|
|
3006
|
-
'datetime',
|
|
3007
|
-
'email',
|
|
3008
|
-
'uuid',
|
|
3009
|
-
'object',
|
|
3010
|
-
'array',
|
|
3011
|
-
'choice'
|
|
3012
|
-
];
|
|
3013
|
-
/** How a step is named in messages: its name, or its id when it was left unnamed. */ const nodeLabel = (node)=>node.name || node.id;
|
|
3014
|
-
/**
|
|
3015
|
-
* Which records a write node touches. one (default): a single record. many: one per item of `items`,
|
|
3016
|
-
* whose per-record expressions read the item as `loop.item` (a loop around the node becomes
|
|
3017
|
-
* `loop.parent`). filter: every record matching `filter`, read as `loop.item`.
|
|
3018
|
-
*/ const RECORD_WRITE_TARGETS = [
|
|
3019
|
-
'one',
|
|
3020
|
-
'many',
|
|
3021
|
-
'filter'
|
|
3022
|
-
];
|
|
3023
|
-
const FLOW_LIMITS = {
|
|
3024
|
-
MAX_NODES: 100,
|
|
3025
|
-
MAX_EDGES: 300,
|
|
3026
|
-
/** Room for a full foreach (MAX_FOREACH_ITEMS) with a few steps per item. */ MAX_STEPS_PER_RUN: 5000,
|
|
3027
|
-
MAX_FOREACH_ITEMS: 1000,
|
|
3028
|
-
MAX_LOOP_DEPTH: 3,
|
|
3029
|
-
MAX_CALL_DEPTH: 5,
|
|
3030
|
-
MAX_HTTP_CALLS: 10,
|
|
3031
|
-
MAX_HTTP_TIMEOUT_MS: 15_000,
|
|
3032
|
-
MAX_HTTP_RESPONSE_BYTES: 1_000_000,
|
|
3033
|
-
MAX_QUERY_LIMIT: 200,
|
|
3034
|
-
MAX_WRITE_ITEMS: 1000,
|
|
3035
|
-
DEFAULT_WRITE_FILTER_LIMIT: 100,
|
|
3036
|
-
MAX_CHILD_INSERTS: 10,
|
|
3037
|
-
MAX_WRITES_PER_RUN: 5000,
|
|
3038
|
-
DEFAULT_TIMEOUT_MS: 30_000,
|
|
3039
|
-
MIN_TIMEOUT_MS: 1000,
|
|
3040
|
-
MAX_TIMEOUT_MS: 120_000,
|
|
3041
|
-
TRACE_PREVIEW_CHARS: 2000,
|
|
3042
|
-
MAX_INPUT_FIELDS: 50,
|
|
3043
|
-
/** How deep object/list-of-object fields may nest inside the request body. */ MAX_INPUT_DEPTH: 4,
|
|
3044
|
-
MAX_VALIDATE_CHECKS: 50,
|
|
3045
|
-
MAX_CODE_LENGTH: 20_000,
|
|
3046
|
-
DEFAULT_CODE_TIMEOUT_MS: 1000,
|
|
3047
|
-
MIN_CODE_TIMEOUT_MS: 10,
|
|
3048
|
-
MAX_CODE_TIMEOUT_MS: 5000,
|
|
3049
|
-
CODE_MEMORY_LIMIT_BYTES: 32 * 1024 * 1024,
|
|
3050
|
-
CODE_STACK_SIZE_BYTES: 512 * 1024,
|
|
3051
|
-
MAX_CODE_OUTPUT_BYTES: 1_000_000,
|
|
3052
|
-
MAX_CODE_LOG_LINES: 50,
|
|
3053
|
-
MAX_CODE_LOG_LINE_CHARS: 500
|
|
3054
|
-
};
|
|
3055
|
-
const FLOW_NODE_ID_PATTERN = /^[A-Za-z][A-Za-z0-9_]{0,39}$/;
|
|
3056
|
-
const FLOW_SLUG_PATTERN = /^[a-z][a-z0-9-]{2,62}$/;
|
|
3057
|
-
const FLOW_INPUT_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_]{0,59}$/;
|
|
3058
|
-
/** Output ports a node of this type can have (a `respond` node ends the flow: none). */ function portsOf(node) {
|
|
3059
|
-
switch(node.type){
|
|
3060
|
-
case 'condition':
|
|
3061
|
-
return [
|
|
3062
|
-
'true',
|
|
3063
|
-
'false'
|
|
3064
|
-
];
|
|
3065
|
-
case 'switch':
|
|
3066
|
-
return [
|
|
3067
|
-
...(node.config.cases ?? []).map((c)=>c.id),
|
|
3068
|
-
'default'
|
|
3069
|
-
];
|
|
3070
|
-
case 'foreach':
|
|
3071
|
-
return [
|
|
3072
|
-
'each',
|
|
3073
|
-
'done'
|
|
3074
|
-
];
|
|
3075
|
-
case 'permission_check':
|
|
3076
|
-
return node.config.onDenied === 'branch' ? [
|
|
3077
|
-
'allowed',
|
|
3078
|
-
'denied'
|
|
3079
|
-
] : [
|
|
3080
|
-
'out'
|
|
3081
|
-
];
|
|
3082
|
-
case 'respond':
|
|
3083
|
-
return [];
|
|
3084
|
-
case 'trigger':
|
|
3085
|
-
case 'validate':
|
|
3086
|
-
case 'set':
|
|
3087
|
-
case 'commit':
|
|
3088
|
-
return [
|
|
3089
|
-
'out'
|
|
3090
|
-
];
|
|
3091
|
-
default:
|
|
3092
|
-
return [
|
|
3093
|
-
'out',
|
|
3094
|
-
'error'
|
|
3095
|
-
];
|
|
3096
|
-
}
|
|
3097
|
-
}
|
|
3098
|
-
|
|
3099
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
3100
|
-
a5: () => (portsOf)
|
|
3101
|
-
}, {
|
|
3102
|
-
At: NON_CONTINUABLE_NODE_TYPES,
|
|
3103
|
-
Dn: RECORD_WRITE_TARGETS,
|
|
3104
|
-
Or: FLOW_LIMITS,
|
|
3105
|
-
Q7: FLOW_INPUT_TYPES,
|
|
3106
|
-
Y3: FLOW_BODY_TYPES,
|
|
3107
|
-
YD: FLOW_SLUG_PATTERN,
|
|
3108
|
-
dA: nodeLabel,
|
|
3109
|
-
fO: FLOW_AUTH_MODES,
|
|
3110
|
-
fZ: FLOW_INPUT_NAME_PATTERN,
|
|
3111
|
-
gl: FLOW_RUN_AS,
|
|
3112
|
-
q2: FLOW_NODE_TYPES,
|
|
3113
|
-
z6: FLOW_NODE_ID_PATTERN
|
|
3114
|
-
});
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
3636
|
},
|
|
3118
3637
|
2678(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
3119
3638
|
const SENSITIVE_KEY = /pass(word)?|secret|token|authorization|api[-_]?key|cookie|credential|private[-_]?key/i;
|
|
3120
3639
|
/** Copy of `value` with the content of sensitive-looking keys replaced, safe to store in a log. */ function redactSensitive(value, depth = 0) {
|
|
3121
3640
|
if (depth > 8) return '[deep]';
|
|
3122
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);
|
|
3123
3644
|
if (value && typeof value === 'object') {
|
|
3124
3645
|
const out = {};
|
|
3125
3646
|
for (const [key, item] of Object.entries(value)){
|
|
@@ -3148,6 +3669,24 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
3148
3669
|
});
|
|
3149
3670
|
|
|
3150
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
|
+
|
|
3151
3690
|
},
|
|
3152
3691
|
8323(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
3153
3692
|
/* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(6157);
|
|
@@ -3349,6 +3888,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
3349
3888
|
}
|
|
3350
3889
|
|
|
3351
3890
|
|
|
3891
|
+
const VARIABLE_ENV_PREFIX = 'ENTITY_BUILDER_VAR_';
|
|
3352
3892
|
class EntityBuilderConfigService {
|
|
3353
3893
|
options;
|
|
3354
3894
|
constructor(options){
|
|
@@ -3369,6 +3909,20 @@ class EntityBuilderConfigService {
|
|
|
3369
3909
|
getConfig() {
|
|
3370
3910
|
return this.options.config;
|
|
3371
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
|
+
}
|
|
3372
3926
|
}
|
|
3373
3927
|
EntityBuilderConfigService = _ts_decorate([
|
|
3374
3928
|
(0,_nestjs_common__rspack_import_0.Injectable)(),
|
|
@@ -3774,54 +4328,24 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
3774
4328
|
|
|
3775
4329
|
|
|
3776
4330
|
},
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
__webpack_require__
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
var
|
|
3786
|
-
|
|
3787
|
-
var
|
|
3788
|
-
|
|
3789
|
-
var
|
|
3790
|
-
|
|
3791
|
-
var
|
|
3792
|
-
|
|
3793
|
-
var
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
const API_KEY_PREFIX_LENGTH = 11; // "fk_" + 8 hex
|
|
3797
|
-
/** A new key: `fk_<8 hex>_<32 hex>`. Shown once; only its hash is stored. */ function generateApiKey() {
|
|
3798
|
-
const key = `fk_${(0,external_node_crypto_.randomBytes)(4).toString('hex')}_${(0,external_node_crypto_.randomBytes)(16).toString('hex')}`;
|
|
3799
|
-
return {
|
|
3800
|
-
key,
|
|
3801
|
-
prefix: apiKeyPrefix(key),
|
|
3802
|
-
hash: hashApiKey(key)
|
|
3803
|
-
};
|
|
3804
|
-
}
|
|
3805
|
-
const hashApiKey = (key)=>(0,external_node_crypto_.createHash)('sha256').update(key).digest('hex');
|
|
3806
|
-
const apiKeyPrefix = (key)=>key.slice(0, API_KEY_PREFIX_LENGTH);
|
|
3807
|
-
function looksLikeApiKey(key) {
|
|
3808
|
-
return typeof key === 'string' && /^fk_[0-9a-f]{8}_[0-9a-f]{32}$/.test(key);
|
|
3809
|
-
}
|
|
3810
|
-
/** Constant-time comparison of a presented key against a stored hash. */ function apiKeyMatches(presented, storedHash) {
|
|
3811
|
-
const a = Buffer.from(hashApiKey(presented), 'hex');
|
|
3812
|
-
const b = Buffer.from(storedHash, 'hex');
|
|
3813
|
-
return a.length === b.length && (0,external_node_crypto_.timingSafeEqual)(a, b);
|
|
3814
|
-
}
|
|
3815
|
-
|
|
3816
|
-
// EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/entities/flow-definition.entity.ts
|
|
3817
|
-
var flow_definition_entity = __webpack_require__(3770);
|
|
3818
|
-
// EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/rule-engine/rule-values.ts
|
|
3819
|
-
var rule_values = __webpack_require__(6622);
|
|
3820
|
-
// EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/services/entity-builder-datasource.provider.ts
|
|
3821
|
-
var entity_builder_datasource_provider = __webpack_require__(424);
|
|
3822
|
-
// EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/services/flow-definition.service.ts
|
|
3823
|
-
var flow_definition_service = __webpack_require__(5229);
|
|
3824
|
-
;// 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);
|
|
3825
4349
|
function _ts_decorate(decorators, target, key, desc) {
|
|
3826
4350
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3827
4351
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -3854,194 +4378,6 @@ function _ts_param(paramIndex, decorator) {
|
|
|
3854
4378
|
|
|
3855
4379
|
|
|
3856
4380
|
|
|
3857
|
-
const TOUCH_INTERVAL_MS = 60_000;
|
|
3858
|
-
class FlowApiKeyService {
|
|
3859
|
-
provider;
|
|
3860
|
-
constructor(provider){
|
|
3861
|
-
this.provider = provider;
|
|
3862
|
-
}
|
|
3863
|
-
async repo() {
|
|
3864
|
-
return this.provider.getRepository(flow_api_key_entity/* .FlowApiKey */.S);
|
|
3865
|
-
}
|
|
3866
|
-
async assertFlowExists(flowId) {
|
|
3867
|
-
const flow = await (await this.provider.getRepository(flow_definition_entity/* .FlowDefinition */.G)).findOne({
|
|
3868
|
-
where: {
|
|
3869
|
-
id: flowId
|
|
3870
|
-
},
|
|
3871
|
-
select: {
|
|
3872
|
-
id: true
|
|
3873
|
-
}
|
|
3874
|
-
});
|
|
3875
|
-
if (!flow) throw (0,flow_definition_service/* .flowNotFound */.YW)();
|
|
3876
|
-
}
|
|
3877
|
-
async findKey(id) {
|
|
3878
|
-
const key = await (await this.repo()).findOne({
|
|
3879
|
-
where: {
|
|
3880
|
-
id
|
|
3881
|
-
}
|
|
3882
|
-
});
|
|
3883
|
-
if (!key) throw new common_.NotFoundException({
|
|
3884
|
-
message: 'API key not found.',
|
|
3885
|
-
messageKey: message_keys/* .FLOW_MESSAGES.API_KEY_NOT_FOUND */.wu.API_KEY_NOT_FOUND
|
|
3886
|
-
});
|
|
3887
|
-
await this.assertFlowExists(key.flowId);
|
|
3888
|
-
return key;
|
|
3889
|
-
}
|
|
3890
|
-
/** The plain key is returned here and never again. */ async create(flowId, name, expiresAt, user) {
|
|
3891
|
-
const expiry = expiresAt ? (0,rule_values/* .parseDateText */.hz)(expiresAt) : null;
|
|
3892
|
-
if (expiry !== null && !(expiry > Date.now())) {
|
|
3893
|
-
throw new common_.BadRequestException({
|
|
3894
|
-
message: 'The expiry date of an API key must be in the future.',
|
|
3895
|
-
messageKey: message_keys/* .FLOW_MESSAGES.API_KEY_EXPIRY_IN_PAST */.wu.API_KEY_EXPIRY_IN_PAST
|
|
3896
|
-
});
|
|
3897
|
-
}
|
|
3898
|
-
await this.assertFlowExists(flowId);
|
|
3899
|
-
const { key, prefix, hash } = generateApiKey();
|
|
3900
|
-
const repo = await this.repo();
|
|
3901
|
-
const saved = await repo.save(repo.create({
|
|
3902
|
-
flowId,
|
|
3903
|
-
name,
|
|
3904
|
-
keyPrefix: prefix,
|
|
3905
|
-
keyHash: hash,
|
|
3906
|
-
isActive: true,
|
|
3907
|
-
expiresAt: expiry === null ? null : new Date(expiry),
|
|
3908
|
-
lastUsedAt: null,
|
|
3909
|
-
createdById: user?.id ?? null
|
|
3910
|
-
}));
|
|
3911
|
-
return {
|
|
3912
|
-
key,
|
|
3913
|
-
info: this.info(saved)
|
|
3914
|
-
};
|
|
3915
|
-
}
|
|
3916
|
-
async list(flowId) {
|
|
3917
|
-
await this.assertFlowExists(flowId);
|
|
3918
|
-
const rows = await (await this.repo()).find({
|
|
3919
|
-
where: {
|
|
3920
|
-
flowId
|
|
3921
|
-
},
|
|
3922
|
-
order: {
|
|
3923
|
-
createdAt: 'DESC'
|
|
3924
|
-
}
|
|
3925
|
-
});
|
|
3926
|
-
return rows.map((r)=>this.info(r));
|
|
3927
|
-
}
|
|
3928
|
-
async revoke(id) {
|
|
3929
|
-
const key = await this.findKey(id);
|
|
3930
|
-
await (await this.repo()).update({
|
|
3931
|
-
id: key.id
|
|
3932
|
-
}, {
|
|
3933
|
-
isActive: false
|
|
3934
|
-
});
|
|
3935
|
-
}
|
|
3936
|
-
async remove(id) {
|
|
3937
|
-
const key = await this.findKey(id);
|
|
3938
|
-
await (await this.repo()).softDelete({
|
|
3939
|
-
id: key.id
|
|
3940
|
-
});
|
|
3941
|
-
}
|
|
3942
|
-
/**
|
|
3943
|
-
* Checks `presented` against the unrevoked keys of this flow. Only the flow access guard calls
|
|
3944
|
-
* this, and only while the flow's authMode is `api_key`; revoking works in any authMode.
|
|
3945
|
-
*/ async verify(flowId, presented) {
|
|
3946
|
-
if (!looksLikeApiKey(presented)) return 'invalid';
|
|
3947
|
-
const repo = await this.repo();
|
|
3948
|
-
const candidates = await repo.find({
|
|
3949
|
-
where: {
|
|
3950
|
-
flowId,
|
|
3951
|
-
keyPrefix: apiKeyPrefix(presented),
|
|
3952
|
-
isActive: true,
|
|
3953
|
-
deletedAt: (0,external_typeorm_.IsNull)()
|
|
3954
|
-
},
|
|
3955
|
-
select: {
|
|
3956
|
-
id: true,
|
|
3957
|
-
keyHash: true,
|
|
3958
|
-
expiresAt: true,
|
|
3959
|
-
lastUsedAt: true
|
|
3960
|
-
}
|
|
3961
|
-
});
|
|
3962
|
-
const match = candidates.find((c)=>apiKeyMatches(presented, c.keyHash));
|
|
3963
|
-
if (!match) return 'invalid';
|
|
3964
|
-
if (isExpired(match.expiresAt)) return 'expired';
|
|
3965
|
-
if (!match.lastUsedAt || Date.now() - match.lastUsedAt.getTime() > TOUCH_INTERVAL_MS) {
|
|
3966
|
-
await repo.update({
|
|
3967
|
-
id: match.id
|
|
3968
|
-
}, {
|
|
3969
|
-
lastUsedAt: new Date()
|
|
3970
|
-
});
|
|
3971
|
-
}
|
|
3972
|
-
return 'valid';
|
|
3973
|
-
}
|
|
3974
|
-
info(row) {
|
|
3975
|
-
const status = !row.isActive ? 'revoked' : isExpired(row.expiresAt) ? 'expired' : 'active';
|
|
3976
|
-
return {
|
|
3977
|
-
id: row.id,
|
|
3978
|
-
flowId: row.flowId,
|
|
3979
|
-
name: row.name,
|
|
3980
|
-
keyPrefix: row.keyPrefix,
|
|
3981
|
-
isActive: row.isActive,
|
|
3982
|
-
status,
|
|
3983
|
-
expiresAt: row.expiresAt,
|
|
3984
|
-
lastUsedAt: row.lastUsedAt,
|
|
3985
|
-
createdAt: row.createdAt
|
|
3986
|
-
};
|
|
3987
|
-
}
|
|
3988
|
-
}
|
|
3989
|
-
FlowApiKeyService = _ts_decorate([
|
|
3990
|
-
(0,common_.Injectable)({
|
|
3991
|
-
scope: common_.Scope.REQUEST
|
|
3992
|
-
}),
|
|
3993
|
-
_ts_param(0, (0,common_.Inject)(entity_builder_datasource_provider/* .EntityBuilderDataSourceProvider */.D)),
|
|
3994
|
-
_ts_metadata("design:type", Function),
|
|
3995
|
-
_ts_metadata("design:paramtypes", [
|
|
3996
|
-
typeof entity_builder_datasource_provider/* .EntityBuilderDataSourceProvider */.D === "undefined" ? Object : entity_builder_datasource_provider/* .EntityBuilderDataSourceProvider */.D
|
|
3997
|
-
])
|
|
3998
|
-
], FlowApiKeyService);
|
|
3999
|
-
function isExpired(expiresAt) {
|
|
4000
|
-
return !!expiresAt && expiresAt.getTime() <= Date.now();
|
|
4001
|
-
}
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
},
|
|
4005
|
-
5229(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
4006
|
-
/* import */ var _flusys_nestjs_shared__rspack_import_0 = __webpack_require__(3422);
|
|
4007
|
-
/* import */ var _flusys_nestjs_shared_classes__rspack_import_1 = __webpack_require__(6937);
|
|
4008
|
-
/* import */ var _flusys_nestjs_shared_modules__rspack_import_2 = __webpack_require__(1236);
|
|
4009
|
-
/* import */ var _nestjs_common__rspack_import_3 = __webpack_require__(6157);
|
|
4010
|
-
/* import */ var typeorm__rspack_import_4 = __webpack_require__(7158);
|
|
4011
|
-
/* import */ var _config_event_actions_js__rspack_import_11 = __webpack_require__(982);
|
|
4012
|
-
/* import */ var _config_message_keys_js__rspack_import_10 = __webpack_require__(5732);
|
|
4013
|
-
/* import */ var _entities_entity_definition_entity_js__rspack_import_5 = __webpack_require__(3189);
|
|
4014
|
-
/* import */ var _entities_flow_definition_entity_js__rspack_import_6 = __webpack_require__(3770);
|
|
4015
|
-
/* import */ var _flow_engine_flow_graph_validator_js__rspack_import_7 = __webpack_require__(3186);
|
|
4016
|
-
/* import */ var _flow_engine_flow_types_js__rspack_import_8 = __webpack_require__(6256);
|
|
4017
|
-
/* import */ var _entity_builder_datasource_provider_js__rspack_import_9 = __webpack_require__(424);
|
|
4018
|
-
function _ts_decorate(decorators, target, key, desc) {
|
|
4019
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4020
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
4021
|
-
r = Reflect.decorate(decorators, target, key, desc);
|
|
4022
|
-
} else {
|
|
4023
|
-
for(var i = decorators.length - 1; i >= 0; i--){
|
|
4024
|
-
if (d = decorators[i]) {
|
|
4025
|
-
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
4026
|
-
}
|
|
4027
|
-
}
|
|
4028
|
-
}
|
|
4029
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
4030
|
-
}
|
|
4031
|
-
function _ts_metadata(metadataKey, metadataValue) {
|
|
4032
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
4033
|
-
return Reflect.metadata(metadataKey, metadataValue);
|
|
4034
|
-
}
|
|
4035
|
-
}
|
|
4036
|
-
function _ts_param(paramIndex, decorator) {
|
|
4037
|
-
return function(target, key) {
|
|
4038
|
-
decorator(target, key, paramIndex);
|
|
4039
|
-
};
|
|
4040
|
-
}
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
4381
|
|
|
4046
4382
|
|
|
4047
4383
|
|
|
@@ -4051,21 +4387,28 @@ function _ts_param(paramIndex, decorator) {
|
|
|
4051
4387
|
|
|
4052
4388
|
|
|
4053
4389
|
const defaultFlowPermissionCode = (slug)=>`entity_builder.flow.${slug}.execute`;
|
|
4054
|
-
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({
|
|
4055
4392
|
message: 'Flow not found.',
|
|
4056
|
-
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
|
|
4057
4406
|
});
|
|
4058
|
-
/**
|
|
4407
|
+
/** What running a flow needs; everything about a run is on its Request steps. */ function toFlowSettings(dto) {
|
|
4059
4408
|
return {
|
|
4060
4409
|
slug: dto.slug,
|
|
4061
|
-
authMode: dto.authMode ?? 'jwt',
|
|
4062
|
-
runAs: dto.runAs ?? 'caller',
|
|
4063
|
-
isTransactional: dto.isTransactional ?? false,
|
|
4064
|
-
bodyType: dto.bodyType ?? 'object',
|
|
4065
|
-
inputSchema: dto.inputSchema ?? [],
|
|
4066
4410
|
nodes: dto.nodes ?? [],
|
|
4067
|
-
edges: dto.edges ?? []
|
|
4068
|
-
timeoutMs: dto.timeoutMs ?? _flow_engine_flow_types_js__rspack_import_8/* .FLOW_LIMITS.DEFAULT_TIMEOUT_MS */.Or.DEFAULT_TIMEOUT_MS
|
|
4411
|
+
edges: dto.edges ?? []
|
|
4069
4412
|
};
|
|
4070
4413
|
}
|
|
4071
4414
|
class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import_1.ApiService {
|
|
@@ -4074,11 +4417,14 @@ class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import
|
|
|
4074
4417
|
provider;
|
|
4075
4418
|
permissionCache;
|
|
4076
4419
|
actionRegistry;
|
|
4077
|
-
|
|
4078
|
-
|
|
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;
|
|
4079
4425
|
}
|
|
4080
4426
|
async findOrFail(id) {
|
|
4081
|
-
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({
|
|
4082
4428
|
where: {
|
|
4083
4429
|
id
|
|
4084
4430
|
}
|
|
@@ -4086,29 +4432,28 @@ class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import
|
|
|
4086
4432
|
if (!flow) throw flowNotFound();
|
|
4087
4433
|
return flow;
|
|
4088
4434
|
}
|
|
4089
|
-
/** Validation with the real entity and flow lists. Returns errors and warnings without throwing. */ async validate(settings) {
|
|
4090
|
-
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({
|
|
4091
4437
|
select: {
|
|
4092
4438
|
code: true
|
|
4093
4439
|
}
|
|
4094
4440
|
});
|
|
4095
|
-
const flows = await (await this.provider.getRepository(
|
|
4096
|
-
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, {
|
|
4097
4443
|
knownEntityCodes: new Set(entities.map((e)=>e.code)),
|
|
4098
4444
|
knownFlows: new Map(flows.map((flow)=>[
|
|
4099
4445
|
flow.slug,
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
]))
|
|
4446
|
+
callableOf(flow)
|
|
4447
|
+
])),
|
|
4448
|
+
messageServices: {
|
|
4449
|
+
notification: !!this.notifications,
|
|
4450
|
+
email: !!this.email
|
|
4451
|
+
},
|
|
4452
|
+
companyMembers: !!this.companyAccess
|
|
4108
4453
|
});
|
|
4109
4454
|
}
|
|
4110
4455
|
/** Names of the other flows whose `call_flow` nodes run `slug`. */ async callersOf(slug, excludeIds) {
|
|
4111
|
-
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({
|
|
4112
4457
|
select: {
|
|
4113
4458
|
id: true,
|
|
4114
4459
|
name: true,
|
|
@@ -4120,21 +4465,109 @@ class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import
|
|
|
4120
4465
|
async assertNotCalled(slug, excludeIds) {
|
|
4121
4466
|
const callers = await this.callersOf(slug, excludeIds);
|
|
4122
4467
|
if (!callers.length) return;
|
|
4123
|
-
throw new
|
|
4468
|
+
throw new _nestjs_common__rspack_import_4.ConflictException({
|
|
4124
4469
|
message: `The flow '${slug}' is called by: ${callers.join(', ')}. Change those flows first.`,
|
|
4125
|
-
messageKey:
|
|
4470
|
+
messageKey: _config_message_keys_js__rspack_import_14/* .FLOW_MESSAGES.CALLED_BY_OTHER_FLOWS */.wu.CALLED_BY_OTHER_FLOWS,
|
|
4126
4471
|
messageVariables: {
|
|
4127
4472
|
slug,
|
|
4128
4473
|
flows: callers.join(', ')
|
|
4129
4474
|
}
|
|
4130
4475
|
});
|
|
4131
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
|
+
}
|
|
4540
|
+
/** A URL other flows' Call flow steps start at cannot be removed or renamed from under them. */ async assertEndpointsNotCalled(before, after) {
|
|
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));
|
|
4543
|
+
if (!removed.length) return;
|
|
4544
|
+
const flows = await (await this.provider.getRepository(_entities_flow_definition_entity_js__rspack_import_7/* .FlowDefinition */.G)).find({
|
|
4545
|
+
select: {
|
|
4546
|
+
id: true,
|
|
4547
|
+
name: true,
|
|
4548
|
+
nodes: true
|
|
4549
|
+
}
|
|
4550
|
+
});
|
|
4551
|
+
for (const path of removed){
|
|
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);
|
|
4553
|
+
if (!callers.length) continue;
|
|
4554
|
+
const url = `api-flows/${before.slug}${path ? `/${path}` : ''}`;
|
|
4555
|
+
throw new _nestjs_common__rspack_import_4.ConflictException({
|
|
4556
|
+
message: `The URL ${url} is called by: ${callers.join(', ')}. Change those flows first.`,
|
|
4557
|
+
messageKey: _config_message_keys_js__rspack_import_14/* .FLOW_MESSAGES.ENDPOINT_CALLED_BY_OTHER_FLOWS */.wu.ENDPOINT_CALLED_BY_OTHER_FLOWS,
|
|
4558
|
+
messageVariables: {
|
|
4559
|
+
url,
|
|
4560
|
+
flows: callers.join(', ')
|
|
4561
|
+
}
|
|
4562
|
+
});
|
|
4563
|
+
}
|
|
4564
|
+
}
|
|
4132
4565
|
async assertSaveable(settings, user, selfId) {
|
|
4133
4566
|
const { errors, warnings } = await this.validate(settings);
|
|
4134
4567
|
if (errors.length) {
|
|
4135
|
-
throw new
|
|
4568
|
+
throw new _nestjs_common__rspack_import_4.BadRequestException({
|
|
4136
4569
|
message: 'The flow has problems.',
|
|
4137
|
-
messageKey:
|
|
4570
|
+
messageKey: _config_message_keys_js__rspack_import_14/* .FLOW_MESSAGES.INVALID */.wu.INVALID,
|
|
4138
4571
|
errors: errors.map((error)=>({
|
|
4139
4572
|
field: 'flow',
|
|
4140
4573
|
...error
|
|
@@ -4142,16 +4575,16 @@ class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import
|
|
|
4142
4575
|
warnings
|
|
4143
4576
|
});
|
|
4144
4577
|
}
|
|
4145
|
-
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({
|
|
4146
4579
|
where: {
|
|
4147
4580
|
slug: settings.slug
|
|
4148
4581
|
},
|
|
4149
4582
|
withDeleted: true
|
|
4150
4583
|
});
|
|
4151
4584
|
if (clash && clash.id !== selfId) {
|
|
4152
|
-
throw new
|
|
4585
|
+
throw new _nestjs_common__rspack_import_4.ConflictException({
|
|
4153
4586
|
message: `The URL name '${settings.slug}' is already used by another flow.`,
|
|
4154
|
-
messageKey:
|
|
4587
|
+
messageKey: _config_message_keys_js__rspack_import_14/* .FLOW_MESSAGES.SLUG_TAKEN */.wu.SLUG_TAKEN,
|
|
4155
4588
|
messageVariables: {
|
|
4156
4589
|
slug: settings.slug
|
|
4157
4590
|
}
|
|
@@ -4160,7 +4593,6 @@ class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import
|
|
|
4160
4593
|
await this.assertMayAuthor(settings, user);
|
|
4161
4594
|
}
|
|
4162
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) {
|
|
4163
|
-
if (settings.runAs === 'system') await this.assertHasPermission(user, _flusys_nestjs_shared__rspack_import_0.FLOW_DEFINITION_PERMISSIONS.SYSTEM);
|
|
4164
4596
|
if (settings.nodes.some((node)=>node?.type === 'code')) await this.assertHasPermission(user, _flusys_nestjs_shared__rspack_import_0.FLOW_DEFINITION_PERMISSIONS.CODE);
|
|
4165
4597
|
}
|
|
4166
4598
|
async assertMayCreate(user) {
|
|
@@ -4168,13 +4600,13 @@ class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import
|
|
|
4168
4600
|
}
|
|
4169
4601
|
/**
|
|
4170
4602
|
* A test run needs what running the flow for real would: the author permissions for its
|
|
4171
|
-
*
|
|
4172
|
-
* real - a draft the permission to save it, a permission
|
|
4173
|
-
*/ 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) {
|
|
4174
4606
|
await this.assertMayAuthor(settings, user);
|
|
4175
4607
|
if (run.mode !== 'live') return;
|
|
4176
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);
|
|
4177
|
-
if (
|
|
4609
|
+
if (endpoint?.authMode === 'permission') await this.permissionCache.assertPermissionLogic(user, flowPermissions(endpoint, settings.slug));
|
|
4178
4610
|
}
|
|
4179
4611
|
assertHasPermission(user, permission) {
|
|
4180
4612
|
return this.permissionCache.assertPermission(user, permission);
|
|
@@ -4184,36 +4616,171 @@ class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import
|
|
|
4184
4616
|
dto
|
|
4185
4617
|
]){
|
|
4186
4618
|
await this.assertSaveable(toFlowSettings(d), user);
|
|
4187
|
-
|
|
4188
|
-
d.
|
|
4189
|
-
d.bodyType ??= 'object';
|
|
4190
|
-
d.authMode ??= 'jwt';
|
|
4191
|
-
d.runAs ??= 'caller';
|
|
4619
|
+
d.nodes = (0,_flow_engine_flow_api_key_js__rspack_import_9/* .sealApiKeys */.ue)(d.nodes);
|
|
4620
|
+
d.version = 0;
|
|
4192
4621
|
}
|
|
4193
4622
|
}
|
|
4194
|
-
|
|
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) {
|
|
4195
4627
|
for (const d of Array.isArray(dto) ? dto : [
|
|
4196
4628
|
dto
|
|
4197
4629
|
]){
|
|
4198
4630
|
const existing = await this.findOrFail(d.id);
|
|
4199
|
-
const
|
|
4200
|
-
...existing,
|
|
4631
|
+
const settings = toFlowSettings({
|
|
4632
|
+
...workingCopy(existing),
|
|
4201
4633
|
...stripUndefined(d)
|
|
4202
4634
|
});
|
|
4203
|
-
await this.assertSaveable(
|
|
4204
|
-
if (
|
|
4205
|
-
existing.
|
|
4206
|
-
|
|
4207
|
-
|
|
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);
|
|
4641
|
+
}
|
|
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);
|
|
4208
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
|
+
]);
|
|
4209
4776
|
}
|
|
4210
4777
|
async beforeDeleteOperation(dto, user, _qr) {
|
|
4211
4778
|
const ids = Array.isArray(dto.id) ? dto.id : [
|
|
4212
4779
|
dto.id
|
|
4213
4780
|
];
|
|
4214
|
-
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({
|
|
4215
4782
|
where: {
|
|
4216
|
-
id: (0,
|
|
4783
|
+
id: (0,typeorm__rspack_import_5.In)(ids)
|
|
4217
4784
|
},
|
|
4218
4785
|
withDeleted: true
|
|
4219
4786
|
});
|
|
@@ -4221,43 +4788,70 @@ class FlowDefinitionService extends _flusys_nestjs_shared_classes__rspack_import
|
|
|
4221
4788
|
if (dto.type === 'restore') return;
|
|
4222
4789
|
for (const flow of flows)await this.assertNotCalled(flow.slug, ids);
|
|
4223
4790
|
}
|
|
4224
|
-
async
|
|
4225
|
-
await this.provisionPermissions(entities);
|
|
4226
|
-
}
|
|
4227
|
-
async afterUpdateOperation(entities) {
|
|
4228
|
-
await this.provisionPermissions(entities);
|
|
4229
|
-
}
|
|
4230
|
-
async provisionPermissions(flows) {
|
|
4231
|
-
const needing = flows.filter((f)=>f.authMode === 'permission');
|
|
4232
|
-
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) {
|
|
4233
4792
|
if (!this.actionRegistry) return;
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
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
|
|
4237
4806
|
})));
|
|
4238
4807
|
}
|
|
4239
4808
|
}
|
|
4240
4809
|
FlowDefinitionService = _ts_decorate([
|
|
4241
|
-
(0,
|
|
4242
|
-
scope:
|
|
4810
|
+
(0,_nestjs_common__rspack_import_4.Injectable)({
|
|
4811
|
+
scope: _nestjs_common__rspack_import_4.Scope.REQUEST
|
|
4243
4812
|
}),
|
|
4244
|
-
_ts_param(0, (0,
|
|
4245
|
-
_ts_param(1, (0,
|
|
4246
|
-
_ts_param(2, (0,
|
|
4247
|
-
_ts_param(3, (0,
|
|
4248
|
-
_ts_param(4, (0,
|
|
4249
|
-
_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)),
|
|
4250
4825
|
_ts_metadata("design:type", Function),
|
|
4251
4826
|
_ts_metadata("design:paramtypes", [
|
|
4252
4827
|
typeof _flusys_nestjs_shared_classes__rspack_import_1.HybridCache === "undefined" ? Object : _flusys_nestjs_shared_classes__rspack_import_1.HybridCache,
|
|
4253
|
-
typeof
|
|
4254
|
-
typeof
|
|
4255
|
-
typeof
|
|
4256
|
-
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
|
|
4257
4835
|
])
|
|
4258
4836
|
], FlowDefinitionService);
|
|
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) {
|
|
4838
|
+
return (nodes ?? []).filter((node)=>node?.type === 'call_flow' && typeof node.config?.flowSlug === 'string').map((node)=>{
|
|
4839
|
+
const config = node.config;
|
|
4840
|
+
return {
|
|
4841
|
+
slug: config.flowSlug,
|
|
4842
|
+
endpoint: typeof config.endpoint === 'string' && config.endpoint ? config.endpoint : null
|
|
4843
|
+
};
|
|
4844
|
+
});
|
|
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
|
+
}
|
|
4259
4853
|
/** Slugs the `call_flow` nodes of a flow run. */ function calledSlugs(nodes) {
|
|
4260
|
-
return (nodes
|
|
4854
|
+
return calledTargets(nodes).map((target)=>target.slug);
|
|
4261
4855
|
}
|
|
4262
4856
|
function stripUndefined(value) {
|
|
4263
4857
|
return Object.fromEntries(Object.entries(value).filter(([, v])=>v !== undefined));
|
|
@@ -4265,10 +4859,14 @@ function stripUndefined(value) {
|
|
|
4265
4859
|
|
|
4266
4860
|
__webpack_require__.d(__webpack_exports__, {
|
|
4267
4861
|
RK: () => (toFlowSettings),
|
|
4268
|
-
Tk: () => (FlowDefinitionService)
|
|
4862
|
+
Tk: () => (FlowDefinitionService),
|
|
4863
|
+
eY: () => (snapshotOf)
|
|
4269
4864
|
}, {
|
|
4270
4865
|
Er: defaultFlowPermissionCode,
|
|
4271
|
-
|
|
4866
|
+
HF: isPublished,
|
|
4867
|
+
YW: flowNotFound,
|
|
4868
|
+
j4: flowPermissions,
|
|
4869
|
+
lw: workingCopy
|
|
4272
4870
|
});
|
|
4273
4871
|
|
|
4274
4872
|
|
|
@@ -4328,8 +4926,11 @@ class FlowExecutionService {
|
|
|
4328
4926
|
await repo.save(repo.create({
|
|
4329
4927
|
flowId: entry.flowId,
|
|
4330
4928
|
flowSlug: entry.flowSlug,
|
|
4929
|
+
flowVersion: entry.flowVersion,
|
|
4331
4930
|
status: entry.result.status,
|
|
4332
4931
|
trigger: entry.trigger,
|
|
4932
|
+
endpointNodeId: entry.endpoint?.nodeId ?? null,
|
|
4933
|
+
endpointPath: entry.endpoint?.path ?? null,
|
|
4333
4934
|
mode: entry.mode,
|
|
4334
4935
|
statusCode: entry.result.statusCode,
|
|
4335
4936
|
input: inputText.length > INPUT_LIMIT_CHARS ? {
|
|
@@ -4380,6 +4981,8 @@ class FlowExecutionService {
|
|
|
4380
4981
|
const where = {};
|
|
4381
4982
|
if (query.flowId) where.flowId = query.flowId;
|
|
4382
4983
|
if (query.status) where.status = query.status;
|
|
4984
|
+
if (query.trigger) where.trigger = query.trigger;
|
|
4985
|
+
if (query.endpointNodeId) where.endpointNodeId = query.endpointNodeId;
|
|
4383
4986
|
const [rows, total] = await repo.findAndCount({
|
|
4384
4987
|
where,
|
|
4385
4988
|
order: {
|
|
@@ -4392,8 +4995,11 @@ class FlowExecutionService {
|
|
|
4392
4995
|
id: true,
|
|
4393
4996
|
flowId: true,
|
|
4394
4997
|
flowSlug: true,
|
|
4998
|
+
flowVersion: true,
|
|
4395
4999
|
status: true,
|
|
4396
5000
|
trigger: true,
|
|
5001
|
+
endpointNodeId: true,
|
|
5002
|
+
endpointPath: true,
|
|
4397
5003
|
mode: true,
|
|
4398
5004
|
statusCode: true,
|
|
4399
5005
|
durationMs: true,
|
|
@@ -4438,7 +5044,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
4438
5044
|
|
|
4439
5045
|
|
|
4440
5046
|
},
|
|
4441
|
-
|
|
5047
|
+
3908(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
4442
5048
|
|
|
4443
5049
|
// EXPORTS
|
|
4444
5050
|
__webpack_require__.d(__webpack_exports__, {
|
|
@@ -4448,10 +5054,14 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
4448
5054
|
|
|
4449
5055
|
// EXTERNAL MODULE: external "@flusys/nestjs-shared/classes"
|
|
4450
5056
|
var classes_ = __webpack_require__(6937);
|
|
4451
|
-
|
|
4452
|
-
|
|
5057
|
+
;// CONCATENATED MODULE: external "@flusys/nestjs-shared/exceptions"
|
|
5058
|
+
|
|
5059
|
+
// EXTERNAL MODULE: external "@flusys/nestjs-shared/interfaces"
|
|
5060
|
+
var interfaces_ = __webpack_require__(5103);
|
|
4453
5061
|
// EXTERNAL MODULE: external "@flusys/nestjs-shared/modules"
|
|
4454
5062
|
var modules_ = __webpack_require__(1236);
|
|
5063
|
+
// EXTERNAL MODULE: external "@flusys/nestjs-shared/utils"
|
|
5064
|
+
var utils_ = __webpack_require__(9216);
|
|
4455
5065
|
// EXTERNAL MODULE: external "@nestjs/common"
|
|
4456
5066
|
var common_ = __webpack_require__(6157);
|
|
4457
5067
|
// EXTERNAL MODULE: external "@nestjs/core"
|
|
@@ -4689,8 +5299,8 @@ const BLOCKED_REQUEST_HEADERS = new Set([
|
|
|
4689
5299
|
});
|
|
4690
5300
|
}
|
|
4691
5301
|
|
|
4692
|
-
// EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/rule-engine/index.ts +
|
|
4693
|
-
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);
|
|
4694
5304
|
// EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/services/entity-builder-config.service.ts
|
|
4695
5305
|
var entity_builder_config_service = __webpack_require__(4281);
|
|
4696
5306
|
// EXTERNAL MODULE: ./projects/nestjs-entity-builder/src/services/entity-builder-datasource.provider.ts
|
|
@@ -4743,6 +5353,8 @@ function _ts_param(paramIndex, decorator) {
|
|
|
4743
5353
|
|
|
4744
5354
|
|
|
4745
5355
|
|
|
5356
|
+
|
|
5357
|
+
|
|
4746
5358
|
|
|
4747
5359
|
|
|
4748
5360
|
|
|
@@ -4753,41 +5365,47 @@ const publishFlowEvent = (eventName, payload, user)=>(0,classes_.publishDomainEv
|
|
|
4753
5365
|
metadata: payload,
|
|
4754
5366
|
user
|
|
4755
5367
|
});
|
|
4756
|
-
/** 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;
|
|
4757
5369
|
class FlowExecutorService {
|
|
4758
5370
|
provider;
|
|
4759
5371
|
ruleEngine;
|
|
4760
5372
|
moduleRef;
|
|
4761
5373
|
permissionCache;
|
|
4762
5374
|
config;
|
|
5375
|
+
companyAccess;
|
|
5376
|
+
notifications;
|
|
5377
|
+
email;
|
|
5378
|
+
branchHierarchy;
|
|
4763
5379
|
logger = new common_.Logger(FlowExecutorService.name);
|
|
4764
|
-
constructor(provider, ruleEngine, moduleRef, permissionCache, config){
|
|
5380
|
+
constructor(provider, ruleEngine, moduleRef, permissionCache, config, companyAccess, notifications, email, branchHierarchy){
|
|
4765
5381
|
this.provider = provider;
|
|
4766
5382
|
this.ruleEngine = ruleEngine;
|
|
4767
5383
|
this.moduleRef = moduleRef;
|
|
4768
5384
|
this.permissionCache = permissionCache;
|
|
4769
5385
|
this.config = config;
|
|
5386
|
+
this.companyAccess = companyAccess;
|
|
5387
|
+
this.notifications = notifications;
|
|
5388
|
+
this.email = email;
|
|
5389
|
+
this.branchHierarchy = branchHierarchy;
|
|
4770
5390
|
}
|
|
4771
|
-
async run(
|
|
5391
|
+
async run(flow, options) {
|
|
4772
5392
|
const startedAt = Date.now();
|
|
4773
|
-
const
|
|
4774
|
-
...definition,
|
|
4775
|
-
timeoutMs: flowTimeout(definition.timeoutMs)
|
|
4776
|
-
};
|
|
5393
|
+
const start = (0,flow_types/* .startEndpoint */.IE)(flow, options.startAt);
|
|
4777
5394
|
const state = {
|
|
5395
|
+
startAt: options.startAt,
|
|
4778
5396
|
input: options.input,
|
|
4779
5397
|
vars: {},
|
|
4780
5398
|
context: {},
|
|
4781
5399
|
request: options.request,
|
|
4782
5400
|
user: options.user,
|
|
5401
|
+
authorization: options.authorization,
|
|
4783
5402
|
permissions: this.ruleEngine.createPermissionResolver(options.user),
|
|
4784
5403
|
mode: options.mode,
|
|
4785
|
-
runAs: flow.runAs,
|
|
4786
|
-
systemAuthorized: flow.runAs === 'system' && options.systemAuthorized === true,
|
|
4787
5404
|
steps: 0,
|
|
4788
5405
|
httpCalls: 0,
|
|
5406
|
+
messages: 0,
|
|
4789
5407
|
writes: 0,
|
|
4790
|
-
deadline: startedAt +
|
|
5408
|
+
deadline: startedAt + flowTimeout(start?.timeoutMs),
|
|
4791
5409
|
callStack: [
|
|
4792
5410
|
flow.slug
|
|
4793
5411
|
],
|
|
@@ -4795,15 +5413,7 @@ class FlowExecutorService {
|
|
|
4795
5413
|
trace: []
|
|
4796
5414
|
};
|
|
4797
5415
|
try {
|
|
4798
|
-
|
|
4799
|
-
throw new flow_errors/* .FlowHttpError */.hk(403, 'This flow is not allowed to run.', undefined, {
|
|
4800
|
-
messageKey: message_keys/* .FLOW_ERROR_MESSAGES.RUN_AS_NOT_ALLOWED */.zr.RUN_AS_NOT_ALLOWED,
|
|
4801
|
-
messageVariables: {
|
|
4802
|
-
runAs: String(flow.runAs)
|
|
4803
|
-
}
|
|
4804
|
-
});
|
|
4805
|
-
}
|
|
4806
|
-
await this.execute(flow, state, this.createEnv());
|
|
5416
|
+
await this.execute(flow, start?.isTransactional === true, state, this.createEnv());
|
|
4807
5417
|
return {
|
|
4808
5418
|
...(0,flow_engine/* .successResult */.JK)(state, startedAt),
|
|
4809
5419
|
...state.savedUpTo ? {
|
|
@@ -4833,10 +5443,10 @@ class FlowExecutorService {
|
|
|
4833
5443
|
}
|
|
4834
5444
|
}
|
|
4835
5445
|
/**
|
|
4836
|
-
* Walks `flow`. A flow called from inside a transaction joins it; otherwise a
|
|
4837
|
-
*
|
|
4838
|
-
*/ async execute(flow, state, env) {
|
|
4839
|
-
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')) {
|
|
4840
5450
|
await new flow_engine/* .FlowEngine */.$I(flow, env).walk(state);
|
|
4841
5451
|
return;
|
|
4842
5452
|
}
|
|
@@ -4898,10 +5508,10 @@ class FlowExecutorService {
|
|
|
4898
5508
|
}
|
|
4899
5509
|
/**
|
|
4900
5510
|
* `call_flow`: runs another active flow as part of this run - same caller,
|
|
4901
|
-
* transaction, test mode and step/HTTP/time budget. Returns what it answered: its `respond`
|
|
5511
|
+
* transaction, test mode and step/HTTP/time budget, from the Request step at `endpoint` (left out, its own URL). Returns what it answered: its `respond`
|
|
4902
5512
|
* body, or the output of its last step. A 4xx/5xx answer or a rejection is passed on as the
|
|
4903
5513
|
* caller's own; any other failure fails the calling node.
|
|
4904
|
-
*/ async callFlow(slug, input, parent, env) {
|
|
5514
|
+
*/ async callFlow(slug, input, parent, env, endpoint) {
|
|
4905
5515
|
if (parent.callStack.includes(slug)) {
|
|
4906
5516
|
throw new flow_errors/* .FlowLimitError */.IM(message_keys/* .FLOW_ERROR_MESSAGES.CALLED_FLOW_RECURSION */.zr.CALLED_FLOW_RECURSION, {
|
|
4907
5517
|
flow: slug,
|
|
@@ -4915,8 +5525,16 @@ class FlowExecutorService {
|
|
|
4915
5525
|
max: flow_types/* .FLOW_LIMITS.MAX_CALL_DEPTH */.Or.MAX_CALL_DEPTH
|
|
4916
5526
|
});
|
|
4917
5527
|
const flow = await this.findCallable(slug, parent.qr);
|
|
4918
|
-
|
|
4919
|
-
const
|
|
5528
|
+
const settings = (0,flow_definition_service/* .toFlowSettings */.RK)(flow);
|
|
5529
|
+
const start = (0,flow_types/* .findEndpoint */.vS)(settings, endpoint);
|
|
5530
|
+
if (!start) {
|
|
5531
|
+
throw new flow_errors/* .FlowKeyedError */.Hp(message_keys/* .FLOW_ERROR_MESSAGES.CALLED_FLOW_ENDPOINT_NOT_FOUND */.zr.CALLED_FLOW_ENDPOINT_NOT_FOUND, {
|
|
5532
|
+
flow: slug,
|
|
5533
|
+
endpoint: endpoint ?? ''
|
|
5534
|
+
}, `Flow '${slug}' has no URL '${endpoint ?? ''}'.`);
|
|
5535
|
+
}
|
|
5536
|
+
await this.assertMayCall(flow, start, parent, env);
|
|
5537
|
+
const checked = (0,flow_input_validator/* .validateFlowInput */.v)(start.inputSchema, input, start.bodyType);
|
|
4920
5538
|
if (checked.errors.length) {
|
|
4921
5539
|
throw new flow_errors/* .FlowHttpError */.hk(400, 'Validation failed', checked.errors, {
|
|
4922
5540
|
messageKey: message_keys/* .FLOW_MESSAGES.INPUT_INVALID */.wu.INPUT_INVALID,
|
|
@@ -4925,22 +5543,21 @@ class FlowExecutorService {
|
|
|
4925
5543
|
}
|
|
4926
5544
|
});
|
|
4927
5545
|
}
|
|
4928
|
-
const settings = (0,flow_definition_service/* .toFlowSettings */.RK)(flow);
|
|
4929
5546
|
const child = {
|
|
5547
|
+
startAt: start.nodeId,
|
|
4930
5548
|
input: checked.values,
|
|
4931
5549
|
vars: {},
|
|
4932
5550
|
context: {},
|
|
4933
5551
|
request: parent.request,
|
|
4934
5552
|
user: parent.user,
|
|
5553
|
+
authorization: parent.authorization,
|
|
4935
5554
|
permissions: parent.permissions,
|
|
4936
5555
|
mode: parent.mode,
|
|
4937
|
-
runAs: flow.authMode === 'internal' ? parent.runAs : settings.runAs,
|
|
4938
|
-
// 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.
|
|
4939
|
-
systemAuthorized: flow.authMode === 'internal' ? parent.systemAuthorized === true : settings.runAs === 'system',
|
|
4940
5556
|
steps: parent.steps,
|
|
4941
5557
|
httpCalls: parent.httpCalls,
|
|
5558
|
+
messages: parent.messages,
|
|
4942
5559
|
writes: parent.writes,
|
|
4943
|
-
deadline: Math.min(parent.deadline, Date.now() + flowTimeout(
|
|
5560
|
+
deadline: Math.min(parent.deadline, Date.now() + flowTimeout(start.timeoutMs)),
|
|
4944
5561
|
qr: parent.qr,
|
|
4945
5562
|
callStack: [
|
|
4946
5563
|
...parent.callStack,
|
|
@@ -4955,13 +5572,14 @@ class FlowExecutorService {
|
|
|
4955
5572
|
if (child.pendingEvents === parent.pendingEvents) parent.pendingEvents.length = queued;
|
|
4956
5573
|
};
|
|
4957
5574
|
try {
|
|
4958
|
-
await this.execute(settings, child, env);
|
|
5575
|
+
await this.execute(settings, start.isTransactional, child, env);
|
|
4959
5576
|
} catch (error) {
|
|
4960
5577
|
dropQueued();
|
|
4961
5578
|
throw calledFlowFailure(flow, error);
|
|
4962
5579
|
} finally{
|
|
4963
5580
|
parent.steps = child.steps;
|
|
4964
5581
|
parent.httpCalls = child.httpCalls;
|
|
5582
|
+
parent.messages = child.messages;
|
|
4965
5583
|
parent.writes = child.writes;
|
|
4966
5584
|
}
|
|
4967
5585
|
if (child.response) {
|
|
@@ -4980,7 +5598,8 @@ class FlowExecutorService {
|
|
|
4980
5598
|
where: {
|
|
4981
5599
|
slug,
|
|
4982
5600
|
isActive: true,
|
|
4983
|
-
deletedAt: (0,external_typeorm_.IsNull)()
|
|
5601
|
+
deletedAt: (0,external_typeorm_.IsNull)(),
|
|
5602
|
+
version: (0,external_typeorm_.MoreThan)(0)
|
|
4984
5603
|
}
|
|
4985
5604
|
});
|
|
4986
5605
|
if (!flow) throw new flow_errors/* .FlowKeyedError */.Hp(message_keys/* .FLOW_ERROR_MESSAGES.CALLED_FLOW_NOT_FOUND */.zr.CALLED_FLOW_NOT_FOUND, {
|
|
@@ -4989,21 +5608,23 @@ class FlowExecutorService {
|
|
|
4989
5608
|
return flow;
|
|
4990
5609
|
}
|
|
4991
5610
|
/**
|
|
4992
|
-
*
|
|
4993
|
-
*
|
|
4994
|
-
*
|
|
4995
|
-
*/ async assertMayCall(flow, parent, env) {
|
|
4996
|
-
|
|
4997
|
-
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) {
|
|
4998
5618
|
throw new flow_errors/* .FlowKeyedError */.Hp(message_keys/* .FLOW_ERROR_MESSAGES.CALLED_FLOW_NOT_ALLOWED */.zr.CALLED_FLOW_NOT_ALLOWED, {
|
|
4999
5619
|
flow: flow.slug,
|
|
5000
|
-
authMode:
|
|
5001
|
-
}, `Flow '${flow.slug}' (${
|
|
5620
|
+
authMode: mode
|
|
5621
|
+
}, `Flow '${flow.slug}' (${mode}) cannot be called by this caller.`);
|
|
5002
5622
|
}
|
|
5003
|
-
if (
|
|
5623
|
+
if (mode === 'permission') await env.assertPermissions((0,flow_definition_service/* .flowPermissions */.j4)(endpoint, flow.slug), parent.user);
|
|
5004
5624
|
}
|
|
5005
5625
|
createEnv() {
|
|
5006
5626
|
const entityServices = new Map();
|
|
5627
|
+
/** One lookup per user for the whole run, however many steps ask. */ const access = new Map();
|
|
5007
5628
|
let permissions;
|
|
5008
5629
|
const env = {
|
|
5009
5630
|
ruleEngine: this.ruleEngine,
|
|
@@ -5022,33 +5643,52 @@ class FlowExecutorService {
|
|
|
5022
5643
|
}
|
|
5023
5644
|
return entityServices.get(entityCode);
|
|
5024
5645
|
},
|
|
5025
|
-
callFlow: (slug, input, state)=>this.callFlow(slug, input, state, env),
|
|
5646
|
+
callFlow: (slug, input, state, endpoint)=>this.callFlow(slug, input, state, env, endpoint),
|
|
5026
5647
|
atomic: (state, work)=>this.atomic(state, work),
|
|
5027
5648
|
commit: (state)=>this.commitProgress(state),
|
|
5028
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
|
+
},
|
|
5029
5667
|
publish: (eventName, payload, user)=>publishFlowEvent(eventName, payload, user),
|
|
5030
|
-
|
|
5668
|
+
assertPermissions: async (logic, user)=>{
|
|
5031
5669
|
if (!user) throw new common_.UnauthorizedException({
|
|
5032
5670
|
message: 'Authentication required',
|
|
5033
5671
|
messageKey: constants_.ERROR_MESSAGES.UNAUTHORIZED
|
|
5034
5672
|
});
|
|
5035
|
-
if (!this.permissionCache.isCacheConfigured()) throw new
|
|
5673
|
+
if (!this.permissionCache.isCacheConfigured()) throw new __rspack_external__flusys_nestjs_shared_exceptions_3edf22e9.PermissionSystemUnavailableException();
|
|
5036
5674
|
permissions ??= this.permissionCache.getPermissions({
|
|
5037
5675
|
userId: user.id,
|
|
5038
5676
|
companyId: user.companyId,
|
|
5039
5677
|
branchId: user.branchId
|
|
5040
5678
|
});
|
|
5041
|
-
const
|
|
5042
|
-
if (!
|
|
5043
|
-
code
|
|
5044
|
-
], '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);
|
|
5045
5681
|
}
|
|
5046
5682
|
};
|
|
5047
5683
|
return env;
|
|
5048
5684
|
}
|
|
5049
|
-
/** 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) {
|
|
5050
5686
|
for (const event of events){
|
|
5051
5687
|
try {
|
|
5688
|
+
if ('delivery' in event) {
|
|
5689
|
+
await event.send();
|
|
5690
|
+
continue;
|
|
5691
|
+
}
|
|
5052
5692
|
if ('eventName' in event) {
|
|
5053
5693
|
await publishFlowEvent(event.eventName, event.payload, user);
|
|
5054
5694
|
continue;
|
|
@@ -5067,6 +5707,10 @@ class FlowExecutorService {
|
|
|
5067
5707
|
user
|
|
5068
5708
|
});
|
|
5069
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
|
+
}
|
|
5070
5714
|
const name = 'eventName' in event ? event.eventName : `${event.entityCode}.${event.action}`;
|
|
5071
5715
|
this.logger.error(`Could not publish ${name}: ${error.message}`);
|
|
5072
5716
|
}
|
|
@@ -5080,13 +5724,25 @@ FlowExecutorService = _ts_decorate([
|
|
|
5080
5724
|
_ts_param(2, (0,common_.Inject)(core_.ModuleRef)),
|
|
5081
5725
|
_ts_param(3, (0,common_.Inject)(modules_.SharedPermissionCacheService)),
|
|
5082
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)),
|
|
5083
5735
|
_ts_metadata("design:type", Function),
|
|
5084
5736
|
_ts_metadata("design:paramtypes", [
|
|
5085
5737
|
typeof entity_builder_datasource_provider/* .EntityBuilderDataSourceProvider */.D === "undefined" ? Object : entity_builder_datasource_provider/* .EntityBuilderDataSourceProvider */.D,
|
|
5086
5738
|
typeof rule_engine/* .RuleEngineService */.iI === "undefined" ? Object : rule_engine/* .RuleEngineService */.iI,
|
|
5087
5739
|
typeof core_.ModuleRef === "undefined" ? Object : core_.ModuleRef,
|
|
5088
5740
|
typeof modules_.SharedPermissionCacheService === "undefined" ? Object : modules_.SharedPermissionCacheService,
|
|
5089
|
-
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
|
|
5090
5746
|
])
|
|
5091
5747
|
], FlowExecutorService);
|
|
5092
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) {
|
|
@@ -5122,13 +5778,14 @@ FlowExecutorService = _ts_decorate([
|
|
|
5122
5778
|
2300(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
5123
5779
|
/* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(6157);
|
|
5124
5780
|
/* import */ var typeorm__rspack_import_1 = __webpack_require__(7158);
|
|
5125
|
-
/* import */ var
|
|
5781
|
+
/* import */ var _config_message_keys_js__rspack_import_9 = __webpack_require__(5732);
|
|
5126
5782
|
/* import */ var _entities_flow_definition_entity_js__rspack_import_2 = __webpack_require__(3770);
|
|
5127
5783
|
/* import */ var _flow_engine_flow_input_validator_js__rspack_import_3 = __webpack_require__(6390);
|
|
5128
|
-
/* import */ var
|
|
5129
|
-
/* import */ var
|
|
5130
|
-
/* import */ var
|
|
5131
|
-
/* import */ var
|
|
5784
|
+
/* import */ var _flow_engine_flow_types_js__rspack_import_4 = __webpack_require__(6256);
|
|
5785
|
+
/* import */ var _entity_builder_datasource_provider_js__rspack_import_5 = __webpack_require__(424);
|
|
5786
|
+
/* import */ var _flow_definition_service_js__rspack_import_6 = __webpack_require__(5229);
|
|
5787
|
+
/* import */ var _flow_execution_service_js__rspack_import_7 = __webpack_require__(7810);
|
|
5788
|
+
/* import */ var _flow_executor_service_js__rspack_import_8 = __webpack_require__(3908);
|
|
5132
5789
|
function _ts_decorate(decorators, target, key, desc) {
|
|
5133
5790
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
5134
5791
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -5161,6 +5818,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
5161
5818
|
|
|
5162
5819
|
|
|
5163
5820
|
|
|
5821
|
+
|
|
5164
5822
|
const HIDDEN_HEADERS = new Set([
|
|
5165
5823
|
'authorization',
|
|
5166
5824
|
'cookie',
|
|
@@ -5197,6 +5855,11 @@ const MAX_QUERY_VALUE_LENGTH = 2000;
|
|
|
5197
5855
|
receivedAt: new Date().toISOString()
|
|
5198
5856
|
};
|
|
5199
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
|
+
}
|
|
5200
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) {
|
|
5201
5864
|
if (!simulated) return caller;
|
|
5202
5865
|
const headers = {
|
|
@@ -5219,7 +5882,7 @@ const inputRejected = (errors)=>({
|
|
|
5219
5882
|
body: {
|
|
5220
5883
|
success: false,
|
|
5221
5884
|
message: 'Validation failed',
|
|
5222
|
-
messageKey:
|
|
5885
|
+
messageKey: _config_message_keys_js__rspack_import_9/* .FLOW_MESSAGES.INPUT_INVALID */.wu.INPUT_INVALID,
|
|
5223
5886
|
errors
|
|
5224
5887
|
},
|
|
5225
5888
|
trace: [],
|
|
@@ -5236,71 +5899,75 @@ class FlowRuntimeService {
|
|
|
5236
5899
|
this.executions = executions;
|
|
5237
5900
|
this.definitions = definitions;
|
|
5238
5901
|
}
|
|
5239
|
-
/** A
|
|
5902
|
+
/** A flow never published is not live yet: it looks the same as an unknown one. */ async findActive(slug) {
|
|
5240
5903
|
return (await this.provider.getRepository(_entities_flow_definition_entity_js__rspack_import_2/* .FlowDefinition */.G)).findOne({
|
|
5241
5904
|
where: {
|
|
5242
5905
|
slug,
|
|
5243
5906
|
isActive: true,
|
|
5244
5907
|
deletedAt: (0,typeorm__rspack_import_1.IsNull)(),
|
|
5245
|
-
|
|
5908
|
+
version: (0,typeorm__rspack_import_1.MoreThan)(0)
|
|
5246
5909
|
}
|
|
5247
5910
|
});
|
|
5248
5911
|
}
|
|
5249
|
-
/** The public entry: a caller hit `POST api-flows/:slug`. */ async handle(flow, body, caller, user) {
|
|
5912
|
+
/** The public entry: a caller hit `POST api-flows/:slug` or `POST api-flows/:slug/:endpoint`. */ async handle(flow, endpoint, body, caller, user) {
|
|
5250
5913
|
const startedAt = new Date();
|
|
5251
|
-
const checked = (0,_flow_engine_flow_input_validator_js__rspack_import_3/* .validateFlowInput */.v)(
|
|
5914
|
+
const checked = (0,_flow_engine_flow_input_validator_js__rspack_import_3/* .validateFlowInput */.v)(endpoint.inputSchema, body, endpoint.bodyType);
|
|
5252
5915
|
if (checked.errors.length) {
|
|
5253
5916
|
const result = inputRejected(checked.errors);
|
|
5254
|
-
await this.logWebhook(flow, body, result, startedAt, user, caller);
|
|
5917
|
+
await this.logWebhook(flow, endpoint, body, result, startedAt, user, caller);
|
|
5255
5918
|
return result;
|
|
5256
5919
|
}
|
|
5257
|
-
|
|
5258
|
-
const result = await this.executor.run((0,_flow_definition_service_js__rspack_import_5/* .toFlowSettings */.RK)(flow), {
|
|
5920
|
+
const result = await this.executor.run((0,_flow_definition_service_js__rspack_import_6/* .toFlowSettings */.RK)(flow), {
|
|
5259
5921
|
mode: 'live',
|
|
5260
5922
|
user,
|
|
5261
5923
|
input: checked.values,
|
|
5924
|
+
startAt: endpoint.nodeId,
|
|
5262
5925
|
request: requestInfo(caller),
|
|
5263
|
-
|
|
5264
|
-
|
|
5926
|
+
authorization: callerAuthorization(caller, user),
|
|
5927
|
+
exposeDetails: false
|
|
5265
5928
|
});
|
|
5266
|
-
await this.logWebhook(flow, checked.values, result, startedAt, user, caller);
|
|
5929
|
+
await this.logWebhook(flow, endpoint, checked.values, result, startedAt, user, caller);
|
|
5267
5930
|
return result;
|
|
5268
5931
|
}
|
|
5269
5932
|
/** The designer's "Test run": a saved flow or an unsaved draft. */ async testRun(dto, user, caller) {
|
|
5270
5933
|
let settings;
|
|
5271
|
-
let permissionCode;
|
|
5272
5934
|
let flow = null;
|
|
5273
5935
|
if (dto.flowId) {
|
|
5274
5936
|
flow = await this.definitions.findOrFail(dto.flowId);
|
|
5275
5937
|
}
|
|
5276
5938
|
if (dto.definition) {
|
|
5277
5939
|
// The designer's current draft, even for a saved flow: `flow` above is kept only to attribute the run.
|
|
5278
|
-
settings = (0,
|
|
5279
|
-
permissionCode = dto.definition.permissionCode;
|
|
5940
|
+
settings = (0,_flow_definition_service_js__rspack_import_6/* .toFlowSettings */.RK)(dto.definition);
|
|
5280
5941
|
} else if (flow) {
|
|
5281
|
-
settings = (0,
|
|
5282
|
-
permissionCode = flow.permissionCode;
|
|
5942
|
+
settings = (0,_flow_definition_service_js__rspack_import_6/* .toFlowSettings */.RK)(flow);
|
|
5283
5943
|
} else {
|
|
5284
5944
|
throw new _nestjs_common__rspack_import_0.BadRequestException({
|
|
5285
5945
|
message: 'Send a flowId or a definition to test.',
|
|
5286
|
-
messageKey:
|
|
5946
|
+
messageKey: _config_message_keys_js__rspack_import_9/* .FLOW_MESSAGES.NOTHING_TO_TEST */.wu.NOTHING_TO_TEST
|
|
5287
5947
|
});
|
|
5288
5948
|
}
|
|
5289
5949
|
const mode = dto.mode ?? 'dry_run';
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
permissionCode
|
|
5294
|
-
}, 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, {
|
|
5295
5953
|
mode,
|
|
5296
5954
|
draft: !!dto.definition,
|
|
5297
5955
|
saved: !!flow
|
|
5298
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
|
+
}
|
|
5299
5966
|
const validation = await this.definitions.validate(settings);
|
|
5300
5967
|
if (validation.errors.length) {
|
|
5301
5968
|
throw new _nestjs_common__rspack_import_0.BadRequestException({
|
|
5302
5969
|
message: 'The flow has problems.',
|
|
5303
|
-
messageKey:
|
|
5970
|
+
messageKey: _config_message_keys_js__rspack_import_9/* .FLOW_MESSAGES.INVALID */.wu.INVALID,
|
|
5304
5971
|
errors: validation.errors.map((error)=>({
|
|
5305
5972
|
field: 'flow',
|
|
5306
5973
|
...error
|
|
@@ -5309,20 +5976,23 @@ class FlowRuntimeService {
|
|
|
5309
5976
|
}
|
|
5310
5977
|
const startedAt = new Date();
|
|
5311
5978
|
const simulated = simulatedCaller(caller, dto.request);
|
|
5312
|
-
const body = dto.input ?? (
|
|
5313
|
-
const checked = (0,_flow_engine_flow_input_validator_js__rspack_import_3/* .validateFlowInput */.v)(
|
|
5979
|
+
const body = dto.input ?? (endpoint.bodyType === 'list' ? [] : {});
|
|
5980
|
+
const checked = (0,_flow_engine_flow_input_validator_js__rspack_import_3/* .validateFlowInput */.v)(endpoint.inputSchema, body, endpoint.bodyType);
|
|
5314
5981
|
const result = checked.errors.length ? inputRejected(checked.errors) : await this.executor.run(settings, {
|
|
5315
5982
|
mode,
|
|
5316
5983
|
user,
|
|
5317
5984
|
input: checked.values,
|
|
5985
|
+
startAt: endpoint.nodeId,
|
|
5318
5986
|
request: requestInfo(simulated),
|
|
5319
|
-
|
|
5320
|
-
|
|
5987
|
+
authorization: callerAuthorization(caller, user),
|
|
5988
|
+
exposeDetails: true
|
|
5321
5989
|
});
|
|
5322
5990
|
await this.executions.record({
|
|
5323
5991
|
flowId: flow?.id ?? null,
|
|
5324
5992
|
flowSlug: settings.slug,
|
|
5993
|
+
flowVersion: dto.definition ? null : flow?.version ?? null,
|
|
5325
5994
|
trigger: 'test',
|
|
5995
|
+
endpoint,
|
|
5326
5996
|
mode,
|
|
5327
5997
|
input: body,
|
|
5328
5998
|
result,
|
|
@@ -5336,11 +6006,13 @@ class FlowRuntimeService {
|
|
|
5336
6006
|
warnings: validation.warnings
|
|
5337
6007
|
};
|
|
5338
6008
|
}
|
|
5339
|
-
async logWebhook(flow, input, result, startedAt, user, caller) {
|
|
6009
|
+
async logWebhook(flow, endpoint, input, result, startedAt, user, caller) {
|
|
5340
6010
|
await this.executions.record({
|
|
5341
6011
|
flowId: flow.id,
|
|
5342
6012
|
flowSlug: flow.slug,
|
|
6013
|
+
flowVersion: flow.version,
|
|
5343
6014
|
trigger: 'webhook',
|
|
6015
|
+
endpoint,
|
|
5344
6016
|
mode: 'live',
|
|
5345
6017
|
input,
|
|
5346
6018
|
result,
|
|
@@ -5355,16 +6027,16 @@ FlowRuntimeService = _ts_decorate([
|
|
|
5355
6027
|
(0,_nestjs_common__rspack_import_0.Injectable)({
|
|
5356
6028
|
scope: _nestjs_common__rspack_import_0.Scope.REQUEST
|
|
5357
6029
|
}),
|
|
5358
|
-
_ts_param(0, (0,_nestjs_common__rspack_import_0.Inject)(
|
|
5359
|
-
_ts_param(1, (0,_nestjs_common__rspack_import_0.Inject)(
|
|
5360
|
-
_ts_param(2, (0,_nestjs_common__rspack_import_0.Inject)(
|
|
5361
|
-
_ts_param(3, (0,_nestjs_common__rspack_import_0.Inject)(
|
|
6030
|
+
_ts_param(0, (0,_nestjs_common__rspack_import_0.Inject)(_entity_builder_datasource_provider_js__rspack_import_5/* .EntityBuilderDataSourceProvider */.D)),
|
|
6031
|
+
_ts_param(1, (0,_nestjs_common__rspack_import_0.Inject)(_flow_executor_service_js__rspack_import_8/* .FlowExecutorService */.F)),
|
|
6032
|
+
_ts_param(2, (0,_nestjs_common__rspack_import_0.Inject)(_flow_execution_service_js__rspack_import_7/* .FlowExecutionService */.A)),
|
|
6033
|
+
_ts_param(3, (0,_nestjs_common__rspack_import_0.Inject)(_flow_definition_service_js__rspack_import_6/* .FlowDefinitionService */.Tk)),
|
|
5362
6034
|
_ts_metadata("design:type", Function),
|
|
5363
6035
|
_ts_metadata("design:paramtypes", [
|
|
5364
|
-
typeof
|
|
5365
|
-
typeof
|
|
5366
|
-
typeof
|
|
5367
|
-
typeof
|
|
6036
|
+
typeof _entity_builder_datasource_provider_js__rspack_import_5/* .EntityBuilderDataSourceProvider */.D === "undefined" ? Object : _entity_builder_datasource_provider_js__rspack_import_5/* .EntityBuilderDataSourceProvider */.D,
|
|
6037
|
+
typeof _flow_executor_service_js__rspack_import_8/* .FlowExecutorService */.F === "undefined" ? Object : _flow_executor_service_js__rspack_import_8/* .FlowExecutorService */.F,
|
|
6038
|
+
typeof _flow_execution_service_js__rspack_import_7/* .FlowExecutionService */.A === "undefined" ? Object : _flow_execution_service_js__rspack_import_7/* .FlowExecutionService */.A,
|
|
6039
|
+
typeof _flow_definition_service_js__rspack_import_6/* .FlowDefinitionService */.Tk === "undefined" ? Object : _flow_definition_service_js__rspack_import_6/* .FlowDefinitionService */.Tk
|
|
5368
6040
|
])
|
|
5369
6041
|
], FlowRuntimeService);
|
|
5370
6042
|
|
|
@@ -5742,6 +6414,7 @@ const FILTER_COMPARISON_SQL = {
|
|
|
5742
6414
|
/** Soft-deletes the record, or deletes it for good when the entity has soft delete turned off. */ async delete(id, user, options = {}) {
|
|
5743
6415
|
this.ensureActive();
|
|
5744
6416
|
const repository = await this.ensureRepository();
|
|
6417
|
+
const soft = this.definition.isSoftDeleteEnabled;
|
|
5745
6418
|
await this.withTransaction(options, async (queryRunner)=>{
|
|
5746
6419
|
const existing = await queryRunner.manager.findOne(repository.target, {
|
|
5747
6420
|
where: {
|
|
@@ -5749,7 +6422,6 @@ const FILTER_COMPARISON_SQL = {
|
|
|
5749
6422
|
}
|
|
5750
6423
|
});
|
|
5751
6424
|
if (!existing) throw this.notFound(id);
|
|
5752
|
-
const soft = this.definition.isSoftDeleteEnabled;
|
|
5753
6425
|
if (soft) {
|
|
5754
6426
|
await queryRunner.manager.softDelete(repository.target, [
|
|
5755
6427
|
id
|
|
@@ -5775,6 +6447,7 @@ const FILTER_COMPARISON_SQL = {
|
|
|
5775
6447
|
]
|
|
5776
6448
|
};
|
|
5777
6449
|
}, user);
|
|
6450
|
+
return soft ? 'deleted' : 'purged';
|
|
5778
6451
|
}
|
|
5779
6452
|
async findById(id, options = {}) {
|
|
5780
6453
|
const repository = await this.repositoryFor(options.queryRunner);
|
|
@@ -5977,181 +6650,6 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
5977
6650
|
});
|
|
5978
6651
|
|
|
5979
6652
|
|
|
5980
|
-
},
|
|
5981
|
-
5313(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
5982
|
-
/* import */ var node_crypto__rspack_import_0 = __webpack_require__(2561);
|
|
5983
|
-
/* import */ var typeorm__rspack_import_1 = __webpack_require__(7158);
|
|
5984
|
-
/* import */ var _enums_field_type_enum_js__rspack_import_2 = __webpack_require__(9614);
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
/** Columns every dynamic table may carry (the `Identity` contract). Everything else is a designed field. */ const SYSTEM_COLUMN_NAMES = [
|
|
5989
|
-
'id',
|
|
5990
|
-
'created_at',
|
|
5991
|
-
'updated_at',
|
|
5992
|
-
'deleted_at',
|
|
5993
|
-
'created_by_id',
|
|
5994
|
-
'updated_by_id',
|
|
5995
|
-
'deleted_by_id'
|
|
5996
|
-
];
|
|
5997
|
-
/** 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 = [
|
|
5998
|
-
_enums_field_type_enum_js__rspack_import_2/* .FieldType.LONG_TEXT */.P.LONG_TEXT,
|
|
5999
|
-
_enums_field_type_enum_js__rspack_import_2/* .FieldType.JSON */.P.JSON,
|
|
6000
|
-
_enums_field_type_enum_js__rspack_import_2/* .FieldType.MULTI_SELECT */.P.MULTI_SELECT
|
|
6001
|
-
];
|
|
6002
|
-
const isIndexableFieldType = (fieldType)=>!NON_INDEXABLE_FIELD_TYPES.includes(fieldType);
|
|
6003
|
-
const uuidColumn = (name, driver, options = {})=>new typeorm__rspack_import_1.TableColumn({
|
|
6004
|
-
name,
|
|
6005
|
-
...driver === 'postgres' ? {
|
|
6006
|
-
type: 'uuid'
|
|
6007
|
-
} : {
|
|
6008
|
-
type: 'char',
|
|
6009
|
-
length: '36'
|
|
6010
|
-
},
|
|
6011
|
-
...options
|
|
6012
|
-
});
|
|
6013
|
-
function buildSystemColumns(flags, driver) {
|
|
6014
|
-
const columns = [
|
|
6015
|
-
uuidColumn('id', driver, {
|
|
6016
|
-
isPrimary: true,
|
|
6017
|
-
isGenerated: true,
|
|
6018
|
-
generationStrategy: 'uuid'
|
|
6019
|
-
}),
|
|
6020
|
-
new typeorm__rspack_import_1.TableColumn({
|
|
6021
|
-
name: 'created_at',
|
|
6022
|
-
type: 'timestamp',
|
|
6023
|
-
isNullable: false,
|
|
6024
|
-
default: 'CURRENT_TIMESTAMP'
|
|
6025
|
-
}),
|
|
6026
|
-
new typeorm__rspack_import_1.TableColumn({
|
|
6027
|
-
name: 'updated_at',
|
|
6028
|
-
type: 'timestamp',
|
|
6029
|
-
isNullable: false,
|
|
6030
|
-
default: 'CURRENT_TIMESTAMP'
|
|
6031
|
-
})
|
|
6032
|
-
];
|
|
6033
|
-
if (flags.isSoftDeleteEnabled) columns.push(softDeleteColumn());
|
|
6034
|
-
if (flags.isAuditEnabled) columns.push(...auditColumns(driver));
|
|
6035
|
-
return columns;
|
|
6036
|
-
}
|
|
6037
|
-
const softDeleteColumn = ()=>new typeorm__rspack_import_1.TableColumn({
|
|
6038
|
-
name: 'deleted_at',
|
|
6039
|
-
type: 'timestamp',
|
|
6040
|
-
isNullable: true
|
|
6041
|
-
});
|
|
6042
|
-
const auditColumns = (driver)=>[
|
|
6043
|
-
uuidColumn('created_by_id', driver, {
|
|
6044
|
-
isNullable: true
|
|
6045
|
-
}),
|
|
6046
|
-
uuidColumn('updated_by_id', driver, {
|
|
6047
|
-
isNullable: true
|
|
6048
|
-
}),
|
|
6049
|
-
uuidColumn('deleted_by_id', driver, {
|
|
6050
|
-
isNullable: true
|
|
6051
|
-
})
|
|
6052
|
-
];
|
|
6053
|
-
const sameColumns = (columnNames, expected)=>columnNames.length === expected.length && expected.every((c)=>columnNames.includes(c));
|
|
6054
|
-
const NAME_HASH_LENGTH = 8;
|
|
6055
|
-
/**
|
|
6056
|
-
* Deterministic index/constraint name within the driver's identifier limit. The hash of
|
|
6057
|
-
* `table.column` keeps names distinct when the readable part is cut short, and when two
|
|
6058
|
-
* table/column pairs would read the same (`eb_a_b` + `c` vs `eb_a` + `b_c`).
|
|
6059
|
-
*/ function indexName(prefix, table, column, maxLength) {
|
|
6060
|
-
const hash = (0,node_crypto__rspack_import_0.createHash)('sha256').update(`${table}.${column}`).digest('hex').slice(0, NAME_HASH_LENGTH);
|
|
6061
|
-
const room = maxLength - prefix.length - hash.length - 2;
|
|
6062
|
-
return `${prefix}_${`${table}_${column}`.slice(0, room)}_${hash}`;
|
|
6063
|
-
}
|
|
6064
|
-
const plainIndex = (table, column, driver, adapter)=>new typeorm__rspack_import_1.TableIndex({
|
|
6065
|
-
name: indexName('idx', table, column, adapter.maxIdentifierLength(driver)),
|
|
6066
|
-
columnNames: [
|
|
6067
|
-
column
|
|
6068
|
-
]
|
|
6069
|
-
});
|
|
6070
|
-
const tableUnique = (table, column, driver, adapter)=>new typeorm__rspack_import_1.TableUnique({
|
|
6071
|
-
name: indexName('uq', table, column, adapter.maxIdentifierLength(driver)),
|
|
6072
|
-
columnNames: [
|
|
6073
|
-
column
|
|
6074
|
-
]
|
|
6075
|
-
});
|
|
6076
|
-
/** MySQL has no unique constraints (TypeORM refuses them), only unique indexes. */ async function addUnique(qr, table, column, driver, adapter) {
|
|
6077
|
-
const name = indexName('uq', table.name, column, adapter.maxIdentifierLength(driver));
|
|
6078
|
-
if (driver === 'mysql') {
|
|
6079
|
-
await qr.createIndex(table, new typeorm__rspack_import_1.TableIndex({
|
|
6080
|
-
name,
|
|
6081
|
-
columnNames: [
|
|
6082
|
-
column
|
|
6083
|
-
],
|
|
6084
|
-
isUnique: true
|
|
6085
|
-
}));
|
|
6086
|
-
return;
|
|
6087
|
-
}
|
|
6088
|
-
await qr.createUniqueConstraint(table, new typeorm__rspack_import_1.TableUnique({
|
|
6089
|
-
name,
|
|
6090
|
-
columnNames: [
|
|
6091
|
-
column
|
|
6092
|
-
]
|
|
6093
|
-
}));
|
|
6094
|
-
}
|
|
6095
|
-
/** The stored column type, with a `uuid` stored before MySQL support became char(36) resolved to what MySQL accepts. */ function columnType(field, driver, adapter) {
|
|
6096
|
-
const type = field.dbType || adapter.mapFieldType(field.fieldType, driver);
|
|
6097
|
-
return driver === 'mysql' && type === 'uuid' ? 'char' : type;
|
|
6098
|
-
}
|
|
6099
|
-
/**
|
|
6100
|
-
* Column for a field. `enforceNotNull` controls whether the DB column is NOT NULL: true when
|
|
6101
|
-
* the table is brand new (no rows can violate it); false when adding to a table that already
|
|
6102
|
-
* has rows (the NOT NULL is applied afterwards, once the column has been backfilled).
|
|
6103
|
-
*/ function buildFieldColumn(field, driver, adapter, options) {
|
|
6104
|
-
const sizing = adapter.getColumnSizing(field.fieldType, driver);
|
|
6105
|
-
return new typeorm__rspack_import_1.TableColumn({
|
|
6106
|
-
name: field.code,
|
|
6107
|
-
type: columnType(field, driver, adapter),
|
|
6108
|
-
length: sizing.length,
|
|
6109
|
-
precision: sizing.precision ?? undefined,
|
|
6110
|
-
scale: sizing.scale,
|
|
6111
|
-
isNullable: options.enforceNotNull ? field.nullable : true,
|
|
6112
|
-
isUnique: options.withUnique ? field.unique : false
|
|
6113
|
-
});
|
|
6114
|
-
}
|
|
6115
|
-
/** 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) {
|
|
6116
|
-
const base = adapter.mapFieldType(fieldType, driver);
|
|
6117
|
-
const sizing = adapter.getColumnSizing(fieldType, driver);
|
|
6118
|
-
if (sizing.length) return `${base}(${sizing.length})`;
|
|
6119
|
-
if (sizing.precision !== undefined) return `${base}(${sizing.precision},${sizing.scale ?? 0})`;
|
|
6120
|
-
return base;
|
|
6121
|
-
}
|
|
6122
|
-
/** Coarse type family, so `character varying` (pg) and `varchar` (mysql) compare equal. */ function typeFamily(type) {
|
|
6123
|
-
const t = type.toLowerCase();
|
|
6124
|
-
if (t === 'uuid') return 'uuid';
|
|
6125
|
-
if (t.includes('json')) return 'json';
|
|
6126
|
-
if (t.includes('timestamp') || t === 'datetime') return 'timestamp';
|
|
6127
|
-
if (t === 'date') return 'date';
|
|
6128
|
-
if (t.includes('bool') || t === 'tinyint') return 'boolean';
|
|
6129
|
-
if (t.includes('int') && !t.includes('point')) return 'integer';
|
|
6130
|
-
if (t.includes('numeric') || t.includes('decimal')) return 'numeric';
|
|
6131
|
-
if (t.includes('char') || t === 'varchar') return 'varchar';
|
|
6132
|
-
if (t.includes('text')) return 'text';
|
|
6133
|
-
return t;
|
|
6134
|
-
}
|
|
6135
|
-
|
|
6136
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
6137
|
-
$6: () => (addUnique),
|
|
6138
|
-
Rm: () => (buildSystemColumns),
|
|
6139
|
-
cg: () => (sqlTypeFor),
|
|
6140
|
-
fu: () => (buildFieldColumn),
|
|
6141
|
-
jp: () => (typeFamily),
|
|
6142
|
-
mo: () => (indexName)
|
|
6143
|
-
}, {
|
|
6144
|
-
G7: sameColumns,
|
|
6145
|
-
HK: auditColumns,
|
|
6146
|
-
OG: softDeleteColumn,
|
|
6147
|
-
d4: isIndexableFieldType,
|
|
6148
|
-
gW: NON_INDEXABLE_FIELD_TYPES,
|
|
6149
|
-
mq: SYSTEM_COLUMN_NAMES,
|
|
6150
|
-
uy: tableUnique,
|
|
6151
|
-
v7: plainIndex
|
|
6152
|
-
});
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
6653
|
},
|
|
6156
6654
|
7259(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
6157
6655
|
/* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(6157);
|