@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.
Files changed (63) hide show
  1. package/README.md +52 -23
  2. package/config/entity-builder.constants.d.ts +2 -0
  3. package/config/message-keys.d.ts +102 -13
  4. package/controllers/definition-bundle.controller.d.ts +15 -0
  5. package/controllers/flow-definition.controller.d.ts +7 -1
  6. package/controllers/flow-runtime.controller.d.ts +16 -8
  7. package/controllers/index.d.ts +1 -1
  8. package/dtos/definition-bundle.dto.d.ts +57 -0
  9. package/dtos/flow.dto.d.ts +13 -20
  10. package/dtos/index.d.ts +1 -0
  11. package/entities/flow-definition.entity.d.ts +3 -9
  12. package/entities/flow-execution.entity.d.ts +3 -0
  13. package/entities/flow-version.entity.d.ts +10 -0
  14. package/entities/index.d.ts +3 -3
  15. package/fesm/21.js +105 -15
  16. package/fesm/458.js +695 -0
  17. package/fesm/{489.js → 582.js} +22 -30
  18. package/fesm/{996.js → 677.js} +1562 -1064
  19. package/fesm/794.js +135 -240
  20. package/fesm/{719.js → 870.js} +2065 -324
  21. package/fesm/{362.js → 897.js} +572 -8
  22. package/fesm/{606.js → 946.js} +621 -296
  23. package/fesm/config/index.js +15 -2
  24. package/fesm/controllers/index.js +9 -9
  25. package/fesm/docs/index.js +7 -4
  26. package/fesm/dtos/index.js +451 -256
  27. package/fesm/entities/index.js +58 -3
  28. package/fesm/guards/index.js +106 -22
  29. package/fesm/index.js +429 -937
  30. package/fesm/interfaces/index.js +19 -2
  31. package/fesm/modules/index.js +10 -627
  32. package/fesm/rule-engine/index.js +12 -3
  33. package/fesm/services/index.js +101 -29
  34. package/flow-engine/flow-api-key.d.ts +3 -7
  35. package/flow-engine/flow-graph.validator.d.ts +5 -4
  36. package/flow-engine/flow-permission-logic.d.ts +2 -0
  37. package/flow-engine/flow-run.types.d.ts +19 -9
  38. package/flow-engine/flow.types.d.ts +115 -11
  39. package/guards/designer-writable.interceptor.d.ts +12 -0
  40. package/guards/index.d.ts +1 -0
  41. package/interfaces/definition-bundle.interface.d.ts +111 -0
  42. package/interfaces/entity-builder-module.interface.d.ts +6 -0
  43. package/interfaces/flow-definition.interface.d.ts +13 -9
  44. package/interfaces/index.d.ts +1 -0
  45. package/package.json +5 -5
  46. package/rule-engine/rule-engine.service.d.ts +1 -0
  47. package/rule-engine/rule-permission.d.ts +3 -7
  48. package/services/definition-bundle.diff.d.ts +62 -0
  49. package/services/definition-bundle.file.d.ts +7 -0
  50. package/services/definition-bundle.service.d.ts +32 -0
  51. package/services/entity-builder-config.service.d.ts +2 -0
  52. package/services/entity-flow-scaffold.d.ts +4 -3
  53. package/services/flow-definition.service.d.ts +26 -12
  54. package/services/flow-execution.service.d.ts +7 -0
  55. package/services/flow-executor.service.d.ts +9 -8
  56. package/services/flow-runtime.service.d.ts +2 -1
  57. package/services/generic-entity.service.d.ts +1 -1
  58. package/services/index.d.ts +3 -1
  59. package/services/schema-evolution.service.d.ts +3 -1
  60. package/services/schema-sync.service.d.ts +6 -2
  61. package/controllers/flow-api-key.controller.d.ts +0 -14
  62. package/entities/flow-api-key.entity.d.ts +0 -10
  63. package/services/flow-api-key.service.d.ts +0 -31
@@ -1,12 +1,1715 @@
1
- export const __rspack_esm_id = 719;
2
- export const __rspack_esm_ids = [719];
1
+ export const __rspack_esm_id = 870;
2
+ export const __rspack_esm_ids = [870];
3
3
  export const __webpack_modules__ = {
4
+ 6691(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
5
+ /* import */ var _nestjs_swagger__rspack_import_0 = __webpack_require__(6176);
6
+ /* import */ var class_transformer__rspack_import_1 = __webpack_require__(5812);
7
+ /* import */ var class_validator__rspack_import_2 = __webpack_require__(5421);
8
+ /* import */ var _config_entity_builder_constants_js__rspack_import_4 = __webpack_require__(6576);
9
+ /* import */ var _enums_entity_status_enum_js__rspack_import_6 = __webpack_require__(1313);
10
+ /* import */ var _enums_field_type_enum_js__rspack_import_5 = __webpack_require__(9614);
11
+ /* import */ var _flow_engine_flow_types_js__rspack_import_3 = __webpack_require__(6256);
12
+ /* import */ var _interfaces_definition_bundle_interface_js__rspack_import_7 = __webpack_require__(8835);
13
+ function _ts_decorate(decorators, target, key, desc) {
14
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
15
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
16
+ r = Reflect.decorate(decorators, target, key, desc);
17
+ } else {
18
+ for(var i = decorators.length - 1; i >= 0; i--){
19
+ if (d = decorators[i]) {
20
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
21
+ }
22
+ }
23
+ }
24
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
25
+ }
26
+ function _ts_metadata(metadataKey, metadataValue) {
27
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
28
+ return Reflect.metadata(metadataKey, metadataValue);
29
+ }
30
+ }
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+ const Nullable = ()=>(0,class_validator__rspack_import_2.ValidateIf)((_object, value)=>value !== null);
40
+ class BundleFieldDto {
41
+ id;
42
+ code;
43
+ label;
44
+ fieldType;
45
+ nullable;
46
+ unique;
47
+ isIndexed;
48
+ defaultValue;
49
+ validationRules;
50
+ selectOptions;
51
+ relationTarget;
52
+ order;
53
+ uiConfig;
54
+ isSearchable;
55
+ deprecated;
56
+ }
57
+ _ts_decorate([
58
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)(),
59
+ (0,class_validator__rspack_import_2.IsUUID)(),
60
+ _ts_metadata("design:type", String)
61
+ ], BundleFieldDto.prototype, "id", void 0);
62
+ _ts_decorate([
63
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)(),
64
+ (0,class_validator__rspack_import_2.IsString)(),
65
+ (0,class_validator__rspack_import_2.MaxLength)((/* inlined export .ENTITY_CODE_MAX_LENGTH */63)),
66
+ (0,class_validator__rspack_import_2.Matches)(_config_entity_builder_constants_js__rspack_import_4/* .ENTITY_CODE_PATTERN */.vs),
67
+ _ts_metadata("design:type", String)
68
+ ], BundleFieldDto.prototype, "code", void 0);
69
+ _ts_decorate([
70
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)(),
71
+ (0,class_validator__rspack_import_2.IsString)(),
72
+ (0,class_validator__rspack_import_2.IsNotEmpty)(),
73
+ (0,class_validator__rspack_import_2.MaxLength)(255),
74
+ _ts_metadata("design:type", String)
75
+ ], BundleFieldDto.prototype, "label", void 0);
76
+ _ts_decorate([
77
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)({
78
+ enum: _enums_field_type_enum_js__rspack_import_5/* .FieldType */.P
79
+ }),
80
+ (0,class_validator__rspack_import_2.IsEnum)(_enums_field_type_enum_js__rspack_import_5/* .FieldType */.P),
81
+ _ts_metadata("design:type", typeof _enums_field_type_enum_js__rspack_import_5/* .FieldType */.P === "undefined" ? Object : _enums_field_type_enum_js__rspack_import_5/* .FieldType */.P)
82
+ ], BundleFieldDto.prototype, "fieldType", void 0);
83
+ _ts_decorate([
84
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)(),
85
+ (0,class_validator__rspack_import_2.IsBoolean)(),
86
+ _ts_metadata("design:type", Boolean)
87
+ ], BundleFieldDto.prototype, "nullable", void 0);
88
+ _ts_decorate([
89
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)(),
90
+ (0,class_validator__rspack_import_2.IsBoolean)(),
91
+ _ts_metadata("design:type", Boolean)
92
+ ], BundleFieldDto.prototype, "unique", void 0);
93
+ _ts_decorate([
94
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)(),
95
+ (0,class_validator__rspack_import_2.IsBoolean)(),
96
+ _ts_metadata("design:type", Boolean)
97
+ ], BundleFieldDto.prototype, "isIndexed", void 0);
98
+ _ts_decorate([
99
+ (0,_nestjs_swagger__rspack_import_0.ApiPropertyOptional)(),
100
+ (0,class_validator__rspack_import_2.Allow)(),
101
+ _ts_metadata("design:type", Object)
102
+ ], BundleFieldDto.prototype, "defaultValue", void 0);
103
+ _ts_decorate([
104
+ (0,_nestjs_swagger__rspack_import_0.ApiPropertyOptional)({
105
+ type: Object,
106
+ nullable: true
107
+ }),
108
+ Nullable(),
109
+ (0,class_validator__rspack_import_2.IsObject)(),
110
+ _ts_metadata("design:type", Object)
111
+ ], BundleFieldDto.prototype, "validationRules", void 0);
112
+ _ts_decorate([
113
+ (0,_nestjs_swagger__rspack_import_0.ApiPropertyOptional)({
114
+ type: [
115
+ Object
116
+ ],
117
+ nullable: true
118
+ }),
119
+ Nullable(),
120
+ (0,class_validator__rspack_import_2.IsArray)(),
121
+ _ts_metadata("design:type", Object)
122
+ ], BundleFieldDto.prototype, "selectOptions", void 0);
123
+ _ts_decorate([
124
+ (0,_nestjs_swagger__rspack_import_0.ApiPropertyOptional)({
125
+ description: 'Code of the entity a RELATION field points to',
126
+ nullable: true
127
+ }),
128
+ Nullable(),
129
+ (0,class_validator__rspack_import_2.IsString)(),
130
+ (0,class_validator__rspack_import_2.Matches)(_config_entity_builder_constants_js__rspack_import_4/* .ENTITY_CODE_PATTERN */.vs),
131
+ _ts_metadata("design:type", Object)
132
+ ], BundleFieldDto.prototype, "relationTarget", void 0);
133
+ _ts_decorate([
134
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)(),
135
+ (0,class_validator__rspack_import_2.IsInt)(),
136
+ (0,class_validator__rspack_import_2.Min)(0),
137
+ _ts_metadata("design:type", Number)
138
+ ], BundleFieldDto.prototype, "order", void 0);
139
+ _ts_decorate([
140
+ (0,_nestjs_swagger__rspack_import_0.ApiPropertyOptional)({
141
+ type: Object,
142
+ nullable: true
143
+ }),
144
+ Nullable(),
145
+ (0,class_validator__rspack_import_2.IsObject)(),
146
+ _ts_metadata("design:type", Object)
147
+ ], BundleFieldDto.prototype, "uiConfig", void 0);
148
+ _ts_decorate([
149
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)(),
150
+ (0,class_validator__rspack_import_2.IsBoolean)(),
151
+ _ts_metadata("design:type", Boolean)
152
+ ], BundleFieldDto.prototype, "isSearchable", void 0);
153
+ _ts_decorate([
154
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)(),
155
+ (0,class_validator__rspack_import_2.IsBoolean)(),
156
+ _ts_metadata("design:type", Boolean)
157
+ ], BundleFieldDto.prototype, "deprecated", void 0);
158
+ class BundleEntityDto {
159
+ id;
160
+ code;
161
+ label;
162
+ description;
163
+ status;
164
+ isSoftDeleteEnabled;
165
+ isAuditEnabled;
166
+ uiConfig;
167
+ fields;
168
+ }
169
+ _ts_decorate([
170
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)(),
171
+ (0,class_validator__rspack_import_2.IsUUID)(),
172
+ _ts_metadata("design:type", String)
173
+ ], BundleEntityDto.prototype, "id", void 0);
174
+ _ts_decorate([
175
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)(),
176
+ (0,class_validator__rspack_import_2.IsString)(),
177
+ (0,class_validator__rspack_import_2.MaxLength)((/* inlined export .ENTITY_CODE_MAX_LENGTH */63)),
178
+ (0,class_validator__rspack_import_2.Matches)(_config_entity_builder_constants_js__rspack_import_4/* .ENTITY_CODE_PATTERN */.vs),
179
+ _ts_metadata("design:type", String)
180
+ ], BundleEntityDto.prototype, "code", void 0);
181
+ _ts_decorate([
182
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)(),
183
+ (0,class_validator__rspack_import_2.IsString)(),
184
+ (0,class_validator__rspack_import_2.IsNotEmpty)(),
185
+ (0,class_validator__rspack_import_2.MaxLength)(255),
186
+ _ts_metadata("design:type", String)
187
+ ], BundleEntityDto.prototype, "label", void 0);
188
+ _ts_decorate([
189
+ (0,_nestjs_swagger__rspack_import_0.ApiPropertyOptional)({
190
+ nullable: true
191
+ }),
192
+ Nullable(),
193
+ (0,class_validator__rspack_import_2.IsString)(),
194
+ (0,class_validator__rspack_import_2.MaxLength)(500),
195
+ _ts_metadata("design:type", Object)
196
+ ], BundleEntityDto.prototype, "description", void 0);
197
+ _ts_decorate([
198
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)({
199
+ enum: _enums_entity_status_enum_js__rspack_import_6/* .EntityStatus */.c
200
+ }),
201
+ (0,class_validator__rspack_import_2.IsEnum)(_enums_entity_status_enum_js__rspack_import_6/* .EntityStatus */.c),
202
+ _ts_metadata("design:type", typeof _enums_entity_status_enum_js__rspack_import_6/* .EntityStatus */.c === "undefined" ? Object : _enums_entity_status_enum_js__rspack_import_6/* .EntityStatus */.c)
203
+ ], BundleEntityDto.prototype, "status", void 0);
204
+ _ts_decorate([
205
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)(),
206
+ (0,class_validator__rspack_import_2.IsBoolean)(),
207
+ _ts_metadata("design:type", Boolean)
208
+ ], BundleEntityDto.prototype, "isSoftDeleteEnabled", void 0);
209
+ _ts_decorate([
210
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)(),
211
+ (0,class_validator__rspack_import_2.IsBoolean)(),
212
+ _ts_metadata("design:type", Boolean)
213
+ ], BundleEntityDto.prototype, "isAuditEnabled", void 0);
214
+ _ts_decorate([
215
+ (0,_nestjs_swagger__rspack_import_0.ApiPropertyOptional)({
216
+ type: Object,
217
+ nullable: true
218
+ }),
219
+ Nullable(),
220
+ (0,class_validator__rspack_import_2.IsObject)(),
221
+ _ts_metadata("design:type", Object)
222
+ ], BundleEntityDto.prototype, "uiConfig", void 0);
223
+ _ts_decorate([
224
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)({
225
+ type: [
226
+ BundleFieldDto
227
+ ]
228
+ }),
229
+ (0,class_validator__rspack_import_2.IsArray)(),
230
+ (0,class_validator__rspack_import_2.ValidateNested)({
231
+ each: true
232
+ }),
233
+ (0,class_transformer__rspack_import_1.Type)(()=>BundleFieldDto),
234
+ _ts_metadata("design:type", Array)
235
+ ], BundleEntityDto.prototype, "fields", void 0);
236
+ class BundleFlowDto {
237
+ name;
238
+ slug;
239
+ description;
240
+ isActive;
241
+ retainExecutions;
242
+ nodes;
243
+ edges;
244
+ }
245
+ _ts_decorate([
246
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)(),
247
+ (0,class_validator__rspack_import_2.IsString)(),
248
+ (0,class_validator__rspack_import_2.IsNotEmpty)(),
249
+ (0,class_validator__rspack_import_2.MaxLength)(255),
250
+ _ts_metadata("design:type", String)
251
+ ], BundleFlowDto.prototype, "name", void 0);
252
+ _ts_decorate([
253
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)(),
254
+ (0,class_validator__rspack_import_2.IsString)(),
255
+ (0,class_validator__rspack_import_2.Matches)(_flow_engine_flow_types_js__rspack_import_3/* .FLOW_SLUG_PATTERN */.YD),
256
+ _ts_metadata("design:type", String)
257
+ ], BundleFlowDto.prototype, "slug", void 0);
258
+ _ts_decorate([
259
+ (0,_nestjs_swagger__rspack_import_0.ApiPropertyOptional)({
260
+ nullable: true
261
+ }),
262
+ Nullable(),
263
+ (0,class_validator__rspack_import_2.IsString)(),
264
+ (0,class_validator__rspack_import_2.MaxLength)(500),
265
+ _ts_metadata("design:type", Object)
266
+ ], BundleFlowDto.prototype, "description", void 0);
267
+ _ts_decorate([
268
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)(),
269
+ (0,class_validator__rspack_import_2.IsBoolean)(),
270
+ _ts_metadata("design:type", Boolean)
271
+ ], BundleFlowDto.prototype, "isActive", void 0);
272
+ _ts_decorate([
273
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)(),
274
+ (0,class_validator__rspack_import_2.IsInt)(),
275
+ (0,class_validator__rspack_import_2.Min)(0),
276
+ (0,class_validator__rspack_import_2.Max)(10000),
277
+ _ts_metadata("design:type", Number)
278
+ ], BundleFlowDto.prototype, "retainExecutions", void 0);
279
+ _ts_decorate([
280
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)({
281
+ type: [
282
+ Object
283
+ ]
284
+ }),
285
+ (0,class_validator__rspack_import_2.IsArray)(),
286
+ (0,class_validator__rspack_import_2.IsObject)({
287
+ each: true
288
+ }),
289
+ _ts_metadata("design:type", Array)
290
+ ], BundleFlowDto.prototype, "nodes", void 0);
291
+ _ts_decorate([
292
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)({
293
+ type: [
294
+ Object
295
+ ]
296
+ }),
297
+ (0,class_validator__rspack_import_2.IsArray)(),
298
+ (0,class_validator__rspack_import_2.IsObject)({
299
+ each: true
300
+ }),
301
+ _ts_metadata("design:type", Array)
302
+ ], BundleFlowDto.prototype, "edges", void 0);
303
+ class DefinitionBundleDto {
304
+ format;
305
+ version;
306
+ entities;
307
+ flows;
308
+ }
309
+ _ts_decorate([
310
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)({
311
+ example: _interfaces_definition_bundle_interface_js__rspack_import_7/* .DEFINITION_BUNDLE_FORMAT */.D
312
+ }),
313
+ (0,class_validator__rspack_import_2.Equals)(_interfaces_definition_bundle_interface_js__rspack_import_7/* .DEFINITION_BUNDLE_FORMAT */.D),
314
+ _ts_metadata("design:type", Object)
315
+ ], DefinitionBundleDto.prototype, "format", void 0);
316
+ _ts_decorate([
317
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)({
318
+ example: (/* inlined export .DEFINITION_BUNDLE_VERSION */1)
319
+ }),
320
+ (0,class_validator__rspack_import_2.Equals)((/* inlined export .DEFINITION_BUNDLE_VERSION */1)),
321
+ _ts_metadata("design:type", Object)
322
+ ], DefinitionBundleDto.prototype, "version", void 0);
323
+ _ts_decorate([
324
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)({
325
+ type: [
326
+ BundleEntityDto
327
+ ]
328
+ }),
329
+ (0,class_validator__rspack_import_2.IsArray)(),
330
+ (0,class_validator__rspack_import_2.ValidateNested)({
331
+ each: true
332
+ }),
333
+ (0,class_transformer__rspack_import_1.Type)(()=>BundleEntityDto),
334
+ _ts_metadata("design:type", Array)
335
+ ], DefinitionBundleDto.prototype, "entities", void 0);
336
+ _ts_decorate([
337
+ (0,_nestjs_swagger__rspack_import_0.ApiProperty)({
338
+ type: [
339
+ BundleFlowDto
340
+ ]
341
+ }),
342
+ (0,class_validator__rspack_import_2.IsArray)(),
343
+ (0,class_validator__rspack_import_2.ValidateNested)({
344
+ each: true
345
+ }),
346
+ (0,class_transformer__rspack_import_1.Type)(()=>BundleFlowDto),
347
+ _ts_metadata("design:type", Array)
348
+ ], DefinitionBundleDto.prototype, "flows", void 0);
349
+ class ExportBundleDto {
350
+ entityCodes;
351
+ flowSlugs;
352
+ }
353
+ _ts_decorate([
354
+ (0,_nestjs_swagger__rspack_import_0.ApiPropertyOptional)({
355
+ type: [
356
+ String
357
+ ],
358
+ description: 'Entity codes to export (all when left out)'
359
+ }),
360
+ (0,class_validator__rspack_import_2.IsOptional)(),
361
+ (0,class_validator__rspack_import_2.IsArray)(),
362
+ (0,class_validator__rspack_import_2.ArrayUnique)(),
363
+ (0,class_validator__rspack_import_2.IsString)({
364
+ each: true
365
+ }),
366
+ _ts_metadata("design:type", Array)
367
+ ], ExportBundleDto.prototype, "entityCodes", void 0);
368
+ _ts_decorate([
369
+ (0,_nestjs_swagger__rspack_import_0.ApiPropertyOptional)({
370
+ type: [
371
+ String
372
+ ],
373
+ description: 'Flow slugs to export (every published flow when left out)'
374
+ }),
375
+ (0,class_validator__rspack_import_2.IsOptional)(),
376
+ (0,class_validator__rspack_import_2.IsArray)(),
377
+ (0,class_validator__rspack_import_2.ArrayUnique)(),
378
+ (0,class_validator__rspack_import_2.IsString)({
379
+ each: true
380
+ }),
381
+ _ts_metadata("design:type", Array)
382
+ ], ExportBundleDto.prototype, "flowSlugs", void 0);
383
+ /** Form values arrive as text: `true` / `false` become booleans, anything else is left for the validator to refuse. */ const FormBoolean = ()=>(0,class_transformer__rspack_import_1.Transform)(({ value })=>value === 'true' ? true : value === 'false' ? false : value);
384
+ /** The form fields sent with the bundle file to plan-import / apply-import. */ class ImportBundleOptionsDto {
385
+ deprecateMissingFields;
386
+ confirm;
387
+ expectedChecksum;
388
+ expectedPlanChecksum;
389
+ }
390
+ _ts_decorate([
391
+ (0,_nestjs_swagger__rspack_import_0.ApiPropertyOptional)({
392
+ description: 'Deprecate fields this environment has and the bundle does not (their columns and data stay)',
393
+ default: false
394
+ }),
395
+ (0,class_validator__rspack_import_2.IsOptional)(),
396
+ FormBoolean(),
397
+ (0,class_validator__rspack_import_2.IsBoolean)(),
398
+ _ts_metadata("design:type", Boolean)
399
+ ], ImportBundleOptionsDto.prototype, "deprecateMissingFields", void 0);
400
+ _ts_decorate([
401
+ (0,_nestjs_swagger__rspack_import_0.ApiPropertyOptional)({
402
+ description: 'apply-import: acknowledge steps that lose (or may lose) data',
403
+ default: false
404
+ }),
405
+ (0,class_validator__rspack_import_2.IsOptional)(),
406
+ FormBoolean(),
407
+ (0,class_validator__rspack_import_2.IsBoolean)(),
408
+ _ts_metadata("design:type", Boolean)
409
+ ], ImportBundleOptionsDto.prototype, "confirm", void 0);
410
+ _ts_decorate([
411
+ (0,_nestjs_swagger__rspack_import_0.ApiPropertyOptional)({
412
+ description: 'apply-import: the checksum of the bundle that was reviewed; a different bundle is refused'
413
+ }),
414
+ (0,class_validator__rspack_import_2.IsOptional)(),
415
+ (0,class_validator__rspack_import_2.IsString)(),
416
+ (0,class_validator__rspack_import_2.Matches)(/^[0-9a-f]{64}$/),
417
+ _ts_metadata("design:type", String)
418
+ ], ImportBundleOptionsDto.prototype, "expectedChecksum", void 0);
419
+ _ts_decorate([
420
+ (0,_nestjs_swagger__rspack_import_0.ApiPropertyOptional)({
421
+ description: 'apply-import: the planChecksum of the plan that was reviewed; a changed plan is refused, and it is required with confirm'
422
+ }),
423
+ (0,class_validator__rspack_import_2.IsOptional)(),
424
+ (0,class_validator__rspack_import_2.IsString)(),
425
+ (0,class_validator__rspack_import_2.Matches)(/^[0-9a-f]{64}$/),
426
+ _ts_metadata("design:type", String)
427
+ ], ImportBundleOptionsDto.prototype, "expectedPlanChecksum", void 0);
428
+
429
+ __webpack_require__.d(__webpack_exports__, {
430
+ JE: () => (DefinitionBundleDto),
431
+ KH: () => (BundleFlowDto),
432
+ QJ: () => (ExportBundleDto),
433
+ U3: () => (BundleFieldDto),
434
+ hX: () => (BundleEntityDto),
435
+ vS: () => (ImportBundleOptionsDto)
436
+ });
437
+
438
+
439
+ },
440
+ 8835(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
441
+ const DEFINITION_BUNDLE_FORMAT = 'flusys.entity-builder.bundle';
442
+ const DEFINITION_BUNDLE_VERSION = 1;
443
+
444
+ __webpack_require__.d(__webpack_exports__, {
445
+ }, {
446
+ D: DEFINITION_BUNDLE_FORMAT
447
+ });
448
+
449
+
450
+ },
4
451
  2492(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
5
452
  const FLOW_REFERENCE_PROVIDER = 'FLOW_REFERENCE_PROVIDER';
6
453
 
7
454
  __webpack_require__.d(__webpack_exports__, {
8
- }, {
9
- $: FLOW_REFERENCE_PROVIDER
455
+ }, {
456
+ $: FLOW_REFERENCE_PROVIDER
457
+ });
458
+
459
+
460
+ },
461
+ 3801(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
462
+ /* import */ var _flusys_nestjs_shared_utils__rspack_import_0 = __webpack_require__(9216);
463
+ /* import */ var node_crypto__rspack_import_1 = __webpack_require__(2561);
464
+ /* import */ var _config_message_keys_js__rspack_import_2 = __webpack_require__(5732);
465
+ /* import */ var _enums_entity_status_enum_js__rspack_import_3 = __webpack_require__(1313);
466
+ /* import */ var _enums_field_type_enum_js__rspack_import_4 = __webpack_require__(9614);
467
+
468
+
469
+
470
+
471
+
472
+ /** JSON with object keys sorted at every level: equal definitions always give the same text. */ function canonicalJson(value) {
473
+ return JSON.stringify(sortKeys(value));
474
+ }
475
+ function sortKeys(value) {
476
+ if (Array.isArray(value)) return value.map(sortKeys);
477
+ if (value && typeof value === 'object' && !(value instanceof Date)) {
478
+ return Object.fromEntries(Object.keys(value).toSorted().filter((key)=>value[key] !== undefined).map((key)=>[
479
+ key,
480
+ sortKeys(value[key])
481
+ ]));
482
+ }
483
+ return value;
484
+ }
485
+ const same = (a, b)=>canonicalJson(a ?? null) === canonicalJson(b ?? null);
486
+ /** Code-point order: the same in every locale, so exports and plans read the same everywhere. */ const byCode = (a, b)=>a < b ? -1 : a > b ? 1 : 0;
487
+ /** What a step, extra or result is about: the flow slug, `entity.field` or the entity code. */ const bundleSubject = (item)=>item.flowSlug ?? (item.fieldCode ? `${item.entityCode}.${item.fieldCode}` : item.entityCode ?? '');
488
+ const bundleChecksum = (bundle)=>(0,node_crypto__rspack_import_1.createHash)('sha256').update(canonicalJson(bundle)).digest('hex');
489
+ // ── flows: API keys and environment variables ─────────────────────────────────────────
490
+ /** Request steps without their API keys: a key belongs to one environment and is never promoted. */ function stripApiKeys(nodes) {
491
+ return nodes.map((node)=>{
492
+ if (node?.type !== 'trigger' || node.config?.['apiKey'] === undefined) return node;
493
+ const { apiKey: _apiKey, ...config } = node.config;
494
+ return {
495
+ ...node,
496
+ config
497
+ };
498
+ });
499
+ }
500
+ const VARIABLE_PATTERN = /\$\{var:([A-Za-z_][A-Za-z0-9_]*)\}/g;
501
+ /** Shorter values would be replaced inside unrelated text. */ const MIN_VARIABLE_VALUE_LENGTH = 4;
502
+ function mapStrings(value, fn) {
503
+ if (typeof value === 'string') return fn(value);
504
+ if (Array.isArray(value)) return value.map((item)=>mapStrings(item, fn));
505
+ if (value && typeof value === 'object') {
506
+ return Object.fromEntries(Object.entries(value).map(([key, item])=>[
507
+ key,
508
+ mapStrings(item, fn)
509
+ ]));
510
+ }
511
+ return value;
512
+ }
513
+ /** Only a step's settings hold environment values: its id, type, name and position are never rewritten. */ const mapConfigStrings = (nodes, fn)=>nodes.map((node)=>node?.config ? {
514
+ ...node,
515
+ config: mapStrings(node.config, fn)
516
+ } : node);
517
+ const escapeRegExp = (text)=>text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
518
+ /**
519
+ * Export: every occurrence of this environment's variable values in a step's settings becomes `${var:NAME}`
520
+ * (longest value first; one pass, so a placeholder already written is never rewritten by a shorter value).
521
+ */ function extractVariables(nodes, variables) {
522
+ const nameOf = new Map();
523
+ for (const [name, value] of Object.entries(variables).filter(([, text])=>typeof text === 'string' && text.length >= MIN_VARIABLE_VALUE_LENGTH).toSorted(([nameA, a], [nameB, b])=>b.length - a.length || byCode(nameA, nameB))){
524
+ if (!nameOf.has(value)) nameOf.set(value, name);
525
+ }
526
+ if (!nameOf.size) return nodes;
527
+ const pattern = new RegExp([
528
+ ...nameOf.keys()
529
+ ].map(escapeRegExp).join('|'), 'g');
530
+ return mapConfigStrings(nodes, (text)=>text.replace(pattern, (value)=>`\${var:${nameOf.get(value)}}`));
531
+ }
532
+ /** Import: `${var:NAME}` in a step's settings becomes this environment's value; names it does not define are returned, not replaced. */ function applyVariables(nodes, variables) {
533
+ const missing = new Set();
534
+ const resolved = mapConfigStrings(nodes, (text)=>text.replace(VARIABLE_PATTERN, (token, name)=>{
535
+ if (typeof variables[name] === 'string') return variables[name];
536
+ missing.add(name);
537
+ return token;
538
+ }));
539
+ return {
540
+ nodes: resolved,
541
+ missing: [
542
+ ...missing
543
+ ].toSorted(byCode)
544
+ };
545
+ }
546
+ /** Slugs the Call flow steps of a flow run. */ function calledFlowSlugs(nodes) {
547
+ return nodes.filter((node)=>node?.type === 'call_flow' && typeof node.config?.['flowSlug'] === 'string').map((node)=>node.config['flowSlug']);
548
+ }
549
+ /** Called flows before their callers, so each Call flow step finds its flow published; otherwise by slug. */ function orderFlows(flows) {
550
+ const bySlug = new Map(flows.map((flow)=>[
551
+ flow.slug,
552
+ flow
553
+ ]));
554
+ const ordered = [];
555
+ const state = new Map();
556
+ const visit = (flow)=>{
557
+ if (state.has(flow.slug)) return;
558
+ state.set(flow.slug, 'visiting');
559
+ for (const slug of calledFlowSlugs(flow.nodes ?? []).toSorted(byCode)){
560
+ const callee = bySlug.get(slug);
561
+ if (callee) visit(callee);
562
+ }
563
+ state.set(flow.slug, 'done');
564
+ ordered.push(flow);
565
+ };
566
+ flows.toSorted((a, b)=>byCode(a.slug, b.slug)).forEach(visit);
567
+ return ordered;
568
+ }
569
+ const FIELD_COMPARED_KEYS = [
570
+ 'label',
571
+ 'fieldType',
572
+ 'nullable',
573
+ 'unique',
574
+ 'isIndexed',
575
+ 'defaultValue',
576
+ 'validationRules',
577
+ 'selectOptions',
578
+ 'relationTarget',
579
+ 'order',
580
+ 'uiConfig',
581
+ 'isSearchable'
582
+ ];
583
+ const ENTITY_COMPARED_KEYS = [
584
+ 'label',
585
+ 'description',
586
+ 'uiConfig',
587
+ 'isSoftDeleteEnabled',
588
+ 'isAuditEnabled',
589
+ 'status'
590
+ ];
591
+ function changedValues(from, to, keys) {
592
+ return Object.fromEntries(keys.filter((key)=>!same(from[key], to[key])).map((key)=>[
593
+ key,
594
+ to[key] ?? null
595
+ ]));
596
+ }
597
+ /**
598
+ * Pairs each item of the bundle with one of this environment's: by id first (a renamed one keeps
599
+ * its id), then by code among those no id claimed, so a rename never takes a field another item owns.
600
+ */ function matchDefinitions(items, current) {
601
+ const pairs = new Map();
602
+ const taken = new Set();
603
+ const claim = (item, hit)=>{
604
+ if (!hit) return;
605
+ pairs.set(item, hit);
606
+ taken.add(hit.id);
607
+ };
608
+ for (const item of items)claim(item, current.find((c)=>c.id === item.id && !taken.has(c.id)));
609
+ for (const item of items.filter((i)=>!pairs.has(i)))claim(item, current.find((c)=>c.code === item.code && !taken.has(c.id)));
610
+ return pairs;
611
+ }
612
+ /** The bundle's own problems: duplicates, and relations to an entity neither the bundle nor this environment has. */ function bundleProblems(entities, current) {
613
+ const problems = [];
614
+ const codes = new Set();
615
+ for (const entity of entities){
616
+ if (codes.has(entity.code)) problems.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .BUNDLE_MESSAGES.DUPLICATE_ENTITY */.iX.DUPLICATE_ENTITY, {
617
+ entity: entity.code
618
+ }));
619
+ if (entity.status === _enums_entity_status_enum_js__rspack_import_3/* .EntityStatus.DRAFT */.c.DRAFT) problems.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .BUNDLE_MESSAGES.ENTITY_DRAFT_IN_BUNDLE */.iX.ENTITY_DRAFT_IN_BUNDLE, {
620
+ entity: entity.code
621
+ }));
622
+ codes.add(entity.code);
623
+ const fieldCodes = new Set();
624
+ const fieldIds = new Set();
625
+ for (const field of entity.fields){
626
+ if (fieldCodes.has(field.code) || fieldIds.has(field.id)) problems.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .BUNDLE_MESSAGES.DUPLICATE_FIELD */.iX.DUPLICATE_FIELD, {
627
+ entity: entity.code,
628
+ field: field.code
629
+ }));
630
+ fieldCodes.add(field.code);
631
+ fieldIds.add(field.id);
632
+ }
633
+ }
634
+ const known = new Set([
635
+ ...codes,
636
+ ...current.map((e)=>e.code)
637
+ ]);
638
+ for (const entity of entities){
639
+ for (const field of entity.fields.filter((f)=>f.fieldType === _enums_field_type_enum_js__rspack_import_4/* .FieldType.RELATION */.P.RELATION && !f.deprecated)){
640
+ if (!field.relationTarget || !known.has(field.relationTarget)) {
641
+ problems.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .BUNDLE_MESSAGES.RELATION_TARGET_UNKNOWN */.iX.RELATION_TARGET_UNKNOWN, {
642
+ entity: entity.code,
643
+ field: field.code,
644
+ target: field.relationTarget ?? ''
645
+ }));
646
+ }
647
+ }
648
+ }
649
+ return problems;
650
+ }
651
+ /** A code no field of the entity has or gets, for the temporary step of a rename cycle. */ function temporaryCode(fieldId, taken) {
652
+ const base = `tmp_${fieldId.replace(/[^0-9a-z]/gi, '').toLowerCase().slice(0, 12)}`;
653
+ let code = base;
654
+ for(let n = 2; taken.has(code); n++)code = `${base}_${n}`;
655
+ taken.add(code);
656
+ return code;
657
+ }
658
+ /**
659
+ * Renames in an order that never takes a code another field still has: a rename waits for the one
660
+ * that frees its new code (a -> b after b -> c), and a cycle (a <-> b) goes through a temporary code
661
+ * first (a -> tmp, b -> a, tmp -> b). Each rename rewrites the references to its field, so the
662
+ * references end up exactly where the bundle has them.
663
+ */ function orderRenames(entityCode, renames, taken) {
664
+ const ordered = [];
665
+ const pending = renames.map((rename)=>({
666
+ ...rename,
667
+ waited: false
668
+ })).toSorted((a, b)=>byCode(a.from, b.from));
669
+ const step = (rename, from, to, dependsOnEarlierStep, warnings)=>({
670
+ kind: 'rename_field',
671
+ entityCode,
672
+ fieldCode: from,
673
+ targetFieldId: rename.targetFieldId,
674
+ details: {
675
+ from,
676
+ to
677
+ },
678
+ dependsOnEarlierStep,
679
+ changes: {
680
+ code: to
681
+ },
682
+ ...warnings ? {
683
+ warnings
684
+ } : {}
685
+ });
686
+ while(pending.length){
687
+ const ready = pending.filter((rename)=>!pending.some((other)=>other !== rename && other.from === rename.to));
688
+ if (ready.length) {
689
+ for (const rename of ready){
690
+ ordered.push(step(rename, rename.from, rename.to, rename.restored || rename.waited));
691
+ pending.splice(pending.indexOf(rename), 1);
692
+ }
693
+ for (const rename of pending)rename.waited = true;
694
+ continue;
695
+ }
696
+ const first = pending[0];
697
+ const temporary = temporaryCode(first.targetFieldId, taken);
698
+ ordered.push(step(first, first.from, temporary, first.restored || first.waited, [
699
+ (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .BUNDLE_MESSAGES.RENAME_VIA_TEMPORARY */.iX.RENAME_VIA_TEMPORARY, {
700
+ field: first.from,
701
+ temporary,
702
+ to: first.to
703
+ })
704
+ ]));
705
+ const freed = pending.find((rename)=>rename.to === first.from);
706
+ if (freed) freed.waited = true;
707
+ first.from = temporary;
708
+ first.waited = true;
709
+ }
710
+ return ordered;
711
+ }
712
+ /**
713
+ * What it takes to bring this environment's entities to the bundle's. Entities and fields are
714
+ * matched by id first (a field renamed where it was designed keeps its id), then by code. Nothing
715
+ * the bundle lacks is removed: such definitions are reported as extras, and only with
716
+ * `deprecateMissingFields` are missing fields deprecated (which keeps their column and data).
717
+ *
718
+ * Order: entities switched back on, new entities (their relation fields wait until every new entity
719
+ * exists), field changes of existing entities (per entity: restores, renames, changes, new fields,
720
+ * deprecations), the new entities' relation fields, and entities switched off last. A DRAFT entity
721
+ * (no table) on either side blocks the import.
722
+ */ function diffEntities(entities, current, options = {}) {
723
+ const result = {
724
+ operations: [],
725
+ unchangedEntities: 0,
726
+ unchangedFields: 0,
727
+ extras: [],
728
+ blockers: bundleProblems(entities, current)
729
+ };
730
+ const entityUpdatesFirst = [];
731
+ const creates = [];
732
+ const fieldOps = [];
733
+ const relationAdds = [];
734
+ const entityUpdatesLast = [];
735
+ const sorted = entities.toSorted((a, b)=>byCode(a.code, b.code));
736
+ const pairs = matchDefinitions(sorted, current);
737
+ const matched = new Set([
738
+ ...pairs.values()
739
+ ].map((e)=>e.id));
740
+ for (const entity of sorted){
741
+ const target = pairs.get(entity);
742
+ if (target && target.code !== entity.code) {
743
+ result.blockers.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .BUNDLE_MESSAGES.ENTITY_CODE_CHANGED */.iX.ENTITY_CODE_CHANGED, {
744
+ entity: entity.code,
745
+ current: target.code
746
+ }));
747
+ continue;
748
+ }
749
+ if (!target) {
750
+ const live = entity.fields.filter((f)=>!f.deprecated);
751
+ creates.push({
752
+ kind: 'create_entity',
753
+ entityCode: entity.code,
754
+ details: {
755
+ fields: live.filter((f)=>f.fieldType !== _enums_field_type_enum_js__rspack_import_4/* .FieldType.RELATION */.P.RELATION).map((f)=>f.code)
756
+ },
757
+ dependsOnEarlierStep: false,
758
+ entity: {
759
+ ...entity,
760
+ fields: live.filter((f)=>f.fieldType !== _enums_field_type_enum_js__rspack_import_4/* .FieldType.RELATION */.P.RELATION)
761
+ }
762
+ });
763
+ for (const field of live.filter((f)=>f.fieldType === _enums_field_type_enum_js__rspack_import_4/* .FieldType.RELATION */.P.RELATION)){
764
+ relationAdds.push({
765
+ kind: 'add_field',
766
+ entityCode: entity.code,
767
+ fieldCode: field.code,
768
+ details: {
769
+ fieldType: field.fieldType,
770
+ relationTarget: field.relationTarget
771
+ },
772
+ dependsOnEarlierStep: true,
773
+ field
774
+ });
775
+ }
776
+ if (entity.status === _enums_entity_status_enum_js__rspack_import_3/* .EntityStatus.DEPRECATED */.c.DEPRECATED) {
777
+ entityUpdatesLast.push({
778
+ kind: 'update_entity',
779
+ entityCode: entity.code,
780
+ details: {
781
+ changes: [
782
+ 'status'
783
+ ]
784
+ },
785
+ dependsOnEarlierStep: true,
786
+ changes: {
787
+ status: _enums_entity_status_enum_js__rspack_import_3/* .EntityStatus.DEPRECATED */.c.DEPRECATED
788
+ }
789
+ });
790
+ }
791
+ continue;
792
+ }
793
+ if (target.status === _enums_entity_status_enum_js__rspack_import_3/* .EntityStatus.DRAFT */.c.DRAFT) {
794
+ result.blockers.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_2/* .BUNDLE_MESSAGES.ENTITY_DRAFT_HERE */.iX.ENTITY_DRAFT_HERE, {
795
+ entity: entity.code
796
+ }));
797
+ continue;
798
+ }
799
+ const entityChanges = changedValues(target, entity, ENTITY_COMPARED_KEYS);
800
+ const deprecating = entityChanges['status'] === _enums_entity_status_enum_js__rspack_import_3/* .EntityStatus.DEPRECATED */.c.DEPRECATED;
801
+ if (Object.keys(entityChanges).length) {
802
+ (deprecating ? entityUpdatesLast : entityUpdatesFirst).push({
803
+ kind: 'update_entity',
804
+ entityCode: entity.code,
805
+ details: {
806
+ changes: Object.keys(entityChanges)
807
+ },
808
+ dependsOnEarlierStep: false,
809
+ changes: entityChanges
810
+ });
811
+ } else {
812
+ result.unchangedEntities++;
813
+ }
814
+ const fields = entity.fields.toSorted((a, b)=>a.order - b.order || byCode(a.code, b.code));
815
+ const fieldPairs = matchDefinitions(fields, target.fields);
816
+ const usedFieldIds = new Set([
817
+ ...fieldPairs.values()
818
+ ].map((f)=>f.id));
819
+ const restores = [];
820
+ const renames = [];
821
+ const updates = [];
822
+ const adds = [];
823
+ const deprecations = [];
824
+ for (const field of fields){
825
+ const existing = fieldPairs.get(field);
826
+ if (!existing) {
827
+ if (field.deprecated) continue;
828
+ adds.push({
829
+ kind: 'add_field',
830
+ entityCode: entity.code,
831
+ fieldCode: field.code,
832
+ details: {
833
+ fieldType: field.fieldType,
834
+ relationTarget: field.relationTarget
835
+ },
836
+ dependsOnEarlierStep: false,
837
+ field
838
+ });
839
+ continue;
840
+ }
841
+ const at = {
842
+ entityCode: entity.code,
843
+ targetFieldId: existing.id
844
+ };
845
+ let touched = false;
846
+ // A deprecated field cannot be changed until it is restored; a rename does not stop the other changes from being previewed.
847
+ const restored = existing.deprecated && !field.deprecated;
848
+ if (restored) {
849
+ restores.push({
850
+ ...at,
851
+ kind: 'restore_field',
852
+ fieldCode: existing.code,
853
+ details: {},
854
+ dependsOnEarlierStep: false
855
+ });
856
+ touched = true;
857
+ }
858
+ if (existing.code !== field.code && !field.deprecated) {
859
+ renames.push({
860
+ targetFieldId: existing.id,
861
+ from: existing.code,
862
+ to: field.code,
863
+ restored
864
+ });
865
+ touched = true;
866
+ }
867
+ const changes = field.deprecated ? {} : changedValues(existing, field, FIELD_COMPARED_KEYS);
868
+ if (Object.keys(changes).length) {
869
+ updates.push({
870
+ ...at,
871
+ kind: 'update_field',
872
+ fieldCode: field.code,
873
+ details: {
874
+ changes: Object.keys(changes)
875
+ },
876
+ dependsOnEarlierStep: restored,
877
+ changes
878
+ });
879
+ touched = true;
880
+ }
881
+ if (field.deprecated && !existing.deprecated) {
882
+ deprecations.push({
883
+ ...at,
884
+ kind: 'deprecate_field',
885
+ fieldCode: existing.code,
886
+ details: {},
887
+ dependsOnEarlierStep: false
888
+ });
889
+ touched = true;
890
+ }
891
+ if (!touched) result.unchangedFields++;
892
+ }
893
+ // A new field may take a code a rename frees: it is added once that rename has run.
894
+ const freedCodes = new Set(renames.map((r)=>r.from));
895
+ for (const add of adds)if (freedCodes.has(add.fieldCode)) add.dependsOnEarlierStep = true;
896
+ const takenCodes = new Set([
897
+ ...target.fields.map((f)=>f.code),
898
+ ...fields.map((f)=>f.code)
899
+ ]);
900
+ fieldOps.push(...restores, ...orderRenames(entity.code, renames, takenCodes), ...updates, ...adds, ...deprecations);
901
+ for (const extra of target.fields.filter((f)=>!usedFieldIds.has(f.id) && !f.deprecated)){
902
+ if (options.deprecateMissingFields) {
903
+ fieldOps.push({
904
+ kind: 'deprecate_field',
905
+ entityCode: entity.code,
906
+ fieldCode: extra.code,
907
+ targetFieldId: extra.id,
908
+ details: {},
909
+ dependsOnEarlierStep: false
910
+ });
911
+ } else {
912
+ result.extras.push({
913
+ kind: 'field',
914
+ entityCode: entity.code,
915
+ fieldCode: extra.code
916
+ });
917
+ }
918
+ }
919
+ }
920
+ for (const extra of current.filter((e)=>!matched.has(e.id)))result.extras.push({
921
+ kind: 'entity',
922
+ entityCode: extra.code
923
+ });
924
+ result.operations = [
925
+ ...entityUpdatesFirst,
926
+ ...creates,
927
+ ...fieldOps,
928
+ ...relationAdds,
929
+ ...entityUpdatesLast
930
+ ];
931
+ return result;
932
+ }
933
+
934
+ __webpack_require__.d(__webpack_exports__, {
935
+ Og: () => (matchDefinitions),
936
+ Q5: () => (calledFlowSlugs),
937
+ dX: () => (stripApiKeys),
938
+ dj: () => (canonicalJson),
939
+ gT: () => (applyVariables),
940
+ lj: () => (extractVariables),
941
+ qG: () => (orderFlows),
942
+ zb: () => (diffEntities)
943
+ }, {
944
+ $I: ENTITY_COMPARED_KEYS,
945
+ VU: byCode,
946
+ bs: bundleSubject,
947
+ i9: bundleChecksum,
948
+ mT: FIELD_COMPARED_KEYS
949
+ });
950
+
951
+
952
+ },
953
+ 6412(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
954
+ /* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(6157);
955
+ /* import */ var class_transformer__rspack_import_1 = __webpack_require__(5812);
956
+ /* import */ var class_validator__rspack_import_2 = __webpack_require__(5421);
957
+ /* import */ var _config_message_keys_js__rspack_import_4 = __webpack_require__(5732);
958
+ /* import */ var _dtos_definition_bundle_dto_js__rspack_import_3 = __webpack_require__(6691);
959
+
960
+
961
+
962
+
963
+
964
+ const MAX_REPORTED_PROBLEMS = 50;
965
+ /** Every failed constraint, named by its path in the bundle (`entities.0.fields.2.code`). */ function problems(errors, parent = '') {
966
+ return errors.flatMap((error)=>{
967
+ const field = parent ? `${parent}.${error.property}` : error.property;
968
+ const own = error.constraints ? [
969
+ {
970
+ field,
971
+ message: Object.values(error.constraints).join('; ')
972
+ }
973
+ ] : [];
974
+ return [
975
+ ...own,
976
+ ...problems(error.children ?? [], field)
977
+ ];
978
+ });
979
+ }
980
+ const invalid = (errors = [])=>new _nestjs_common__rspack_import_0.BadRequestException({
981
+ message: 'The file is not a valid entity builder bundle.',
982
+ messageKey: _config_message_keys_js__rspack_import_4/* .BUNDLE_MESSAGES.FILE_INVALID */.iX.FILE_INVALID,
983
+ ...errors.length ? {
984
+ errors: errors.slice(0, MAX_REPORTED_PROBLEMS)
985
+ } : {}
986
+ });
987
+ /**
988
+ * The uploaded bundle, parsed and checked as strictly as a request body (unknown keys refused). The
989
+ * bundle travels as a file rather than as JSON so the app's JSON body limit never applies to it: the
990
+ * upload limit is the package's own (`ENTITY_BUNDLE_MAX_BYTES`, enforced by FileInterceptor).
991
+ */ function readBundleFile(file) {
992
+ if (!file?.buffer?.length) {
993
+ throw new _nestjs_common__rspack_import_0.BadRequestException({
994
+ message: 'Attach the bundle file as the "bundle" form field.',
995
+ messageKey: _config_message_keys_js__rspack_import_4/* .BUNDLE_MESSAGES.FILE_REQUIRED */.iX.FILE_REQUIRED
996
+ });
997
+ }
998
+ let raw;
999
+ try {
1000
+ raw = JSON.parse(file.buffer.toString('utf8').replace(/^\uFEFF/, ''));
1001
+ } catch {
1002
+ throw invalid();
1003
+ }
1004
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) throw invalid();
1005
+ const bundle = (0,class_transformer__rspack_import_1.plainToInstance)(_dtos_definition_bundle_dto_js__rspack_import_3/* .DefinitionBundleDto */.JE, raw);
1006
+ const errors = (0,class_validator__rspack_import_2.validateSync)(bundle, {
1007
+ whitelist: true,
1008
+ forbidNonWhitelisted: true
1009
+ });
1010
+ if (errors.length) throw invalid(problems(errors));
1011
+ return bundle;
1012
+ }
1013
+
1014
+ __webpack_require__.d(__webpack_exports__, {
1015
+ z: () => (readBundleFile)
1016
+ });
1017
+
1018
+
1019
+ },
1020
+ 7463(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1021
+ /* import */ var _flusys_nestjs_shared_utils__rspack_import_0 = __webpack_require__(9216);
1022
+ /* import */ var _nestjs_common__rspack_import_1 = __webpack_require__(6157);
1023
+ /* import */ var node_crypto__rspack_import_2 = __webpack_require__(2561);
1024
+ /* import */ var typeorm__rspack_import_3 = __webpack_require__(7158);
1025
+ /* import */ var _config_message_keys_js__rspack_import_17 = __webpack_require__(5732);
1026
+ /* import */ var _dtos_schema_change_dto_js__rspack_import_4 = __webpack_require__(4945);
1027
+ /* import */ var _entities_entity_definition_entity_js__rspack_import_5 = __webpack_require__(3189);
1028
+ /* import */ var _enums_entity_status_enum_js__rspack_import_16 = __webpack_require__(1313);
1029
+ /* import */ var _entities_field_definition_entity_js__rspack_import_6 = __webpack_require__(2206);
1030
+ /* import */ var _entities_flow_definition_entity_js__rspack_import_7 = __webpack_require__(3770);
1031
+ /* import */ var _flow_engine_flow_errors_js__rspack_import_8 = __webpack_require__(8542);
1032
+ /* import */ var _flow_engine_flow_types_js__rspack_import_9 = __webpack_require__(6256);
1033
+ /* import */ var _interfaces_definition_bundle_interface_js__rspack_import_18 = __webpack_require__(8835);
1034
+ /* import */ var _interfaces_flow_definition_interface_js__rspack_import_19 = __webpack_require__(9609);
1035
+ /* import */ var _definition_bundle_diff_js__rspack_import_10 = __webpack_require__(3801);
1036
+ /* import */ var _entity_builder_config_service_js__rspack_import_11 = __webpack_require__(4281);
1037
+ /* import */ var _entity_builder_datasource_provider_js__rspack_import_12 = __webpack_require__(424);
1038
+ /* import */ var _flow_definition_service_js__rspack_import_13 = __webpack_require__(5229);
1039
+ /* import */ var _schema_evolution_service_js__rspack_import_14 = __webpack_require__(3606);
1040
+ /* import */ var _schema_sync_service_js__rspack_import_15 = __webpack_require__(3474);
1041
+ function _ts_decorate(decorators, target, key, desc) {
1042
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1043
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
1044
+ r = Reflect.decorate(decorators, target, key, desc);
1045
+ } else {
1046
+ for(var i = decorators.length - 1; i >= 0; i--){
1047
+ if (d = decorators[i]) {
1048
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1049
+ }
1050
+ }
1051
+ }
1052
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1053
+ }
1054
+ function _ts_metadata(metadataKey, metadataValue) {
1055
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
1056
+ return Reflect.metadata(metadataKey, metadataValue);
1057
+ }
1058
+ }
1059
+ function _ts_param(paramIndex, decorator) {
1060
+ return function(target, key) {
1061
+ decorator(target, key, paramIndex);
1062
+ };
1063
+ }
1064
+
1065
+
1066
+
1067
+
1068
+
1069
+
1070
+
1071
+
1072
+
1073
+
1074
+
1075
+
1076
+
1077
+
1078
+
1079
+
1080
+
1081
+
1082
+
1083
+
1084
+ /** The reasons a failed step gives besides its message: a change's blockers, a flow's validation errors. */ function failureDetails(error) {
1085
+ if (!(error instanceof _nestjs_common__rspack_import_1.HttpException)) return [];
1086
+ const response = error.getResponse();
1087
+ if (typeof response !== 'object') return [];
1088
+ const details = response.blockers ?? response.errors ?? [];
1089
+ return details.filter((d)=>typeof d?.messageKey === 'string').map((d)=>(0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(d.messageKey, d.messageVariables));
1090
+ }
1091
+ /** Structural changes that, unpreviewed, may turn out to lose data (a type conversion, a column made required or unique, audit or soft delete switched off). */ const LOSSY_FIELD_CHANGES = [
1092
+ 'fieldType',
1093
+ 'nullable',
1094
+ 'unique'
1095
+ ];
1096
+ const LOSSY_ENTITY_CHANGES = [
1097
+ 'isSoftDeleteEnabled',
1098
+ 'isAuditEnabled'
1099
+ ];
1100
+ function mayLoseData(step) {
1101
+ const changes = Array.isArray(step.details['changes']) ? step.details['changes'] : [];
1102
+ if (step.kind === 'update_field') return changes.some((c)=>LOSSY_FIELD_CHANGES.includes(c));
1103
+ return step.kind === 'update_entity' && changes.some((c)=>LOSSY_ENTITY_CHANGES.includes(c));
1104
+ }
1105
+ /**
1106
+ * What was reviewed: the bundle, the options and every step (kind, subject, changes, and whether its
1107
+ * preview loses data). Not the SQL or row counts, which change with every write and would refuse each apply.
1108
+ */ function planChecksum(bundle, deprecateMissingFields, steps) {
1109
+ const reviewed = steps.map((step)=>({
1110
+ kind: step.kind,
1111
+ subject: (0,_definition_bundle_diff_js__rspack_import_10/* .bundleSubject */.bs)(step),
1112
+ details: step.details,
1113
+ destructive: step.preview?.destructive ?? null
1114
+ }));
1115
+ return (0,node_crypto__rspack_import_2.createHash)('sha256').update((0,_definition_bundle_diff_js__rspack_import_10/* .canonicalJson */.dj)({
1116
+ bundle,
1117
+ deprecateMissingFields,
1118
+ steps: reviewed
1119
+ })).digest('hex');
1120
+ }
1121
+ const newApiKey = ()=>`fk_${(0,node_crypto__rspack_import_2.randomBytes)(4).toString('hex')}_${(0,node_crypto__rspack_import_2.randomBytes)(16).toString('hex')}`;
1122
+ const triggerPath = (node)=>typeof node.config?.['path'] === 'string' && node.config['path'] ? node.config['path'] : null;
1123
+ const needsApiKey = (node)=>node?.type === 'trigger' && node.config?.['authMode'] === 'api_key';
1124
+ /** The stored API keys of a flow's Request steps (published and draft), by step id. */ function storedApiKeys(flow) {
1125
+ const keys = new Map();
1126
+ for (const node of [
1127
+ ...flow?.nodes ?? [],
1128
+ ...flow?.draft?.nodes ?? []
1129
+ ]){
1130
+ if (node?.type === 'trigger' && (0,_flow_engine_flow_types_js__rspack_import_9/* .isStoredApiKey */.xA)(node.config?.['apiKey']) && !keys.has(node.id)) keys.set(node.id, node.config['apiKey']);
1131
+ }
1132
+ return keys;
1133
+ }
1134
+ class DefinitionBundleService {
1135
+ provider;
1136
+ config;
1137
+ schemaSync;
1138
+ evolution;
1139
+ flows;
1140
+ constructor(provider, config, schemaSync, evolution, flows){
1141
+ this.provider = provider;
1142
+ this.config = config;
1143
+ this.schemaSync = schemaSync;
1144
+ this.evolution = evolution;
1145
+ this.flows = flows;
1146
+ }
1147
+ variables() {
1148
+ return this.config.getBundleVariables();
1149
+ }
1150
+ // ── export ──────────────────────────────────────────────────────────────────────────
1151
+ async export(dto) {
1152
+ const current = await this.loadEntities();
1153
+ const selected = dto.entityCodes ? current.filter((e)=>dto.entityCodes.includes(e.code)) : current;
1154
+ // A DRAFT entity has no table where it is designed, so there is nothing to promote yet.
1155
+ const drafts = selected.filter((e)=>e.status === _enums_entity_status_enum_js__rspack_import_16/* .EntityStatus.DRAFT */.c.DRAFT).toSorted((a, b)=>(0,_definition_bundle_diff_js__rspack_import_10/* .byCode */.VU)(a.code, b.code));
1156
+ const entities = selected.filter((e)=>e.status !== _enums_entity_status_enum_js__rspack_import_16/* .EntityStatus.DRAFT */.c.DRAFT).toSorted((a, b)=>(0,_definition_bundle_diff_js__rspack_import_10/* .byCode */.VU)(a.code, b.code)).map((entity)=>({
1157
+ ...entity,
1158
+ fields: entity.fields.toSorted((a, b)=>a.order - b.order || (0,_definition_bundle_diff_js__rspack_import_10/* .byCode */.VU)(a.code, b.code))
1159
+ }));
1160
+ const flowRepo = await this.provider.getRepository(_entities_flow_definition_entity_js__rspack_import_7/* .FlowDefinition */.G);
1161
+ const rows = (await flowRepo.find({
1162
+ where: dto.flowSlugs ? {
1163
+ slug: (0,typeorm__rspack_import_3.In)(dto.flowSlugs)
1164
+ } : {}
1165
+ })).toSorted((a, b)=>(0,_definition_bundle_diff_js__rspack_import_10/* .byCode */.VU)(a.slug, b.slug));
1166
+ const warnings = [
1167
+ ...drafts.map((entity)=>(0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_17/* .BUNDLE_MESSAGES.ENTITY_DRAFT_SKIPPED */.iX.ENTITY_DRAFT_SKIPPED, {
1168
+ entity: entity.code
1169
+ })),
1170
+ ...rows.filter((flow)=>!(0,_flow_definition_service_js__rspack_import_13/* .isPublished */.HF)(flow)).map((flow)=>(0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_17/* .BUNDLE_MESSAGES.FLOW_UNPUBLISHED_SKIPPED */.iX.FLOW_UNPUBLISHED_SKIPPED, {
1171
+ flow: flow.slug
1172
+ }))
1173
+ ];
1174
+ const variables = this.variables();
1175
+ const flows = rows.filter(_flow_definition_service_js__rspack_import_13/* .isPublished */.HF).map((flow)=>{
1176
+ const snapshot = (0,_flow_definition_service_js__rspack_import_13/* .snapshotOf */.eY)(flow);
1177
+ return {
1178
+ ...snapshot,
1179
+ description: snapshot.description ?? null,
1180
+ nodes: (0,_definition_bundle_diff_js__rspack_import_10/* .extractVariables */.lj)((0,_definition_bundle_diff_js__rspack_import_10/* .stripApiKeys */.dX)(snapshot.nodes ?? []), variables),
1181
+ edges: snapshot.edges ?? []
1182
+ };
1183
+ });
1184
+ // Keys sorted at every level: PostgreSQL and MySQL hand JSON columns back in different key orders.
1185
+ const bundle = JSON.parse((0,_definition_bundle_diff_js__rspack_import_10/* .canonicalJson */.dj)({
1186
+ format: _interfaces_definition_bundle_interface_js__rspack_import_18/* .DEFINITION_BUNDLE_FORMAT */.D,
1187
+ version: (/* inlined export .DEFINITION_BUNDLE_VERSION */1),
1188
+ entities,
1189
+ flows
1190
+ }));
1191
+ return {
1192
+ bundle,
1193
+ checksum: (0,_definition_bundle_diff_js__rspack_import_10/* .bundleChecksum */.i9)(bundle),
1194
+ warnings
1195
+ };
1196
+ }
1197
+ /** Every entity of this environment with its fields, relations named by target code. */ async loadEntities() {
1198
+ const definitions = await (await this.provider.getRepository(_entities_entity_definition_entity_js__rspack_import_5/* .EntityDefinition */.f)).find();
1199
+ const fields = await (await this.provider.getRepository(_entities_field_definition_entity_js__rspack_import_6/* .FieldDefinition */.c)).find();
1200
+ const codeOf = new Map(definitions.map((d)=>[
1201
+ d.id,
1202
+ d.code
1203
+ ]));
1204
+ return definitions.map((definition)=>({
1205
+ id: definition.id,
1206
+ code: definition.code,
1207
+ label: definition.label,
1208
+ description: definition.description ?? null,
1209
+ status: definition.status,
1210
+ isSoftDeleteEnabled: definition.isSoftDeleteEnabled,
1211
+ isAuditEnabled: definition.isAuditEnabled,
1212
+ uiConfig: definition.uiConfig ?? null,
1213
+ fields: fields.filter((f)=>f.entityDefinitionId === definition.id && !f.isSystemField).map((f)=>({
1214
+ id: f.id,
1215
+ code: f.code,
1216
+ label: f.label,
1217
+ fieldType: f.fieldType,
1218
+ nullable: f.nullable,
1219
+ unique: f.unique,
1220
+ isIndexed: f.isIndexed,
1221
+ defaultValue: f.defaultValue ?? null,
1222
+ validationRules: f.validationRules ?? null,
1223
+ selectOptions: f.selectOptions ?? null,
1224
+ relationTarget: f.relationTargetEntityId ? codeOf.get(f.relationTargetEntityId) ?? null : null,
1225
+ order: f.order,
1226
+ uiConfig: f.uiConfig ?? null,
1227
+ isSearchable: f.isSearchable,
1228
+ deprecated: !!f.deprecatedAt
1229
+ }))
1230
+ }));
1231
+ }
1232
+ // ── plan ────────────────────────────────────────────────────────────────────────────
1233
+ async planImport(dto, user) {
1234
+ const { plan } = await this.buildPlan(dto, user);
1235
+ return plan;
1236
+ }
1237
+ /** The plan, with what apply-import runs: the entity operations and the flows, in order. */ async buildPlan(dto, user) {
1238
+ const bundle = dto.bundle;
1239
+ const current = await this.loadEntities();
1240
+ const entityDiff = (0,_definition_bundle_diff_js__rspack_import_10/* .diffEntities */.zb)(bundle.entities, current, {
1241
+ deprecateMissingFields: dto.deprecateMissingFields === true
1242
+ });
1243
+ const flowDiff = await this.diffFlows(bundle.flows);
1244
+ const existingCodes = new Set(current.map((e)=>e.code));
1245
+ const steps = [];
1246
+ for (const operation of entityDiff.operations){
1247
+ const dependent = operation.dependsOnEarlierStep || operation.kind !== 'create_entity' && !existingCodes.has(operation.entityCode) || this.relationNotYetCreated(operation, existingCodes);
1248
+ const step = {
1249
+ kind: operation.kind,
1250
+ entityCode: operation.entityCode,
1251
+ ...operation.fieldCode ? {
1252
+ fieldCode: operation.fieldCode
1253
+ } : {},
1254
+ details: operation.details,
1255
+ preview: null,
1256
+ warnings: [
1257
+ ...operation.warnings ?? [],
1258
+ ...dependent ? [
1259
+ (0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_17/* .BUNDLE_MESSAGES.STEP_AFTER_EARLIER */.iX.STEP_AFTER_EARLIER)
1260
+ ] : []
1261
+ ],
1262
+ blockers: []
1263
+ };
1264
+ if (!dependent) {
1265
+ try {
1266
+ step.preview = await this.previewEntityStep(operation, current, user);
1267
+ step.blockers.push(...step.preview.blockers);
1268
+ } catch (error) {
1269
+ step.blockers.push((0,_flow_engine_flow_errors_js__rspack_import_8/* .errorRef */.O$)(error));
1270
+ }
1271
+ }
1272
+ steps.push(step);
1273
+ }
1274
+ const schemaChanges = entityDiff.operations.length > 0;
1275
+ const importedSlugs = new Set(flowDiff.planned.map((p)=>p.flow.slug));
1276
+ for (const planned of flowDiff.planned){
1277
+ const step = {
1278
+ kind: planned.kind,
1279
+ flowSlug: planned.flow.slug,
1280
+ details: planned.details,
1281
+ preview: null,
1282
+ warnings: [
1283
+ ...planned.warnings
1284
+ ],
1285
+ blockers: [
1286
+ ...planned.blockers
1287
+ ]
1288
+ };
1289
+ // A flow with a code step needs that permission from whoever imports it, as from whoever saves it.
1290
+ await this.flows.assertMayAuthor((0,_flow_definition_service_js__rspack_import_13/* .toFlowSettings */.RK)(planned.flow), user).catch((error)=>step.blockers.push((0,_flow_engine_flow_errors_js__rspack_import_8/* .errorRef */.O$)(error)));
1291
+ const dependsOnImport = schemaChanges || (0,_definition_bundle_diff_js__rspack_import_10/* .calledFlowSlugs */.Q5)(planned.flow.nodes).some((slug)=>importedSlugs.has(slug));
1292
+ if (dependsOnImport) {
1293
+ step.warnings.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_17/* .BUNDLE_MESSAGES.FLOWS_CHECKED_ON_APPLY */.iX.FLOWS_CHECKED_ON_APPLY));
1294
+ } else if (!step.blockers.length) {
1295
+ const { errors, warnings } = await this.flows.validate((0,_flow_definition_service_js__rspack_import_13/* .toFlowSettings */.RK)(planned.flow));
1296
+ step.blockers.push(...errors);
1297
+ step.warnings.push(...warnings);
1298
+ }
1299
+ steps.push(step);
1300
+ }
1301
+ const checksum = (0,_definition_bundle_diff_js__rspack_import_10/* .bundleChecksum */.i9)(bundle);
1302
+ const plan = {
1303
+ checksum,
1304
+ planChecksum: planChecksum(checksum, dto.deprecateMissingFields === true, steps),
1305
+ steps,
1306
+ unchanged: {
1307
+ entities: entityDiff.unchangedEntities,
1308
+ fields: entityDiff.unchangedFields,
1309
+ flows: flowDiff.unchanged
1310
+ },
1311
+ extras: [
1312
+ ...entityDiff.extras,
1313
+ ...flowDiff.extras
1314
+ ],
1315
+ blockers: [
1316
+ ...entityDiff.blockers,
1317
+ ...flowDiff.blockers
1318
+ ],
1319
+ destructive: steps.some((s)=>s.preview?.destructive),
1320
+ mayLoseData: steps.some((s)=>s.preview?.destructive || !s.preview && mayLoseData(s))
1321
+ };
1322
+ return {
1323
+ plan,
1324
+ operations: entityDiff.operations,
1325
+ flows: flowDiff.planned
1326
+ };
1327
+ }
1328
+ /** A relation to an entity this import creates: its id is only known once the entity exists. */ relationNotYetCreated(operation, existingCodes) {
1329
+ const target = operation.field?.relationTarget ?? operation.changes?.['relationTarget'];
1330
+ return !!target && !existingCodes.has(target);
1331
+ }
1332
+ async previewEntityStep(operation, current, user) {
1333
+ if (operation.kind === 'create_entity') return this.schemaSync.planCreateEntity(this.createRequest(operation.entity), user);
1334
+ return this.evolution.plan(this.changeRequest(operation, current), user);
1335
+ }
1336
+ async diffFlows(bundleFlows) {
1337
+ const repo = await this.provider.getRepository(_entities_flow_definition_entity_js__rspack_import_7/* .FlowDefinition */.G);
1338
+ const existing = await repo.find();
1339
+ const bySlug = new Map(existing.map((flow)=>[
1340
+ flow.slug,
1341
+ flow
1342
+ ]));
1343
+ const slugs = bundleFlows.map((f)=>f.slug);
1344
+ const deleted = slugs.length ? new Set((await repo.find({
1345
+ select: {
1346
+ id: true,
1347
+ slug: true
1348
+ },
1349
+ where: {
1350
+ slug: (0,typeorm__rspack_import_3.In)(slugs)
1351
+ },
1352
+ withDeleted: true
1353
+ })).filter((f)=>!bySlug.has(f.slug)).map((f)=>f.slug)) : new Set();
1354
+ const variables = this.variables();
1355
+ const result = {
1356
+ planned: [],
1357
+ unchanged: 0,
1358
+ extras: [],
1359
+ blockers: []
1360
+ };
1361
+ const seen = new Set();
1362
+ for (const slug of slugs){
1363
+ if (seen.has(slug)) result.blockers.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_17/* .BUNDLE_MESSAGES.DUPLICATE_FLOW */.iX.DUPLICATE_FLOW, {
1364
+ flow: slug
1365
+ }));
1366
+ seen.add(slug);
1367
+ }
1368
+ for (const bundleFlow of (0,_definition_bundle_diff_js__rspack_import_10/* .orderFlows */.qG)(bundleFlows)){
1369
+ const { nodes, missing } = (0,_definition_bundle_diff_js__rspack_import_10/* .applyVariables */.gT)(bundleFlow.nodes ?? [], variables);
1370
+ const flow = {
1371
+ ...bundleFlow,
1372
+ nodes,
1373
+ edges: bundleFlow.edges ?? []
1374
+ };
1375
+ const blockers = missing.map((name)=>(0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_17/* .BUNDLE_MESSAGES.VARIABLE_MISSING */.iX.VARIABLE_MISSING, {
1376
+ name,
1377
+ flow: flow.slug
1378
+ }));
1379
+ const target = bySlug.get(flow.slug);
1380
+ if (!target && deleted.has(flow.slug)) blockers.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_17/* .BUNDLE_MESSAGES.FLOW_SLUG_DELETED */.iX.FLOW_SLUG_DELETED, {
1381
+ flow: flow.slug
1382
+ }));
1383
+ const keys = storedApiKeys(target);
1384
+ const warnings = flow.nodes.filter((node)=>needsApiKey(node) && !keys.has(node.id)).map((node)=>(0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_17/* .BUNDLE_MESSAGES.FLOW_API_KEY_GENERATED */.iX.FLOW_API_KEY_GENERATED, {
1385
+ flow: flow.slug,
1386
+ path: triggerPath(node) ?? ''
1387
+ }));
1388
+ if (!target) {
1389
+ result.planned.push({
1390
+ kind: 'create_flow',
1391
+ flow,
1392
+ existingId: null,
1393
+ details: {},
1394
+ warnings,
1395
+ blockers
1396
+ });
1397
+ continue;
1398
+ }
1399
+ const live = (0,_flow_definition_service_js__rspack_import_13/* .snapshotOf */.eY)(target);
1400
+ const changed = _interfaces_flow_definition_interface_js__rspack_import_19/* .FLOW_VERSIONED_FIELDS.filter */.v.filter((key)=>key === 'nodes' ? (0,_definition_bundle_diff_js__rspack_import_10/* .canonicalJson */.dj)((0,_definition_bundle_diff_js__rspack_import_10/* .stripApiKeys */.dX)(live.nodes ?? [])) !== (0,_definition_bundle_diff_js__rspack_import_10/* .canonicalJson */.dj)((0,_definition_bundle_diff_js__rspack_import_10/* .stripApiKeys */.dX)(flow.nodes)) : (0,_definition_bundle_diff_js__rspack_import_10/* .canonicalJson */.dj)(live[key] ?? null) !== (0,_definition_bundle_diff_js__rspack_import_10/* .canonicalJson */.dj)(flow[key] ?? null));
1401
+ if (!changed.length && (0,_flow_definition_service_js__rspack_import_13/* .isPublished */.HF)(target) && !blockers.length) {
1402
+ result.unchanged++;
1403
+ continue;
1404
+ }
1405
+ if (target.draft) warnings.push((0,_flusys_nestjs_shared_utils__rspack_import_0.messageRef)(_config_message_keys_js__rspack_import_17/* .BUNDLE_MESSAGES.FLOW_DRAFT_REPLACED */.iX.FLOW_DRAFT_REPLACED, {
1406
+ flow: flow.slug
1407
+ }));
1408
+ result.planned.push({
1409
+ kind: 'update_flow',
1410
+ flow,
1411
+ existingId: target.id,
1412
+ details: {
1413
+ changes: changed
1414
+ },
1415
+ warnings,
1416
+ blockers
1417
+ });
1418
+ }
1419
+ for (const extra of existing.filter((flow)=>!seen.has(flow.slug)))result.extras.push({
1420
+ kind: 'flow',
1421
+ flowSlug: extra.slug
1422
+ });
1423
+ return result;
1424
+ }
1425
+ // ── requests for the designer's services ────────────────────────────────────────────
1426
+ fieldSpec(field, relationTargetEntityId) {
1427
+ return {
1428
+ code: field.code,
1429
+ label: field.label,
1430
+ fieldType: field.fieldType,
1431
+ nullable: field.nullable,
1432
+ unique: field.unique,
1433
+ isIndexed: field.isIndexed,
1434
+ defaultValue: field.defaultValue ?? undefined,
1435
+ validationRules: field.validationRules ?? undefined,
1436
+ selectOptions: field.selectOptions ?? undefined,
1437
+ order: field.order,
1438
+ uiConfig: field.uiConfig ?? undefined,
1439
+ isSearchable: field.isSearchable,
1440
+ ...relationTargetEntityId ? {
1441
+ relationTargetEntityId
1442
+ } : {}
1443
+ };
1444
+ }
1445
+ createRequest(entity) {
1446
+ return {
1447
+ code: entity.code,
1448
+ label: entity.label,
1449
+ description: entity.description ?? undefined,
1450
+ isSoftDeleteEnabled: entity.isSoftDeleteEnabled,
1451
+ isAuditEnabled: entity.isAuditEnabled,
1452
+ uiConfig: entity.uiConfig ?? undefined,
1453
+ fields: entity.fields.map((field)=>this.fieldSpec(field))
1454
+ };
1455
+ }
1456
+ /** The schema change for one step, with this environment's ids (looked up now: earlier steps may have created them). */ changeRequest(operation, current) {
1457
+ const entity = current.find((e)=>e.code === operation.entityCode);
1458
+ const idOf = (code)=>code ? current.find((e)=>e.code === code)?.id : undefined;
1459
+ switch(operation.kind){
1460
+ case 'add_field':
1461
+ return {
1462
+ action: _dtos_schema_change_dto_js__rspack_import_4/* .SchemaChangeAction.ADD_FIELD */.M3.ADD_FIELD,
1463
+ entityDefinitionId: entity?.id,
1464
+ field: this.fieldSpec(operation.field, idOf(operation.field.relationTarget))
1465
+ };
1466
+ case 'rename_field':
1467
+ case 'update_field':
1468
+ {
1469
+ const { relationTarget, ...changes } = operation.changes ?? {};
1470
+ if (relationTarget !== undefined) Object.assign(changes, {
1471
+ relationTargetEntityId: idOf(relationTarget) ?? null
1472
+ });
1473
+ return {
1474
+ action: _dtos_schema_change_dto_js__rspack_import_4/* .SchemaChangeAction.UPDATE_FIELD */.M3.UPDATE_FIELD,
1475
+ fieldDefinitionId: operation.targetFieldId,
1476
+ changes
1477
+ };
1478
+ }
1479
+ case 'deprecate_field':
1480
+ return {
1481
+ action: _dtos_schema_change_dto_js__rspack_import_4/* .SchemaChangeAction.DEPRECATE_FIELD */.M3.DEPRECATE_FIELD,
1482
+ fieldDefinitionId: operation.targetFieldId
1483
+ };
1484
+ case 'restore_field':
1485
+ return {
1486
+ action: _dtos_schema_change_dto_js__rspack_import_4/* .SchemaChangeAction.RESTORE_FIELD */.M3.RESTORE_FIELD,
1487
+ fieldDefinitionId: operation.targetFieldId
1488
+ };
1489
+ default:
1490
+ return {
1491
+ action: _dtos_schema_change_dto_js__rspack_import_4/* .SchemaChangeAction.UPDATE_ENTITY */.M3.UPDATE_ENTITY,
1492
+ entityDefinitionId: entity?.id,
1493
+ changes: operation.changes
1494
+ };
1495
+ }
1496
+ }
1497
+ // ── apply ───────────────────────────────────────────────────────────────────────────
1498
+ async applyImport(dto, user) {
1499
+ const checksum = (0,_definition_bundle_diff_js__rspack_import_10/* .bundleChecksum */.i9)(dto.bundle);
1500
+ if (dto.expectedChecksum && dto.expectedChecksum !== checksum) {
1501
+ throw new _nestjs_common__rspack_import_1.ConflictException({
1502
+ message: 'The bundle is not the one that was reviewed. Plan the import again.',
1503
+ messageKey: _config_message_keys_js__rspack_import_17/* .BUNDLE_MESSAGES.CHECKSUM_MISMATCH */.iX.CHECKSUM_MISMATCH,
1504
+ messageVariables: {
1505
+ checksum
1506
+ }
1507
+ });
1508
+ }
1509
+ const { plan, operations, flows } = await this.buildPlan(dto, user);
1510
+ if (dto.expectedPlanChecksum && dto.expectedPlanChecksum !== plan.planChecksum) {
1511
+ throw new _nestjs_common__rspack_import_1.ConflictException({
1512
+ message: 'The plan changed since it was reviewed. Plan the import again.',
1513
+ messageKey: _config_message_keys_js__rspack_import_17/* .BUNDLE_MESSAGES.PLAN_CHANGED */.iX.PLAN_CHANGED,
1514
+ messageVariables: {
1515
+ planChecksum: plan.planChecksum
1516
+ }
1517
+ });
1518
+ }
1519
+ // `errors` is what the global exception filter passes on, so the caller sees every reason.
1520
+ const blockers = [
1521
+ ...plan.blockers.map((b)=>({
1522
+ field: 'bundle',
1523
+ ...b
1524
+ })),
1525
+ ...plan.steps.flatMap((s)=>s.blockers.map((b)=>({
1526
+ field: (0,_definition_bundle_diff_js__rspack_import_10/* .bundleSubject */.bs)(s),
1527
+ ...b
1528
+ })))
1529
+ ];
1530
+ if (blockers.length) {
1531
+ throw new _nestjs_common__rspack_import_1.ConflictException({
1532
+ message: 'The import is blocked. Plan it again to see why.',
1533
+ messageKey: _config_message_keys_js__rspack_import_17/* .BUNDLE_MESSAGES.APPLY_BLOCKED */.iX.APPLY_BLOCKED,
1534
+ errors: blockers
1535
+ });
1536
+ }
1537
+ if (plan.mayLoseData && dto.confirm !== true) {
1538
+ const lossy = plan.steps.filter((s)=>s.preview?.destructive || !s.preview && mayLoseData(s)).map((s)=>({
1539
+ field: (0,_definition_bundle_diff_js__rspack_import_10/* .bundleSubject */.bs)(s),
1540
+ messageKey: _config_message_keys_js__rspack_import_17/* .BUNDLE_MESSAGES.CONFIRM_REQUIRED */.iX.CONFIRM_REQUIRED
1541
+ }));
1542
+ throw new _nestjs_common__rspack_import_1.BadRequestException({
1543
+ message: 'The import loses data or information. Review the plan and resend with confirm: true.',
1544
+ messageKey: _config_message_keys_js__rspack_import_17/* .BUNDLE_MESSAGES.CONFIRM_REQUIRED */.iX.CONFIRM_REQUIRED,
1545
+ errors: lossy
1546
+ });
1547
+ }
1548
+ // A confirmation covers the steps that were reviewed, never ones the environment has grown since.
1549
+ if (plan.mayLoseData && !dto.expectedPlanChecksum) {
1550
+ throw new _nestjs_common__rspack_import_1.BadRequestException({
1551
+ message: 'Send the planChecksum of the reviewed plan as expectedPlanChecksum to confirm it.',
1552
+ messageKey: _config_message_keys_js__rspack_import_17/* .BUNDLE_MESSAGES.PLAN_CHECKSUM_REQUIRED */.iX.PLAN_CHECKSUM_REQUIRED
1553
+ });
1554
+ }
1555
+ const result = {
1556
+ checksum: plan.checksum,
1557
+ completed: true,
1558
+ steps: [],
1559
+ apiKeys: [],
1560
+ warnings: plan.steps.flatMap((s)=>s.warnings)
1561
+ };
1562
+ const note = `Imported from bundle ${plan.checksum.slice(0, 12)}`;
1563
+ const run = async (step, fn)=>{
1564
+ if (!result.completed) return result.steps.push({
1565
+ ...step,
1566
+ status: 'skipped'
1567
+ });
1568
+ try {
1569
+ await fn();
1570
+ result.steps.push({
1571
+ ...step,
1572
+ status: 'applied'
1573
+ });
1574
+ } catch (error) {
1575
+ result.completed = false;
1576
+ const reasons = failureDetails(error);
1577
+ result.steps.push({
1578
+ ...step,
1579
+ status: 'failed',
1580
+ error: (0,_flow_engine_flow_errors_js__rspack_import_8/* .errorRef */.O$)(error),
1581
+ ...reasons.length ? {
1582
+ blockers: reasons
1583
+ } : {}
1584
+ });
1585
+ }
1586
+ };
1587
+ // Entity codes and field ids never change during an import: only a created entity adds ids to look up.
1588
+ let current = await this.loadEntities();
1589
+ for (const operation of operations){
1590
+ await run({
1591
+ kind: operation.kind,
1592
+ entityCode: operation.entityCode,
1593
+ ...operation.fieldCode ? {
1594
+ fieldCode: operation.fieldCode
1595
+ } : {}
1596
+ }, ()=>this.applyEntityStep(operation, current, dto.confirm === true, user));
1597
+ if (operation.kind === 'create_entity' && result.completed) current = await this.loadEntities();
1598
+ }
1599
+ for (const planned of flows){
1600
+ await run({
1601
+ kind: planned.kind,
1602
+ flowSlug: planned.flow.slug
1603
+ }, ()=>this.applyFlowStep(planned, note, result.apiKeys, user));
1604
+ }
1605
+ return result;
1606
+ }
1607
+ async applyEntityStep(operation, current, confirm, user) {
1608
+ if (operation.kind === 'create_entity') {
1609
+ const entity = operation.entity;
1610
+ await this.schemaSync.createEntity(this.createRequest(entity), user, {
1611
+ entityId: await this.idIsFree(_entities_entity_definition_entity_js__rspack_import_5/* .EntityDefinition */.f, entity.id) ? entity.id : undefined,
1612
+ fieldIds: Object.fromEntries(await this.freeFieldIds(entity.fields))
1613
+ });
1614
+ return;
1615
+ }
1616
+ const request = {
1617
+ ...this.changeRequest(operation, current),
1618
+ confirm
1619
+ };
1620
+ const fieldId = operation.kind === 'add_field' && await this.idIsFree(_entities_field_definition_entity_js__rspack_import_6/* .FieldDefinition */.c, operation.field.id) ? operation.field.id : undefined;
1621
+ await this.evolution.apply(request, user, {
1622
+ fieldId
1623
+ });
1624
+ }
1625
+ async idIsFree(entity, id) {
1626
+ return !await (await this.provider.getRepository(entity)).exists({
1627
+ where: {
1628
+ id
1629
+ },
1630
+ withDeleted: true
1631
+ });
1632
+ }
1633
+ async freeFieldIds(fields) {
1634
+ if (!fields.length) return [];
1635
+ const taken = new Set((await (await this.provider.getRepository(_entities_field_definition_entity_js__rspack_import_6/* .FieldDefinition */.c)).find({
1636
+ select: {
1637
+ id: true
1638
+ },
1639
+ where: {
1640
+ id: (0,typeorm__rspack_import_3.In)(fields.map((f)=>f.id))
1641
+ },
1642
+ withDeleted: true
1643
+ })).map((f)=>f.id));
1644
+ return fields.filter((f)=>!taken.has(f.id)).map((f)=>[
1645
+ f.code,
1646
+ f.id
1647
+ ]);
1648
+ }
1649
+ /** Saves the flow (a Request step keeps this environment's API key, or gets a new one shown once) and publishes it. */ async applyFlowStep(planned, note, apiKeys, user) {
1650
+ const existing = planned.existingId ? await this.flows.findOrFail(planned.existingId) : undefined;
1651
+ const keys = storedApiKeys(existing);
1652
+ const generated = [];
1653
+ const nodes = planned.flow.nodes.map((node)=>{
1654
+ if (!needsApiKey(node)) return node;
1655
+ const stored = keys.get(node.id);
1656
+ if (stored) return {
1657
+ ...node,
1658
+ config: {
1659
+ ...node.config,
1660
+ apiKey: stored
1661
+ }
1662
+ };
1663
+ const key = newApiKey();
1664
+ generated.push({
1665
+ flowSlug: planned.flow.slug,
1666
+ nodeId: node.id,
1667
+ path: triggerPath(node),
1668
+ key
1669
+ });
1670
+ return {
1671
+ ...node,
1672
+ config: {
1673
+ ...node.config,
1674
+ apiKey: key
1675
+ }
1676
+ };
1677
+ });
1678
+ const values = {
1679
+ ...planned.flow,
1680
+ description: planned.flow.description ?? undefined,
1681
+ nodes
1682
+ };
1683
+ const id = existing ? (await this.flows.update({
1684
+ ...values,
1685
+ id: existing.id
1686
+ }, user), existing.id) : (await this.flows.insert(values, user)).id;
1687
+ // Saved: these keys are stored now, so they are answered even if publishing fails (the next import reuses them).
1688
+ apiKeys.push(...generated);
1689
+ await this.flows.publish(id, note, user);
1690
+ }
1691
+ }
1692
+ DefinitionBundleService = _ts_decorate([
1693
+ (0,_nestjs_common__rspack_import_1.Injectable)({
1694
+ scope: _nestjs_common__rspack_import_1.Scope.REQUEST
1695
+ }),
1696
+ _ts_param(0, (0,_nestjs_common__rspack_import_1.Inject)(_entity_builder_datasource_provider_js__rspack_import_12/* .EntityBuilderDataSourceProvider */.D)),
1697
+ _ts_param(1, (0,_nestjs_common__rspack_import_1.Inject)(_entity_builder_config_service_js__rspack_import_11/* .EntityBuilderConfigService */.E)),
1698
+ _ts_param(2, (0,_nestjs_common__rspack_import_1.Inject)(_schema_sync_service_js__rspack_import_15/* .SchemaSyncService */.W)),
1699
+ _ts_param(3, (0,_nestjs_common__rspack_import_1.Inject)(_schema_evolution_service_js__rspack_import_14/* .SchemaEvolutionService */._)),
1700
+ _ts_param(4, (0,_nestjs_common__rspack_import_1.Inject)(_flow_definition_service_js__rspack_import_13/* .FlowDefinitionService */.Tk)),
1701
+ _ts_metadata("design:type", Function),
1702
+ _ts_metadata("design:paramtypes", [
1703
+ typeof _entity_builder_datasource_provider_js__rspack_import_12/* .EntityBuilderDataSourceProvider */.D === "undefined" ? Object : _entity_builder_datasource_provider_js__rspack_import_12/* .EntityBuilderDataSourceProvider */.D,
1704
+ typeof _entity_builder_config_service_js__rspack_import_11/* .EntityBuilderConfigService */.E === "undefined" ? Object : _entity_builder_config_service_js__rspack_import_11/* .EntityBuilderConfigService */.E,
1705
+ typeof _schema_sync_service_js__rspack_import_15/* .SchemaSyncService */.W === "undefined" ? Object : _schema_sync_service_js__rspack_import_15/* .SchemaSyncService */.W,
1706
+ typeof _schema_evolution_service_js__rspack_import_14/* .SchemaEvolutionService */._ === "undefined" ? Object : _schema_evolution_service_js__rspack_import_14/* .SchemaEvolutionService */._,
1707
+ typeof _flow_definition_service_js__rspack_import_13/* .FlowDefinitionService */.Tk === "undefined" ? Object : _flow_definition_service_js__rspack_import_13/* .FlowDefinitionService */.Tk
1708
+ ])
1709
+ ], DefinitionBundleService);
1710
+
1711
+ __webpack_require__.d(__webpack_exports__, {
1712
+ P: () => (DefinitionBundleService)
10
1713
  });
11
1714
 
12
1715
 
@@ -147,13 +1850,17 @@ __webpack_require__.d(__webpack_exports__, {
147
1850
 
148
1851
  },
149
1852
  8271(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
150
- /* import */ var _config_message_keys_js__rspack_import_2 = __webpack_require__(5732);
151
- /* import */ var _enums_field_type_enum_js__rspack_import_1 = __webpack_require__(9614);
152
- /* import */ var _flow_engine_flow_types_js__rspack_import_0 = __webpack_require__(6256);
1853
+ /* import */ var _flusys_nestjs_shared_constants__rspack_import_0 = __webpack_require__(9140);
1854
+ /* import */ var _config_message_keys_js__rspack_import_4 = __webpack_require__(5732);
1855
+ /* import */ var _enums_field_type_enum_js__rspack_import_2 = __webpack_require__(9614);
1856
+ /* import */ var _flow_engine_flow_permission_logic_js__rspack_import_3 = __webpack_require__(8220);
1857
+ /* import */ var _flow_engine_flow_types_js__rspack_import_1 = __webpack_require__(6256);
1858
+
153
1859
 
154
1860
 
155
1861
 
156
- const SLUG_SUFFIX = {
1862
+
1863
+ /** The path of each endpoint's Request step: `api-flows/<entity>/<path>`. */ const ENTITY_FLOW_PATHS = {
157
1864
  insert: 'insert',
158
1865
  insertMany: 'insert-many',
159
1866
  getById: 'get-by-id',
@@ -165,7 +1872,7 @@ const SLUG_SUFFIX = {
165
1872
  bulkUpsert: 'bulk-upsert',
166
1873
  delete: 'delete'
167
1874
  };
168
- const DEFAULT_FLOW_NAME = {
1875
+ const DEFAULT_ENDPOINT_NAME = {
169
1876
  insert: 'Insert',
170
1877
  insertMany: 'Insert many',
171
1878
  getById: 'Get by id',
@@ -183,26 +1890,71 @@ const DEFAULT_INPUT_LABEL = {
183
1890
  search: 'Search'
184
1891
  };
185
1892
  const DEFAULT_NO_MATCH_MESSAGE = 'No record matches the filter.';
186
- const MAX_FLOW_NAME_LENGTH = 255;
1893
+ const MAX_NAME_LENGTH = 255;
187
1894
  /** A supplied text when it has content, the English default otherwise. */ const textOr = (value, fallback)=>value?.trim() || fallback;
188
1895
  const INPUT_TYPE = {
189
- [_enums_field_type_enum_js__rspack_import_1/* .FieldType.TEXT */.P.TEXT]: 'string',
190
- [_enums_field_type_enum_js__rspack_import_1/* .FieldType.LONG_TEXT */.P.LONG_TEXT]: 'text',
191
- [_enums_field_type_enum_js__rspack_import_1/* .FieldType.INTEGER */.P.INTEGER]: 'integer',
192
- [_enums_field_type_enum_js__rspack_import_1/* .FieldType.DECIMAL */.P.DECIMAL]: 'number',
193
- [_enums_field_type_enum_js__rspack_import_1/* .FieldType.BOOLEAN */.P.BOOLEAN]: 'boolean',
194
- [_enums_field_type_enum_js__rspack_import_1/* .FieldType.DATE */.P.DATE]: 'date',
195
- [_enums_field_type_enum_js__rspack_import_1/* .FieldType.DATETIME */.P.DATETIME]: 'datetime',
196
- [_enums_field_type_enum_js__rspack_import_1/* .FieldType.EMAIL */.P.EMAIL]: 'email',
197
- [_enums_field_type_enum_js__rspack_import_1/* .FieldType.SINGLE_SELECT */.P.SINGLE_SELECT]: 'choice',
198
- [_enums_field_type_enum_js__rspack_import_1/* .FieldType.MULTI_SELECT */.P.MULTI_SELECT]: 'array',
199
- [_enums_field_type_enum_js__rspack_import_1/* .FieldType.RELATION */.P.RELATION]: 'uuid',
200
- [_enums_field_type_enum_js__rspack_import_1/* .FieldType.JSON */.P.JSON]: 'object',
201
- [_enums_field_type_enum_js__rspack_import_1/* .FieldType.FILE */.P.FILE]: 'string'
1896
+ [_enums_field_type_enum_js__rspack_import_2/* .FieldType.TEXT */.P.TEXT]: 'string',
1897
+ [_enums_field_type_enum_js__rspack_import_2/* .FieldType.LONG_TEXT */.P.LONG_TEXT]: 'text',
1898
+ [_enums_field_type_enum_js__rspack_import_2/* .FieldType.INTEGER */.P.INTEGER]: 'integer',
1899
+ [_enums_field_type_enum_js__rspack_import_2/* .FieldType.DECIMAL */.P.DECIMAL]: 'number',
1900
+ [_enums_field_type_enum_js__rspack_import_2/* .FieldType.BOOLEAN */.P.BOOLEAN]: 'boolean',
1901
+ [_enums_field_type_enum_js__rspack_import_2/* .FieldType.DATE */.P.DATE]: 'date',
1902
+ [_enums_field_type_enum_js__rspack_import_2/* .FieldType.DATETIME */.P.DATETIME]: 'datetime',
1903
+ [_enums_field_type_enum_js__rspack_import_2/* .FieldType.EMAIL */.P.EMAIL]: 'email',
1904
+ [_enums_field_type_enum_js__rspack_import_2/* .FieldType.SINGLE_SELECT */.P.SINGLE_SELECT]: 'choice',
1905
+ [_enums_field_type_enum_js__rspack_import_2/* .FieldType.MULTI_SELECT */.P.MULTI_SELECT]: 'array',
1906
+ [_enums_field_type_enum_js__rspack_import_2/* .FieldType.RELATION */.P.RELATION]: 'uuid',
1907
+ [_enums_field_type_enum_js__rspack_import_2/* .FieldType.JSON */.P.JSON]: 'object',
1908
+ [_enums_field_type_enum_js__rspack_import_2/* .FieldType.FILE */.P.FILE]: 'uuid'
202
1909
  };
203
- const MAX_SLUG_LENGTH = 63;
204
1910
  const LIST_LIMIT = 50;
205
- /** A bulk flow runs up to three steps per item (bulkUpsert: check, write, keep), well inside FLOW_LIMITS.MAX_STEPS_PER_RUN. */ const BULK_MAX_ITEMS = 200;
1911
+ const READ_ENDPOINTS = new Set([
1912
+ 'getById',
1913
+ 'getByIds',
1914
+ 'getAll',
1915
+ 'getByFilter'
1916
+ ]);
1917
+ /** The entity permissions each endpoint asks for - the ones created with the entity; an upsert may create and update. */ const ENDPOINT_ACTIONS = {
1918
+ insert: [
1919
+ 'create'
1920
+ ],
1921
+ insertMany: [
1922
+ 'create'
1923
+ ],
1924
+ getById: [
1925
+ 'read'
1926
+ ],
1927
+ getByIds: [
1928
+ 'read'
1929
+ ],
1930
+ getAll: [
1931
+ 'read'
1932
+ ],
1933
+ getByFilter: [
1934
+ 'read'
1935
+ ],
1936
+ update: [
1937
+ 'update'
1938
+ ],
1939
+ updateMany: [
1940
+ 'update'
1941
+ ],
1942
+ bulkUpsert: [
1943
+ 'create',
1944
+ 'update'
1945
+ ],
1946
+ delete: [
1947
+ 'delete'
1948
+ ]
1949
+ };
1950
+ function endpointPermissions(entityCode, endpoint) {
1951
+ const actions = ENDPOINT_ACTIONS[endpoint].map((action)=>(0,_flow_engine_flow_permission_logic_js__rspack_import_3/* .permissionAction */.s)((0,_flusys_nestjs_shared_constants__rspack_import_0.dynamicEntityPermission)(entityCode, action)));
1952
+ return actions.length === 1 ? actions[0] : {
1953
+ type: 'group',
1954
+ operator: 'AND',
1955
+ children: actions
1956
+ };
1957
+ }
206
1958
  const COLUMN = {
207
1959
  x: 40,
208
1960
  gap: 300
@@ -219,24 +1971,60 @@ const lit = (value)=>({
219
1971
  type: 'literal',
220
1972
  value
221
1973
  });
222
- /** `customer_ticket` + getAll -> `customer-ticket-get-all`, shortened so it always fits the slug length. */ function entityFlowSlug(entityCode, endpoint) {
223
- const suffix = SLUG_SUFFIX[endpoint];
224
- const base = entityCode.replace(/_/g, '-').slice(0, MAX_SLUG_LENGTH - suffix.length - 1).replace(/-+$/, '');
225
- return `${base}-${suffix}`;
226
- }
1974
+ /** `customer_ticket` -> `customer-ticket`: an entity code always fits a flow URL name. */ const entityFlowSlug = (entityCode)=>entityCode.replace(/_/g, '-');
227
1975
  function optionValues(options) {
228
1976
  return (options ?? []).map((o)=>o && typeof o === 'object' && 'value' in o ? String(o.value) : String(o));
229
1977
  }
230
- function fieldInput(field, required) {
1978
+ const NUMERIC_TYPES = new Set([
1979
+ _enums_field_type_enum_js__rspack_import_2/* .FieldType.INTEGER */.P.INTEGER,
1980
+ _enums_field_type_enum_js__rspack_import_2/* .FieldType.DECIMAL */.P.DECIMAL
1981
+ ]);
1982
+ const TEXT_TYPES = new Set([
1983
+ _enums_field_type_enum_js__rspack_import_2/* .FieldType.TEXT */.P.TEXT,
1984
+ _enums_field_type_enum_js__rspack_import_2/* .FieldType.LONG_TEXT */.P.LONG_TEXT,
1985
+ _enums_field_type_enum_js__rspack_import_2/* .FieldType.EMAIL */.P.EMAIL
1986
+ ]);
1987
+ /** The field's rules a Request body checks the same way the record write does. */ function inputRules(field) {
1988
+ const rules = field.validationRules ?? {};
1989
+ const keys = NUMERIC_TYPES.has(field.fieldType) ? [
1990
+ 'min',
1991
+ 'max'
1992
+ ] : TEXT_TYPES.has(field.fieldType) ? [
1993
+ 'minLength',
1994
+ 'maxLength'
1995
+ ] : [];
1996
+ return Object.fromEntries(keys.filter((key)=>typeof rules[key] === 'number' && Number.isFinite(rules[key])).map((key)=>[
1997
+ key,
1998
+ rules[key]
1999
+ ]));
2000
+ }
2001
+ /**
2002
+ * The Request body input of a field: a choice carries its options, a multi-select is a list of
2003
+ * those choices, a relation or file is an id. `rules`: a write also checks the field's own value rules.
2004
+ */ function fieldInput(field, required, rules = true) {
231
2005
  const options = optionValues(field.selectOptions);
232
- const type = INPUT_TYPE[field.fieldType] === 'choice' && !options.length ? 'string' : INPUT_TYPE[field.fieldType];
233
- return {
2006
+ const base = {
234
2007
  name: field.code,
235
2008
  label: field.label || field.code,
236
- type,
237
2009
  ...required ? {
238
2010
  required: true
239
2011
  } : {},
2012
+ ...rules ? inputRules(field) : {}
2013
+ };
2014
+ if (field.fieldType === _enums_field_type_enum_js__rspack_import_2/* .FieldType.MULTI_SELECT */.P.MULTI_SELECT) return {
2015
+ ...base,
2016
+ type: 'array',
2017
+ ...options.length ? {
2018
+ itemType: 'choice',
2019
+ options
2020
+ } : {
2021
+ itemType: 'string'
2022
+ }
2023
+ };
2024
+ const type = INPUT_TYPE[field.fieldType] === 'choice' && !options.length ? 'string' : INPUT_TYPE[field.fieldType];
2025
+ return {
2026
+ ...base,
2027
+ type,
240
2028
  ...type === 'choice' ? {
241
2029
  options
242
2030
  } : {}
@@ -248,7 +2036,8 @@ const fieldMap = (fields, scope)=>Object.fromEntries(fields.map((f)=>[
248
2036
  ref(`${scope}.${f.code}`)
249
2037
  ]));
250
2038
  const optionalFieldInputs = (fields)=>fields.map((f)=>fieldInput(f, false));
251
- /** Fields an equality filter can match - a list or JSON value cannot be compared as one value. */ const filterableFields = (entity)=>entity.fields.filter((f)=>f.fieldType !== _enums_field_type_enum_js__rspack_import_1/* .FieldType.MULTI_SELECT */.P.MULTI_SELECT && f.fieldType !== _enums_field_type_enum_js__rspack_import_1/* .FieldType.JSON */.P.JSON);
2039
+ /** Inputs of a read filter: only the value's type is checked, never the write rules. */ const filterInputs = (fields)=>fields.map((f)=>fieldInput(f, false, false));
2040
+ /** Fields an equality filter can match - a list or JSON value cannot be compared as one value. */ const filterableFields = (entity)=>entity.fields.filter((f)=>f.fieldType !== _enums_field_type_enum_js__rspack_import_2/* .FieldType.MULTI_SELECT */.P.MULTI_SELECT && f.fieldType !== _enums_field_type_enum_js__rspack_import_2/* .FieldType.JSON */.P.JSON);
252
2041
  const idInput = (t)=>({
253
2042
  name: 'id',
254
2043
  label: t.inputLabels.id,
@@ -275,56 +2064,53 @@ const respond = (id, column, statusCode, body, row)=>({
275
2064
  body
276
2065
  }
277
2066
  });
278
- /** The body is the list itself (`itemSchema` checks each item): foreach `input` -> `body` (per item) ... done -> respond with the collected results. */ function bulkGraph(itemSchema, body, bodyEdges, collect, statusCode) {
279
- return {
280
- bodyType: 'list',
281
- inputSchema: itemSchema,
282
- steps: [
283
- {
284
- id: 'each',
285
- type: 'foreach',
286
- column: 1,
287
- config: {
288
- items: ref('input'),
289
- maxItems: BULK_MAX_ITEMS,
290
- collect
291
- }
292
- },
293
- ...body,
294
- respond('respond', 2, statusCode, ref('context.each.results'))
295
- ],
296
- edges: [
297
- [
298
- 'each',
299
- 'each',
300
- body[0].id
301
- ],
302
- ...bodyEdges,
303
- [
304
- 'each',
305
- 'done',
306
- 'respond'
307
- ]
308
- ],
309
- isTransactional: true
310
- };
311
- }
312
- function endpointGraph(entity, endpoint, texts) {
2067
+ /**
2068
+ * The steps of one endpoint. Its step ids are `<endpoint>_<step>` (`id()`), so the endpoints of one
2069
+ * flow never share a step. A bulk body is the list itself (`itemSchema` checks each item), written by
2070
+ * one step that walks it (`target: many`, each item read as `loop.item`), all or nothing, and
2071
+ * answered with the saved records in order.
2072
+ */ function endpointGraph(entity, endpoint, texts) {
2073
+ const id = (step)=>`${endpoint}_${step}`;
313
2074
  const entityCode = entity.code;
314
2075
  const single = (inputSchema, step, statusCode = 200)=>({
315
2076
  inputSchema,
316
2077
  steps: [
317
2078
  {
318
2079
  ...step,
2080
+ id: id('record'),
319
2081
  column: 1
320
2082
  },
321
- respond('respond', 2, statusCode, ref(`context.${step.id}`))
2083
+ respond(id('respond'), 2, statusCode, ref(`context.${id('record')}`))
2084
+ ],
2085
+ edges: [
2086
+ [
2087
+ id('record'),
2088
+ 'out',
2089
+ id('respond')
2090
+ ]
2091
+ ]
2092
+ });
2093
+ const bulk = (itemSchema, step, statusCode)=>({
2094
+ bodyType: 'list',
2095
+ inputSchema: itemSchema,
2096
+ steps: [
2097
+ {
2098
+ ...step,
2099
+ id: id('records'),
2100
+ column: 1,
2101
+ config: {
2102
+ ...step.config,
2103
+ target: 'many',
2104
+ items: ref('input')
2105
+ }
2106
+ },
2107
+ respond(id('respond'), 2, statusCode, ref(`context.${id('records')}.items`))
322
2108
  ],
323
2109
  edges: [
324
2110
  [
325
- step.id,
2111
+ id('records'),
326
2112
  'out',
327
- 'respond'
2113
+ id('respond')
328
2114
  ]
329
2115
  ]
330
2116
  });
@@ -333,7 +2119,6 @@ function endpointGraph(entity, endpoint, texts) {
333
2119
  switch(endpoint){
334
2120
  case 'insert':
335
2121
  return single(insertInputs, {
336
- id: 'record',
337
2122
  type: 'entity_insert',
338
2123
  config: {
339
2124
  entityCode,
@@ -341,23 +2126,17 @@ function endpointGraph(entity, endpoint, texts) {
341
2126
  }
342
2127
  }, 201);
343
2128
  case 'insertMany':
344
- return bulkGraph(insertInputs, [
345
- {
346
- id: 'record',
347
- type: 'entity_insert',
348
- column: 1,
349
- row: 1,
350
- config: {
351
- entityCode,
352
- fields: fieldMap(entity.fields, 'loop.item')
353
- }
2129
+ return bulk(insertInputs, {
2130
+ type: 'entity_insert',
2131
+ config: {
2132
+ entityCode,
2133
+ fields: fieldMap(entity.fields, 'loop.item')
354
2134
  }
355
- ], [], ref('context.record'), 201);
2135
+ }, 201);
356
2136
  case 'getById':
357
2137
  return single([
358
2138
  idInput(texts)
359
2139
  ], {
360
- id: 'record',
361
2140
  type: 'entity_get',
362
2141
  config: {
363
2142
  entityCode,
@@ -368,7 +2147,6 @@ function endpointGraph(entity, endpoint, texts) {
368
2147
  return single([
369
2148
  idsInput(texts)
370
2149
  ], {
371
- id: 'records',
372
2150
  type: 'entity_query',
373
2151
  config: {
374
2152
  entityCode,
@@ -378,7 +2156,7 @@ function endpointGraph(entity, endpoint, texts) {
378
2156
  value: ref('input.ids')
379
2157
  }
380
2158
  },
381
- limit: _flow_engine_flow_types_js__rspack_import_0/* .FLOW_LIMITS.MAX_QUERY_LIMIT */.Or.MAX_QUERY_LIMIT
2159
+ limit: _flow_engine_flow_types_js__rspack_import_1/* .FLOW_LIMITS.MAX_QUERY_LIMIT */.Or.MAX_QUERY_LIMIT
382
2160
  }
383
2161
  });
384
2162
  case 'getAll':
@@ -388,9 +2166,8 @@ function endpointGraph(entity, endpoint, texts) {
388
2166
  label: texts.inputLabels.search,
389
2167
  type: 'string'
390
2168
  },
391
- ...optionalFieldInputs(filterFields)
2169
+ ...filterInputs(filterFields)
392
2170
  ], {
393
- id: 'records',
394
2171
  type: 'entity_query',
395
2172
  config: {
396
2173
  entityCode,
@@ -406,11 +2183,11 @@ function endpointGraph(entity, endpoint, texts) {
406
2183
  ...idInput(texts),
407
2184
  required: false
408
2185
  },
409
- ...optionalFieldInputs(filterFields)
2186
+ ...filterInputs(filterFields)
410
2187
  ],
411
2188
  steps: [
412
2189
  {
413
- id: 'records',
2190
+ id: id('records'),
414
2191
  type: 'entity_query',
415
2192
  column: 1,
416
2193
  config: {
@@ -423,7 +2200,7 @@ function endpointGraph(entity, endpoint, texts) {
423
2200
  }
424
2201
  },
425
2202
  {
426
- id: 'found',
2203
+ id: id('found'),
427
2204
  type: 'condition',
428
2205
  column: 2,
429
2206
  config: {
@@ -431,35 +2208,35 @@ function endpointGraph(entity, endpoint, texts) {
431
2208
  operator: 'AND',
432
2209
  conditions: [
433
2210
  {
434
- field: 'context.records.items',
2211
+ field: `context.${id('records')}.items`,
435
2212
  comparison: 'is_not_empty'
436
2213
  }
437
2214
  ]
438
2215
  }
439
2216
  }
440
2217
  },
441
- respond('respond', 3, 200, ref('context.records.items.0')),
442
- respond('not_found', 3, 404, {
2218
+ respond(id('respond'), 3, 200, ref(`context.${id('records')}.items.0`)),
2219
+ respond(id('not_found'), 3, 404, {
443
2220
  success: lit(false),
444
2221
  message: lit(texts.noMatchMessage),
445
- messageKey: lit(_config_message_keys_js__rspack_import_2/* .GENERIC_RECORD_MESSAGES.NO_MATCH */.j4.NO_MATCH)
2222
+ messageKey: lit(_config_message_keys_js__rspack_import_4/* .GENERIC_RECORD_MESSAGES.NO_MATCH */.j4.NO_MATCH)
446
2223
  }, 1)
447
2224
  ],
448
2225
  edges: [
449
2226
  [
450
- 'records',
2227
+ id('records'),
451
2228
  'out',
452
- 'found'
2229
+ id('found')
453
2230
  ],
454
2231
  [
455
- 'found',
2232
+ id('found'),
456
2233
  'true',
457
- 'respond'
2234
+ id('respond')
458
2235
  ],
459
2236
  [
460
- 'found',
2237
+ id('found'),
461
2238
  'false',
462
- 'not_found'
2239
+ id('not_found')
463
2240
  ]
464
2241
  ]
465
2242
  };
@@ -468,7 +2245,6 @@ function endpointGraph(entity, endpoint, texts) {
468
2245
  idInput(texts),
469
2246
  ...optionalFieldInputs(entity.fields)
470
2247
  ], {
471
- id: 'record',
472
2248
  type: 'entity_update',
473
2249
  config: {
474
2250
  entityCode,
@@ -477,117 +2253,35 @@ function endpointGraph(entity, endpoint, texts) {
477
2253
  }
478
2254
  });
479
2255
  case 'updateMany':
480
- return bulkGraph([
2256
+ return bulk([
481
2257
  idInput(texts),
482
2258
  ...optionalFieldInputs(entity.fields)
483
- ], [
484
- {
485
- id: 'record',
486
- type: 'entity_update',
487
- column: 1,
488
- row: 1,
489
- config: {
490
- entityCode,
491
- id: ref('loop.item.id'),
492
- fields: fieldMap(entity.fields, 'loop.item')
493
- }
2259
+ ], {
2260
+ type: 'entity_update',
2261
+ config: {
2262
+ entityCode,
2263
+ fields: fieldMap(entity.fields, 'loop.item')
494
2264
  }
495
- ], [], ref('context.record'), 200);
2265
+ }, 200);
496
2266
  case 'bulkUpsert':
497
- return bulkGraph([
2267
+ return bulk([
498
2268
  {
499
2269
  ...idInput(texts),
500
2270
  required: false
501
2271
  },
502
2272
  ...optionalFieldInputs(entity.fields)
503
- ], [
504
- {
505
- id: 'has_id',
506
- type: 'condition',
507
- column: 1,
508
- row: 1,
509
- config: {
510
- rule: {
511
- operator: 'AND',
512
- conditions: [
513
- {
514
- field: 'loop.item.id',
515
- comparison: 'is_not_empty'
516
- }
517
- ]
518
- }
519
- }
520
- },
521
- {
522
- id: 'updated',
523
- type: 'entity_update',
524
- column: 2,
525
- row: 1,
526
- config: {
527
- entityCode,
528
- id: ref('loop.item.id'),
529
- fields: fieldMap(entity.fields, 'loop.item')
530
- }
531
- },
532
- {
533
- id: 'inserted',
534
- type: 'entity_insert',
535
- column: 2,
536
- row: 2,
537
- config: {
538
- entityCode,
539
- fields: fieldMap(entity.fields, 'loop.item')
540
- }
541
- },
542
- {
543
- id: 'keep_updated',
544
- type: 'set',
545
- column: 3,
546
- row: 1,
547
- config: {
548
- values: {
549
- saved: ref('context.updated')
550
- }
551
- }
552
- },
553
- {
554
- id: 'keep_inserted',
555
- type: 'set',
556
- column: 3,
557
- row: 2,
558
- config: {
559
- values: {
560
- saved: ref('context.inserted')
561
- }
562
- }
2273
+ ], {
2274
+ type: 'entity_update',
2275
+ config: {
2276
+ entityCode,
2277
+ fields: fieldMap(entity.fields, 'loop.item'),
2278
+ onNotFound: 'insert'
563
2279
  }
564
- ], [
565
- [
566
- 'has_id',
567
- 'true',
568
- 'updated'
569
- ],
570
- [
571
- 'has_id',
572
- 'false',
573
- 'inserted'
574
- ],
575
- [
576
- 'updated',
577
- 'out',
578
- 'keep_updated'
579
- ],
580
- [
581
- 'inserted',
582
- 'out',
583
- 'keep_inserted'
584
- ]
585
- ], ref('vars.saved'), 200);
2280
+ }, 200);
586
2281
  case 'delete':
587
2282
  return single([
588
2283
  idInput(texts)
589
2284
  ], {
590
- id: 'record',
591
2285
  type: 'entity_delete',
592
2286
  config: {
593
2287
  entityCode,
@@ -597,11 +2291,15 @@ function endpointGraph(entity, endpoint, texts) {
597
2291
  }
598
2292
  }
599
2293
  /**
600
- * A ready-made flow for one record endpoint of the generic API controller. It runs as the
601
- * caller, so the entity permissions still decide who may use it, and it is an ordinary flow
602
- * afterwards - the user can change or delete it like any other. The bulk endpoints take the list
603
- * of records as the body and loop over it in one transaction, so a failing item rolls back the whole request.
604
- */ function buildEntityFlow(entity, endpoint, texts = {}) {
2294
+ * The ready-made flow of an entity: `api-flows/<entity>` with one Request step per endpoint of the
2295
+ * generic API controller, each on its own path (`ENTITY_FLOW_PATHS`) with its own body, laid out
2296
+ * one below the other. Each asks its caller for the entity's own permission (`entity_builder.entity.<code>.<action>`,
2297
+ * created with the entity), since a flow's access is its only gate, and it is an ordinary flow
2298
+ * afterwards - the user can change or delete it like any other. A
2299
+ * write endpoint is transactional: a bulk endpoint writes its whole list in one step, so a failing
2300
+ * item rolls back the whole request; a read endpoint opens none. A bulk body holds at most
2301
+ * FLOW_LIMITS.MAX_WRITE_ITEMS items.
2302
+ */ function buildEntityFlow(entity, endpoints, texts = {}) {
605
2303
  const resolved = {
606
2304
  inputLabels: {
607
2305
  id: textOr(texts.inputLabels?.id, DEFAULT_INPUT_LABEL.id),
@@ -610,57 +2308,65 @@ function endpointGraph(entity, endpoint, texts) {
610
2308
  },
611
2309
  noMatchMessage: textOr(texts.noMatchMessage, DEFAULT_NO_MATCH_MESSAGE)
612
2310
  };
613
- const graph = endpointGraph(entity, endpoint, resolved);
614
- const nodes = [
615
- {
616
- id: 'trigger',
2311
+ const nodes = [];
2312
+ const edges = [];
2313
+ let band = 0;
2314
+ for (const endpoint of endpoints){
2315
+ const graph = endpointGraph(entity, endpoint, resolved);
2316
+ const at = (column, row = 0)=>({
2317
+ x: COLUMN.x + column * COLUMN.gap,
2318
+ y: ROW.y + (band + row) * ROW.gap
2319
+ });
2320
+ const config = {
2321
+ path: ENTITY_FLOW_PATHS[endpoint],
2322
+ bodyType: graph.bodyType ?? 'object',
2323
+ inputSchema: graph.inputSchema,
2324
+ authMode: 'permission',
2325
+ permissions: endpointPermissions(entity.code, endpoint),
2326
+ ...READ_ENDPOINTS.has(endpoint) ? {} : {
2327
+ isTransactional: true
2328
+ }
2329
+ };
2330
+ nodes.push({
2331
+ id: endpoint,
617
2332
  type: 'trigger',
618
- name: '',
619
- position: {
620
- x: COLUMN.x,
621
- y: ROW.y
622
- },
623
- config: {}
624
- },
625
- ...graph.steps.map(({ column, row, ...step })=>({
2333
+ name: textOr(texts.names?.[endpoint], DEFAULT_ENDPOINT_NAME[endpoint]).slice(0, MAX_NAME_LENGTH),
2334
+ position: at(0),
2335
+ config
2336
+ }, ...graph.steps.map(({ column, row, ...step })=>({
626
2337
  ...step,
627
2338
  name: '',
628
- position: {
629
- x: COLUMN.x + column * COLUMN.gap,
630
- y: ROW.y + (row ?? 0) * ROW.gap
631
- }
632
- }))
633
- ];
634
- const edges = [
635
- [
636
- 'trigger',
637
- 'out',
638
- graph.steps[0].id
639
- ],
640
- ...graph.edges
641
- ].map(([from, port, to])=>({
642
- id: `e_${from}_${port}_${to}`,
643
- from,
644
- port,
645
- to
646
- }));
2339
+ position: at(column, row)
2340
+ })));
2341
+ edges.push(...[
2342
+ [
2343
+ endpoint,
2344
+ 'out',
2345
+ graph.steps[0].id
2346
+ ],
2347
+ ...graph.edges
2348
+ ].map(([from, port, to])=>({
2349
+ id: `e_${from}_${port}_${to}`,
2350
+ from,
2351
+ port,
2352
+ to
2353
+ })));
2354
+ band += 1 + Math.max(0, ...graph.steps.map((step)=>step.row ?? 0));
2355
+ }
647
2356
  return {
648
- name: `${entity.label} - ${textOr(texts.names?.[endpoint], DEFAULT_FLOW_NAME[endpoint])}`.slice(0, MAX_FLOW_NAME_LENGTH),
649
- slug: entityFlowSlug(entity.code, endpoint),
2357
+ name: entity.label.slice(0, MAX_NAME_LENGTH),
2358
+ slug: entityFlowSlug(entity.code),
650
2359
  isActive: true,
651
- authMode: 'jwt',
652
- runAs: 'caller',
653
- isTransactional: graph.isTransactional ?? false,
654
- bodyType: graph.bodyType ?? 'object',
655
- inputSchema: graph.inputSchema,
656
2360
  nodes,
657
2361
  edges
658
2362
  };
659
2363
  }
660
2364
 
661
2365
  __webpack_require__.d(__webpack_exports__, {
662
- C: () => (buildEntityFlow),
663
- x: () => (entityFlowSlug)
2366
+ CO: () => (buildEntityFlow)
2367
+ }, {
2368
+ IP: ENTITY_FLOW_PATHS,
2369
+ x2: entityFlowSlug
664
2370
  });
665
2371
 
666
2372
 
@@ -1854,8 +3560,8 @@ class SchemaEvolutionService {
1854
3560
  const prepared = await this.prepare(request, user);
1855
3561
  return this.executor.simulate(prepared.target, prepared.run, prepared.impact);
1856
3562
  }
1857
- async apply(request, user) {
1858
- const prepared = await this.prepare(request, user);
3563
+ /** `options.fieldId`: the id add_field gives the new field (an import keeps the id it has where it was designed). */ async apply(request, user, options = {}) {
3564
+ const prepared = await this.prepare(request, user, options.fieldId);
1859
3565
  const { plan, outcome } = await this.executor.apply(prepared.target, prepared.run, {
1860
3566
  confirm: request.confirm === true,
1861
3567
  impact: prepared.impact
@@ -2033,10 +3739,10 @@ class SchemaEvolutionService {
2033
3739
  return true;
2034
3740
  }
2035
3741
  // ── dispatch ────────────────────────────────────────────────────────────────────────
2036
- async prepare(request, user) {
3742
+ async prepare(request, user, fieldId) {
2037
3743
  switch(request.action){
2038
3744
  case _dtos_schema_change_dto_js__rspack_import_6/* .SchemaChangeAction.ADD_FIELD */.M3.ADD_FIELD:
2039
- return this.prepareAddField(request, user);
3745
+ return this.prepareAddField(request, user, fieldId);
2040
3746
  case _dtos_schema_change_dto_js__rspack_import_6/* .SchemaChangeAction.UPDATE_FIELD */.M3.UPDATE_FIELD:
2041
3747
  return this.prepareUpdateField(request, user);
2042
3748
  case _dtos_schema_change_dto_js__rspack_import_6/* .SchemaChangeAction.DEPRECATE_FIELD */.M3.DEPRECATE_FIELD:
@@ -2133,7 +3839,7 @@ class SchemaEvolutionService {
2133
3839
  return table.indices.filter((i)=>i.columnNames.length === 1 && i.columnNames[0] === column && i.isUnique === unique);
2134
3840
  }
2135
3841
  // ── add_field ───────────────────────────────────────────────────────────────────────
2136
- async prepareAddField(request, user) {
3842
+ async prepareAddField(request, user, fieldId) {
2137
3843
  const { definition: loaded } = await this.loadEntity(request.entityDefinitionId);
2138
3844
  const spec = request.field;
2139
3845
  if (!spec) {
@@ -2158,7 +3864,12 @@ class SchemaEvolutionService {
2158
3864
  const nullable = spec.nullable ?? true;
2159
3865
  const unique = spec.unique ?? false;
2160
3866
  const dbType = this.adapter.mapFieldType(spec.fieldType, ctx.driver);
2161
- if (spec.relationTargetEntityId) {
3867
+ const isRelation = spec.fieldType === _enums_field_type_enum_js__rspack_import_20/* .FieldType.RELATION */.P.RELATION;
3868
+ if (isRelation && !spec.relationTargetEntityId) {
3869
+ ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.RELATION_TARGET_REQUIRED */.M3.RELATION_TARGET_REQUIRED, {
3870
+ field: spec.code
3871
+ }));
3872
+ } else if (isRelation) {
2162
3873
  const target = await ctx.qr.manager.getRepository(_entities_entity_definition_entity_js__rspack_import_7/* .EntityDefinition */.f).findOne({
2163
3874
  where: {
2164
3875
  id: spec.relationTargetEntityId
@@ -2198,8 +3909,8 @@ class SchemaEvolutionService {
2198
3909
  }));
2199
3910
  }
2200
3911
  }
2201
- // Every existing row gets the same backfill value, so two rows or more would clash.
2202
- if (unique && backfill !== null && rows > 1) {
3912
+ // Only a required field is backfilled; every existing row gets the same value, so two rows or more would clash.
3913
+ if (unique && !nullable && backfill !== null && rows > 1) {
2203
3914
  ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_19/* .SCHEMA_BLOCKER_MESSAGES.UNIQUE_BACKFILL_CONFLICT */.M3.UNIQUE_BACKFILL_CONFLICT));
2204
3915
  }
2205
3916
  if (ctx.blocked || !table) {
@@ -2249,10 +3960,13 @@ class SchemaEvolutionService {
2249
3960
  await ctx.qr.createIndex(table, (0,_schema_columns_js__rspack_import_17/* .plainIndex */.v7)(definition.tableName, spec.code, ctx.driver, this.adapter));
2250
3961
  });
2251
3962
  }
2252
- let fieldId = null;
3963
+ let savedFieldId = null;
2253
3964
  await ctx.metadata(async ()=>{
2254
3965
  const repo = ctx.qr.manager.getRepository(_entities_field_definition_entity_js__rspack_import_8/* .FieldDefinition */.c);
2255
3966
  const saved = await repo.save(repo.create({
3967
+ ...fieldId ? {
3968
+ id: fieldId
3969
+ } : {},
2256
3970
  entityDefinitionId: definition.id,
2257
3971
  code: spec.code,
2258
3972
  label: spec.label,
@@ -2264,18 +3978,18 @@ class SchemaEvolutionService {
2264
3978
  defaultValue: spec.defaultValue ?? null,
2265
3979
  validationRules: spec.validationRules ?? null,
2266
3980
  selectOptions: spec.selectOptions ?? null,
2267
- relationTargetEntityId: spec.relationTargetEntityId ?? null,
3981
+ relationTargetEntityId: isRelation ? spec.relationTargetEntityId : null,
2268
3982
  order: spec.order ?? Math.max(-1, ...fields.map((f)=>f.order)) + 1,
2269
3983
  uiConfig: spec.uiConfig ?? null,
2270
3984
  isSearchable: spec.isSearchable ?? false,
2271
3985
  isSystemField: false,
2272
3986
  deprecatedAt: null
2273
3987
  }));
2274
- fieldId = saved.id;
3988
+ savedFieldId = saved.id;
2275
3989
  });
2276
3990
  return {
2277
3991
  operation: _enums_ddl_operation_enum_js__rspack_import_21/* .DdlOperation.ADD_COLUMN */.i.ADD_COLUMN,
2278
- fieldDefinitionId: fieldId,
3992
+ fieldDefinitionId: savedFieldId,
2279
3993
  diff: {
2280
3994
  field: {
2281
3995
  code: spec.code,
@@ -3280,21 +4994,23 @@ __webpack_require__.d(__webpack_exports__, {
3280
4994
  /* import */ var _flusys_nestjs_shared_utils__rspack_import_1 = __webpack_require__(9216);
3281
4995
  /* import */ var _nestjs_common__rspack_import_2 = __webpack_require__(6157);
3282
4996
  /* import */ var typeorm__rspack_import_3 = __webpack_require__(7158);
3283
- /* import */ var _config_message_keys_js__rspack_import_16 = __webpack_require__(5732);
4997
+ /* import */ var _config_message_keys_js__rspack_import_17 = __webpack_require__(5732);
3284
4998
  /* import */ var _entities_entity_definition_entity_js__rspack_import_4 = __webpack_require__(3189);
3285
4999
  /* import */ var _entities_field_definition_entity_js__rspack_import_5 = __webpack_require__(2206);
3286
5000
  /* import */ var _entities_flow_definition_entity_js__rspack_import_6 = __webpack_require__(3770);
3287
- /* import */ var _enums_ddl_operation_enum_js__rspack_import_18 = __webpack_require__(9949);
3288
- /* import */ var _enums_entity_status_enum_js__rspack_import_19 = __webpack_require__(1313);
5001
+ /* import */ var _enums_ddl_operation_enum_js__rspack_import_20 = __webpack_require__(9949);
5002
+ /* import */ var _enums_entity_status_enum_js__rspack_import_21 = __webpack_require__(1313);
5003
+ /* import */ var _enums_field_type_enum_js__rspack_import_19 = __webpack_require__(9614);
3289
5004
  /* import */ var _flow_engine_flow_errors_js__rspack_import_7 = __webpack_require__(8542);
3290
5005
  /* import */ var _entity_builder_datasource_provider_js__rspack_import_8 = __webpack_require__(424);
3291
5006
  /* import */ var _entity_flow_scaffold_js__rspack_import_9 = __webpack_require__(8271);
3292
5007
  /* import */ var _entity_permission_service_js__rspack_import_10 = __webpack_require__(1462);
3293
- /* import */ var _flow_definition_service_js__rspack_import_11 = __webpack_require__(5229);
3294
- /* import */ var _identifier_rules_js__rspack_import_12 = __webpack_require__(413);
3295
- /* import */ var _schema_change_executor_service_js__rspack_import_13 = __webpack_require__(6605);
3296
- /* import */ var _schema_columns_js__rspack_import_14 = __webpack_require__(5313);
3297
- /* import */ var _schema_dialect_adapter_service_js__rspack_import_15 = __webpack_require__(7259);
5008
+ /* import */ var _field_value_validator_js__rspack_import_11 = __webpack_require__(3525);
5009
+ /* import */ var _flow_definition_service_js__rspack_import_12 = __webpack_require__(5229);
5010
+ /* import */ var _identifier_rules_js__rspack_import_13 = __webpack_require__(413);
5011
+ /* import */ var _schema_change_executor_service_js__rspack_import_14 = __webpack_require__(6605);
5012
+ /* import */ var _schema_columns_js__rspack_import_15 = __webpack_require__(5313);
5013
+ /* import */ var _schema_dialect_adapter_service_js__rspack_import_16 = __webpack_require__(7259);
3298
5014
  function _ts_decorate(decorators, target, key, desc) {
3299
5015
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3300
5016
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -3338,6 +5054,11 @@ function _ts_param(paramIndex, decorator) {
3338
5054
 
3339
5055
 
3340
5056
 
5057
+
5058
+
5059
+ const presetId = (id)=>id ? {
5060
+ id
5061
+ } : {};
3341
5062
  class SchemaSyncService {
3342
5063
  dataSourceProvider;
3343
5064
  dialectAdapter;
@@ -3353,17 +5074,17 @@ class SchemaSyncService {
3353
5074
  this.flowDefinitionService = flowDefinitionService;
3354
5075
  }
3355
5076
  validateCreateRequest(dto) {
3356
- (0,_identifier_rules_js__rspack_import_12/* .assertValidIdentifier */.kV)(dto.code, 'entity');
5077
+ (0,_identifier_rules_js__rspack_import_13/* .assertValidIdentifier */.kV)(dto.code, 'entity');
3357
5078
  const fields = dto.fields ?? [];
3358
5079
  for (const field of fields){
3359
- (0,_identifier_rules_js__rspack_import_12/* .assertValidIdentifier */.kV)(field.code, 'field');
3360
- (0,_identifier_rules_js__rspack_import_12/* .assertIndexableField */.fY)(field);
5080
+ (0,_identifier_rules_js__rspack_import_13/* .assertValidIdentifier */.kV)(field.code, 'field');
5081
+ (0,_identifier_rules_js__rspack_import_13/* .assertIndexableField */.fY)(field);
3361
5082
  }
3362
5083
  const duplicate = fields.map((f)=>f.code).find((code, index, all)=>all.indexOf(code) !== index);
3363
5084
  if (duplicate) {
3364
5085
  throw new _nestjs_common__rspack_import_2.BadRequestException({
3365
5086
  message: `Field code '${duplicate}' is defined more than once.`,
3366
- messageKey: _config_message_keys_js__rspack_import_16/* .SCHEMA_MESSAGES.DUPLICATE_FIELD_CODE */.Hu.DUPLICATE_FIELD_CODE,
5087
+ messageKey: _config_message_keys_js__rspack_import_17/* .SCHEMA_MESSAGES.DUPLICATE_FIELD_CODE */.Hu.DUPLICATE_FIELD_CODE,
3367
5088
  messageVariables: {
3368
5089
  code: duplicate
3369
5090
  }
@@ -3371,7 +5092,7 @@ class SchemaSyncService {
3371
5092
  }
3372
5093
  }
3373
5094
  async createTarget(dto, user) {
3374
- const lockCodes = await (0,_schema_change_executor_service_js__rspack_import_13/* .relationTargetCodes */.e)(this.dataSourceProvider, (dto.fields ?? []).map((f)=>f.relationTargetEntityId));
5095
+ const lockCodes = await (0,_schema_change_executor_service_js__rspack_import_14/* .relationTargetCodes */.e)(this.dataSourceProvider, (dto.fields ?? []).map((f)=>f.relationTargetEntityId));
3375
5096
  return {
3376
5097
  action: 'create_entity',
3377
5098
  entityDefinitionId: null,
@@ -3381,7 +5102,7 @@ class SchemaSyncService {
3381
5102
  lockCodes
3382
5103
  };
3383
5104
  }
3384
- createRun(dto, user, created) {
5105
+ createRun(dto, user, created, ids = {}) {
3385
5106
  const tableName = `${(/* inlined export .ENTITY_TABLE_PREFIX */"eb_")}${dto.code}`;
3386
5107
  const fieldSpecs = dto.fields ?? [];
3387
5108
  const flowEndpoints = dto.flowEndpoints ?? [];
@@ -3392,7 +5113,7 @@ class SchemaSyncService {
3392
5113
  const taken = await ctx.qr.query((0,_flusys_nestjs_shared_classes__rspack_import_0.buildQuery)(`SELECT table_name FROM information_schema.tables WHERE table_schema = ${schemaExpr} AND table_name = ?`, ctx.driver), [
3393
5114
  tableName
3394
5115
  ]);
3395
- if (taken.length) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_16/* .SCHEMA_BLOCKER_MESSAGES.TABLE_EXISTS */.M3.TABLE_EXISTS, {
5116
+ if (taken.length) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_17/* .SCHEMA_BLOCKER_MESSAGES.TABLE_EXISTS */.M3.TABLE_EXISTS, {
3396
5117
  table: tableName
3397
5118
  }));
3398
5119
  const definitions = ctx.qr.manager.getRepository(_entities_entity_definition_entity_js__rspack_import_4/* .EntityDefinition */.f);
@@ -3401,41 +5122,61 @@ class SchemaSyncService {
3401
5122
  code: dto.code
3402
5123
  }
3403
5124
  });
3404
- if (known) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_16/* .SCHEMA_BLOCKER_MESSAGES.ENTITY_CODE_EXISTS */.M3.ENTITY_CODE_EXISTS, {
5125
+ if (known) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_17/* .SCHEMA_BLOCKER_MESSAGES.ENTITY_CODE_EXISTS */.M3.ENTITY_CODE_EXISTS, {
3405
5126
  code: dto.code
3406
5127
  }));
3407
- for (const spec of fieldSpecs){
3408
- if (spec.relationTargetEntityId) {
3409
- const target = await definitions.findOne({
3410
- where: {
3411
- id: spec.relationTargetEntityId
3412
- }
3413
- });
3414
- if (!target) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_16/* .SCHEMA_BLOCKER_MESSAGES.RELATION_FIELD_TARGET_MISSING */.M3.RELATION_FIELD_TARGET_MISSING, {
5128
+ for (const spec of fieldSpecs.filter((f)=>f.fieldType === _enums_field_type_enum_js__rspack_import_19/* .FieldType.RELATION */.P.RELATION)){
5129
+ if (!spec.relationTargetEntityId) {
5130
+ ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_17/* .SCHEMA_BLOCKER_MESSAGES.RELATION_TARGET_REQUIRED */.M3.RELATION_TARGET_REQUIRED, {
3415
5131
  field: spec.code
3416
5132
  }));
5133
+ continue;
3417
5134
  }
5135
+ const target = await definitions.findOne({
5136
+ where: {
5137
+ id: spec.relationTargetEntityId
5138
+ }
5139
+ });
5140
+ if (!target) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_17/* .SCHEMA_BLOCKER_MESSAGES.RELATION_FIELD_TARGET_MISSING */.M3.RELATION_FIELD_TARGET_MISSING, {
5141
+ field: spec.code
5142
+ }));
3418
5143
  }
5144
+ const withDefault = fieldSpecs.filter((f)=>f.defaultValue !== undefined && f.defaultValue !== null);
5145
+ const { errors: defaultErrors } = (0,_field_value_validator_js__rspack_import_11/* .validateRecord */.e)(withDefault.map((f)=>({
5146
+ code: f.code,
5147
+ label: f.label,
5148
+ fieldType: f.fieldType,
5149
+ nullable: true,
5150
+ defaultValue: null,
5151
+ selectOptions: f.selectOptions ?? null,
5152
+ validationRules: f.validationRules ?? null
5153
+ })), Object.fromEntries(withDefault.map((f)=>[
5154
+ f.code,
5155
+ f.defaultValue
5156
+ ])), 'insert');
5157
+ for (const error of defaultErrors)ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_17/* .SCHEMA_BLOCKER_MESSAGES.DEFAULT_INVALID */.M3.DEFAULT_INVALID, {
5158
+ problem: (0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(error.messageKey, error.messageVariables)
5159
+ }));
3419
5160
  if (flowEndpoints.length) {
3420
- const slugs = flowEndpoints.map((endpoint)=>(0,_entity_flow_scaffold_js__rspack_import_9/* .entityFlowSlug */.x)(dto.code, endpoint));
3421
- const clashes = await ctx.qr.manager.getRepository(_entities_flow_definition_entity_js__rspack_import_6/* .FlowDefinition */.G).find({
5161
+ const slug = (0,_entity_flow_scaffold_js__rspack_import_9/* .entityFlowSlug */.x2)(dto.code);
5162
+ const clash = await ctx.qr.manager.getRepository(_entities_flow_definition_entity_js__rspack_import_6/* .FlowDefinition */.G).findOne({
3422
5163
  select: {
3423
5164
  slug: true
3424
5165
  },
3425
5166
  where: {
3426
- slug: (0,typeorm__rspack_import_3.In)(slugs)
5167
+ slug
3427
5168
  },
3428
5169
  withDeleted: true
3429
5170
  });
3430
- for (const clash of clashes)ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_16/* .SCHEMA_BLOCKER_MESSAGES.FLOW_SLUG_TAKEN */.M3.FLOW_SLUG_TAKEN, {
3431
- slug: clash.slug
5171
+ if (clash) ctx.block((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_17/* .SCHEMA_BLOCKER_MESSAGES.FLOW_SLUG_TAKEN */.M3.FLOW_SLUG_TAKEN, {
5172
+ slug
3432
5173
  }));
3433
5174
  }
3434
5175
  if (ctx.blocked) return {
3435
- operation: _enums_ddl_operation_enum_js__rspack_import_18/* .DdlOperation.CREATE_TABLE */.i.CREATE_TABLE,
5176
+ operation: _enums_ddl_operation_enum_js__rspack_import_20/* .DdlOperation.CREATE_TABLE */.i.CREATE_TABLE,
3436
5177
  diff: {}
3437
5178
  };
3438
- const columns = fieldSpecs.map((spec)=>(0,_schema_columns_js__rspack_import_14/* .buildFieldColumn */.fu)({
5179
+ const columns = fieldSpecs.map((spec)=>(0,_schema_columns_js__rspack_import_15/* .buildFieldColumn */.fu)({
3439
5180
  code: spec.code,
3440
5181
  fieldType: spec.fieldType,
3441
5182
  dbType: '',
@@ -3448,33 +5189,34 @@ class SchemaSyncService {
3448
5189
  const table = new typeorm__rspack_import_3.Table({
3449
5190
  name: tableName,
3450
5191
  columns: [
3451
- ...(0,_schema_columns_js__rspack_import_14/* .buildSystemColumns */.Rm)({
5192
+ ...(0,_schema_columns_js__rspack_import_15/* .buildSystemColumns */.Rm)({
3452
5193
  isSoftDeleteEnabled,
3453
5194
  isAuditEnabled
3454
5195
  }, ctx.driver),
3455
5196
  ...columns
3456
5197
  ]
3457
5198
  });
3458
- await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_16/* .SCHEMA_STEP_MESSAGES.CREATE_TABLE */.EQ.CREATE_TABLE, {
5199
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_17/* .SCHEMA_STEP_MESSAGES.CREATE_TABLE */.EQ.CREATE_TABLE, {
3459
5200
  table: tableName
3460
5201
  }), async ()=>{
3461
5202
  await ctx.qr.createTable(table, false);
3462
5203
  });
3463
5204
  for (const spec of fieldSpecs.filter((f)=>f.isIndexed && !f.unique)){
3464
- await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_16/* .SCHEMA_STEP_MESSAGES.ADD_INDEX */.EQ.ADD_INDEX, {
5205
+ await ctx.ddl((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_17/* .SCHEMA_STEP_MESSAGES.ADD_INDEX */.EQ.ADD_INDEX, {
3465
5206
  column: spec.code
3466
5207
  }), async ()=>{
3467
- await ctx.qr.createIndex(table, (0,_schema_columns_js__rspack_import_14/* .plainIndex */.v7)(tableName, spec.code, ctx.driver, this.dialectAdapter));
5208
+ await ctx.qr.createIndex(table, (0,_schema_columns_js__rspack_import_15/* .plainIndex */.v7)(tableName, spec.code, ctx.driver, this.dialectAdapter));
3468
5209
  });
3469
5210
  }
3470
5211
  await ctx.metadata(async ()=>{
3471
5212
  const definitionRepo = ctx.qr.manager.getRepository(_entities_entity_definition_entity_js__rspack_import_4/* .EntityDefinition */.f);
3472
5213
  const definition = await definitionRepo.save(definitionRepo.create({
5214
+ ...presetId(ids.entityId),
3473
5215
  code: dto.code,
3474
5216
  label: dto.label,
3475
5217
  description: dto.description ?? null,
3476
5218
  tableName,
3477
- status: _enums_entity_status_enum_js__rspack_import_19/* .EntityStatus.ACTIVE */.c.ACTIVE,
5219
+ status: _enums_entity_status_enum_js__rspack_import_21/* .EntityStatus.ACTIVE */.c.ACTIVE,
3478
5220
  schemaVersion: 1,
3479
5221
  isSoftDeleteEnabled,
3480
5222
  isAuditEnabled,
@@ -3483,6 +5225,7 @@ class SchemaSyncService {
3483
5225
  const fieldRepo = ctx.qr.manager.getRepository(_entities_field_definition_entity_js__rspack_import_5/* .FieldDefinition */.c);
3484
5226
  if (fieldSpecs.length) {
3485
5227
  await fieldRepo.save(fieldSpecs.map((spec, index)=>fieldRepo.create({
5228
+ ...presetId(ids.fieldIds?.[spec.code]),
3486
5229
  entityDefinitionId: definition.id,
3487
5230
  code: spec.code,
3488
5231
  label: spec.label,
@@ -3494,7 +5237,7 @@ class SchemaSyncService {
3494
5237
  defaultValue: spec.defaultValue ?? null,
3495
5238
  validationRules: spec.validationRules ?? null,
3496
5239
  selectOptions: spec.selectOptions ?? null,
3497
- relationTargetEntityId: spec.relationTargetEntityId ?? null,
5240
+ relationTargetEntityId: spec.fieldType === _enums_field_type_enum_js__rspack_import_19/* .FieldType.RELATION */.P.RELATION ? spec.relationTargetEntityId : null,
3498
5241
  order: spec.order ?? index,
3499
5242
  uiConfig: spec.uiConfig ?? null,
3500
5243
  isSearchable: spec.isSearchable ?? false,
@@ -3505,7 +5248,7 @@ class SchemaSyncService {
3505
5248
  created.definition = definition;
3506
5249
  });
3507
5250
  return {
3508
- operation: _enums_ddl_operation_enum_js__rspack_import_18/* .DdlOperation.CREATE_TABLE */.i.CREATE_TABLE,
5251
+ operation: _enums_ddl_operation_enum_js__rspack_import_20/* .DdlOperation.CREATE_TABLE */.i.CREATE_TABLE,
3509
5252
  entityDefinitionId: created.definition?.id ?? null,
3510
5253
  diff: {
3511
5254
  fields: fieldSpecs.map((f)=>({
@@ -3519,36 +5262,34 @@ class SchemaSyncService {
3519
5262
  try {
3520
5263
  await this.entityPermissionService.provisionForEntity(created.definition);
3521
5264
  } finally{
3522
- created.warnings.push(...await this.createEndpointFlows(dto, flowEndpoints, user));
5265
+ if (flowEndpoints.length) created.warnings.push(...await this.createEndpointFlow(dto, flowEndpoints, user));
3523
5266
  }
3524
5267
  }
3525
5268
  };
3526
5269
  };
3527
5270
  }
3528
5271
  /**
3529
- * One ready-made flow per requested endpoint, saved through FlowDefinitionService so it is
3530
- * validated like any other flow. Each is saved on its own: one that fails does not stop the
3531
- * rest, and is reported as a warning since the entity is already committed.
3532
- */ async createEndpointFlows(dto, endpoints, user) {
3533
- const entity = {
5272
+ * The entity's ready-made flow, one Request step per requested endpoint, saved through
5273
+ * FlowDefinitionService so it is validated like any other flow. The entity is already committed,
5274
+ * so a flow that cannot be saved is reported as a warning.
5275
+ */ async createEndpointFlow(dto, endpoints, user) {
5276
+ const flow = (0,_entity_flow_scaffold_js__rspack_import_9/* .buildEntityFlow */.CO)({
3534
5277
  code: dto.code,
3535
5278
  label: dto.label,
3536
5279
  fields: dto.fields ?? []
3537
- };
3538
- const warnings = [];
3539
- for (const endpoint of endpoints){
3540
- const flow = (0,_entity_flow_scaffold_js__rspack_import_9/* .buildEntityFlow */.C)(entity, endpoint, dto.flowTexts);
3541
- try {
3542
- await this.flowDefinitionService.insert(flow, user);
3543
- } catch (error) {
3544
- this.logger.error(`Endpoint flow '${flow.slug}' of entity '${dto.code}' could not be created: ${error.message}`);
3545
- warnings.push((0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_16/* .SCHEMA_WARNING_MESSAGES.ENDPOINT_FLOW_FAILED */.Uu.ENDPOINT_FLOW_FAILED, {
5280
+ }, endpoints, dto.flowTexts);
5281
+ try {
5282
+ await this.flowDefinitionService.insert(flow, user);
5283
+ return [];
5284
+ } catch (error) {
5285
+ this.logger.error(`The flow '${flow.slug}' of entity '${dto.code}' could not be created: ${error.message}`);
5286
+ return [
5287
+ (0,_flusys_nestjs_shared_utils__rspack_import_1.messageRef)(_config_message_keys_js__rspack_import_17/* .SCHEMA_WARNING_MESSAGES.ENDPOINT_FLOW_FAILED */.Uu.ENDPOINT_FLOW_FAILED, {
3546
5288
  slug: flow.slug,
3547
5289
  detail: (0,_flow_engine_flow_errors_js__rspack_import_7/* .errorRef */.O$)(error)
3548
- }));
3549
- }
5290
+ })
5291
+ ];
3550
5292
  }
3551
- return warnings;
3552
5293
  }
3553
5294
  /** Preview of `createEntity`: the CREATE TABLE / CREATE INDEX statements, nothing is created. */ async planCreateEntity(dto, user) {
3554
5295
  this.validateCreateRequest(dto);
@@ -3556,7 +5297,7 @@ class SchemaSyncService {
3556
5297
  warnings: []
3557
5298
  }));
3558
5299
  }
3559
- async createEntity(dto, user) {
5300
+ async createEntity(dto, user, ids = {}) {
3560
5301
  this.validateCreateRequest(dto);
3561
5302
  if (dto.flowEndpoints?.length) await this.flowDefinitionService.assertMayCreate(user);
3562
5303
  const created = {
@@ -3564,12 +5305,12 @@ class SchemaSyncService {
3564
5305
  };
3565
5306
  let planWarnings;
3566
5307
  try {
3567
- ({ plan: { warnings: planWarnings } } = await this.executor.apply(await this.createTarget(dto, user), this.createRun(dto, user, created)));
5308
+ ({ plan: { warnings: planWarnings } } = await this.executor.apply(await this.createTarget(dto, user), this.createRun(dto, user, created, ids)));
3568
5309
  } catch (error) {
3569
- if (error instanceof _nestjs_common__rspack_import_2.ConflictException && error.getResponse().blockers?.some((b)=>b.messageKey === _config_message_keys_js__rspack_import_16/* .SCHEMA_BLOCKER_MESSAGES.ENTITY_CODE_EXISTS */.M3.ENTITY_CODE_EXISTS || b.messageKey === _config_message_keys_js__rspack_import_16/* .SCHEMA_BLOCKER_MESSAGES.TABLE_EXISTS */.M3.TABLE_EXISTS)) {
5310
+ if (error instanceof _nestjs_common__rspack_import_2.ConflictException && error.getResponse().blockers?.some((b)=>b.messageKey === _config_message_keys_js__rspack_import_17/* .SCHEMA_BLOCKER_MESSAGES.ENTITY_CODE_EXISTS */.M3.ENTITY_CODE_EXISTS || b.messageKey === _config_message_keys_js__rspack_import_17/* .SCHEMA_BLOCKER_MESSAGES.TABLE_EXISTS */.M3.TABLE_EXISTS)) {
3570
5311
  throw new _nestjs_common__rspack_import_2.ConflictException({
3571
5312
  message: `An entity with the code '${dto.code}' already exists.`,
3572
- messageKey: _config_message_keys_js__rspack_import_16/* .ENTITY_DEFINITION_MESSAGES.CODE_ALREADY_EXISTS */.pL.CODE_ALREADY_EXISTS,
5313
+ messageKey: _config_message_keys_js__rspack_import_17/* .ENTITY_DEFINITION_MESSAGES.CODE_ALREADY_EXISTS */.pL.CODE_ALREADY_EXISTS,
3573
5314
  messageVariables: {
3574
5315
  code: dto.code
3575
5316
  }
@@ -3591,17 +5332,17 @@ SchemaSyncService = _ts_decorate([
3591
5332
  scope: _nestjs_common__rspack_import_2.Scope.REQUEST
3592
5333
  }),
3593
5334
  _ts_param(0, (0,_nestjs_common__rspack_import_2.Inject)(_entity_builder_datasource_provider_js__rspack_import_8/* .EntityBuilderDataSourceProvider */.D)),
3594
- _ts_param(1, (0,_nestjs_common__rspack_import_2.Inject)(_schema_dialect_adapter_service_js__rspack_import_15/* .SchemaDialectAdapterService */.I)),
3595
- _ts_param(2, (0,_nestjs_common__rspack_import_2.Inject)(_schema_change_executor_service_js__rspack_import_13/* .SchemaChangeExecutor */.T)),
5335
+ _ts_param(1, (0,_nestjs_common__rspack_import_2.Inject)(_schema_dialect_adapter_service_js__rspack_import_16/* .SchemaDialectAdapterService */.I)),
5336
+ _ts_param(2, (0,_nestjs_common__rspack_import_2.Inject)(_schema_change_executor_service_js__rspack_import_14/* .SchemaChangeExecutor */.T)),
3596
5337
  _ts_param(3, (0,_nestjs_common__rspack_import_2.Inject)(_entity_permission_service_js__rspack_import_10/* .EntityPermissionService */.u)),
3597
- _ts_param(4, (0,_nestjs_common__rspack_import_2.Inject)(_flow_definition_service_js__rspack_import_11/* .FlowDefinitionService */.Tk)),
5338
+ _ts_param(4, (0,_nestjs_common__rspack_import_2.Inject)(_flow_definition_service_js__rspack_import_12/* .FlowDefinitionService */.Tk)),
3598
5339
  _ts_metadata("design:type", Function),
3599
5340
  _ts_metadata("design:paramtypes", [
3600
5341
  typeof _entity_builder_datasource_provider_js__rspack_import_8/* .EntityBuilderDataSourceProvider */.D === "undefined" ? Object : _entity_builder_datasource_provider_js__rspack_import_8/* .EntityBuilderDataSourceProvider */.D,
3601
- typeof _schema_dialect_adapter_service_js__rspack_import_15/* .SchemaDialectAdapterService */.I === "undefined" ? Object : _schema_dialect_adapter_service_js__rspack_import_15/* .SchemaDialectAdapterService */.I,
3602
- typeof _schema_change_executor_service_js__rspack_import_13/* .SchemaChangeExecutor */.T === "undefined" ? Object : _schema_change_executor_service_js__rspack_import_13/* .SchemaChangeExecutor */.T,
5342
+ typeof _schema_dialect_adapter_service_js__rspack_import_16/* .SchemaDialectAdapterService */.I === "undefined" ? Object : _schema_dialect_adapter_service_js__rspack_import_16/* .SchemaDialectAdapterService */.I,
5343
+ typeof _schema_change_executor_service_js__rspack_import_14/* .SchemaChangeExecutor */.T === "undefined" ? Object : _schema_change_executor_service_js__rspack_import_14/* .SchemaChangeExecutor */.T,
3603
5344
  typeof _entity_permission_service_js__rspack_import_10/* .EntityPermissionService */.u === "undefined" ? Object : _entity_permission_service_js__rspack_import_10/* .EntityPermissionService */.u,
3604
- typeof _flow_definition_service_js__rspack_import_11/* .FlowDefinitionService */.Tk === "undefined" ? Object : _flow_definition_service_js__rspack_import_11/* .FlowDefinitionService */.Tk
5345
+ typeof _flow_definition_service_js__rspack_import_12/* .FlowDefinitionService */.Tk === "undefined" ? Object : _flow_definition_service_js__rspack_import_12/* .FlowDefinitionService */.Tk
3605
5346
  ])
3606
5347
  ], SchemaSyncService);
3607
5348