@nocobase/plugin-flow-engine 2.1.0-alpha.45 → 2.1.0-alpha.46

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 (93) hide show
  1. package/dist/client/index.js +1 -1
  2. package/dist/externalVersion.js +9 -9
  3. package/dist/node_modules/@ant-design/icons-svg/package.json +1 -1
  4. package/dist/node_modules/acorn/package.json +1 -1
  5. package/dist/node_modules/acorn-jsx/package.json +1 -1
  6. package/dist/node_modules/acorn-walk/package.json +1 -1
  7. package/dist/node_modules/ses/package.json +1 -1
  8. package/dist/node_modules/zod/package.json +1 -1
  9. package/dist/server/flow-surfaces/apply/compiler.js +10 -11
  10. package/dist/server/flow-surfaces/authoring-validation.d.ts +1 -0
  11. package/dist/server/flow-surfaces/authoring-validation.js +773 -26
  12. package/dist/server/flow-surfaces/blueprint/normalize-document.js +5 -1
  13. package/dist/server/flow-surfaces/catalog.js +9 -5
  14. package/dist/server/flow-surfaces/chart-config.js +220 -16
  15. package/dist/server/flow-surfaces/contract-guard.js +40 -6
  16. package/dist/server/flow-surfaces/default-block-actions.js +2 -0
  17. package/dist/server/flow-surfaces/errors.d.ts +15 -0
  18. package/dist/server/flow-surfaces/errors.js +49 -3
  19. package/dist/server/flow-surfaces/event-flow-normalizer.d.ts +19 -0
  20. package/dist/server/flow-surfaces/event-flow-normalizer.js +128 -0
  21. package/dist/server/flow-surfaces/filter-group.d.ts +9 -1
  22. package/dist/server/flow-surfaces/filter-group.js +402 -3
  23. package/dist/server/flow-surfaces/public-data-surface-default-filter.js +2 -1
  24. package/dist/server/flow-surfaces/route-sync.js +19 -2
  25. package/dist/server/flow-surfaces/runjs-authoring/ast/bindings.d.ts +66 -0
  26. package/dist/server/flow-surfaces/runjs-authoring/ast/bindings.js +661 -0
  27. package/dist/server/flow-surfaces/runjs-authoring/ast/execution.d.ts +20 -0
  28. package/dist/server/flow-surfaces/runjs-authoring/ast/execution.js +275 -0
  29. package/dist/server/flow-surfaces/runjs-authoring/ast/parser.d.ts +16 -0
  30. package/dist/server/flow-surfaces/runjs-authoring/ast/parser.js +130 -0
  31. package/dist/server/flow-surfaces/runjs-authoring/ast/react-values.d.ts +20 -0
  32. package/dist/server/flow-surfaces/runjs-authoring/ast/react-values.js +401 -0
  33. package/dist/server/flow-surfaces/runjs-authoring/ast/request-config.d.ts +21 -0
  34. package/dist/server/flow-surfaces/runjs-authoring/ast/request-config.js +199 -0
  35. package/dist/server/flow-surfaces/runjs-authoring/ast/source.d.ts +70 -0
  36. package/dist/server/flow-surfaces/runjs-authoring/ast/source.js +895 -0
  37. package/dist/server/flow-surfaces/runjs-authoring/ast/static-bindings.d.ts +23 -0
  38. package/dist/server/flow-surfaces/runjs-authoring/ast/static-bindings.js +618 -0
  39. package/dist/server/flow-surfaces/runjs-authoring/ast/static-values.d.ts +196 -0
  40. package/dist/server/flow-surfaces/runjs-authoring/ast/static-values.js +1777 -0
  41. package/dist/server/flow-surfaces/runjs-authoring/ast/walk.d.ts +10 -0
  42. package/dist/server/flow-surfaces/runjs-authoring/ast/walk.js +55 -0
  43. package/dist/server/flow-surfaces/runjs-authoring/collectors.d.ts +12 -0
  44. package/dist/server/flow-surfaces/runjs-authoring/collectors.js +589 -0
  45. package/dist/server/flow-surfaces/runjs-authoring/index.d.ts +2 -25
  46. package/dist/server/flow-surfaces/runjs-authoring/index.js +5 -11138
  47. package/dist/server/flow-surfaces/runjs-authoring/inspect.d.ts +13 -0
  48. package/dist/server/flow-surfaces/runjs-authoring/inspect.js +149 -0
  49. package/dist/server/flow-surfaces/runjs-authoring/internal-types.d.ts +333 -0
  50. package/dist/server/flow-surfaces/runjs-authoring/internal-types.js +36 -0
  51. package/dist/server/flow-surfaces/runjs-authoring/rules.js +2 -0
  52. package/dist/server/flow-surfaces/runjs-authoring/runtime/constants.d.ts +67 -0
  53. package/dist/server/flow-surfaces/runjs-authoring/runtime/constants.js +757 -0
  54. package/dist/server/flow-surfaces/runjs-authoring/runtime/errors.d.ts +22 -0
  55. package/dist/server/flow-surfaces/runjs-authoring/runtime/errors.js +91 -0
  56. package/dist/server/flow-surfaces/runjs-authoring/runtime/source-budget.d.ts +16 -0
  57. package/dist/server/flow-surfaces/runjs-authoring/runtime/source-budget.js +115 -0
  58. package/dist/server/flow-surfaces/runjs-authoring/runtime/surface.d.ts +19 -0
  59. package/dist/server/flow-surfaces/runjs-authoring/runtime/surface.js +140 -0
  60. package/dist/server/flow-surfaces/runjs-authoring/runtime/types.d.ts +91 -0
  61. package/dist/server/flow-surfaces/runjs-authoring/runtime/types.js +24 -0
  62. package/dist/server/flow-surfaces/runjs-authoring/scan/ctx-api.d.ts +138 -0
  63. package/dist/server/flow-surfaces/runjs-authoring/scan/ctx-api.js +1779 -0
  64. package/dist/server/flow-surfaces/runjs-authoring/scan/filter.d.ts +10 -0
  65. package/dist/server/flow-surfaces/runjs-authoring/scan/filter.js +1583 -0
  66. package/dist/server/flow-surfaces/runjs-authoring/scan/index.d.ts +195 -0
  67. package/dist/server/flow-surfaces/runjs-authoring/scan/index.js +463 -0
  68. package/dist/server/flow-surfaces/runjs-authoring/scan/react-render.d.ts +48 -0
  69. package/dist/server/flow-surfaces/runjs-authoring/scan/react-render.js +379 -0
  70. package/dist/server/flow-surfaces/runjs-authoring/scan/react.d.ts +26 -0
  71. package/dist/server/flow-surfaces/runjs-authoring/scan/react.js +1441 -0
  72. package/dist/server/flow-surfaces/runjs-authoring/scan/resource.d.ts +23 -0
  73. package/dist/server/flow-surfaces/runjs-authoring/scan/resource.js +1427 -0
  74. package/dist/server/flow-surfaces/runjs-authoring/scan/source-patterns.d.ts +91 -0
  75. package/dist/server/flow-surfaces/runjs-authoring/scan/source-patterns.js +889 -0
  76. package/dist/server/flow-surfaces/runjs-authoring/types.d.ts +1 -1
  77. package/dist/server/flow-surfaces/runjs-authoring/unknown-global-stop/index.d.ts +10 -0
  78. package/dist/server/flow-surfaces/runjs-authoring/unknown-global-stop/index.js +40 -0
  79. package/dist/server/flow-surfaces/runjs-authoring/validators/index.d.ts +12 -0
  80. package/dist/server/flow-surfaces/runjs-authoring/validators/index.js +887 -0
  81. package/dist/server/flow-surfaces/service-helpers.d.ts +29 -0
  82. package/dist/server/flow-surfaces/service-helpers.js +105 -0
  83. package/dist/server/flow-surfaces/service-utils.d.ts +15 -3
  84. package/dist/server/flow-surfaces/service-utils.js +6 -5
  85. package/dist/server/flow-surfaces/service.d.ts +7 -1
  86. package/dist/server/flow-surfaces/service.js +488 -94
  87. package/dist/server/flow-surfaces/types.d.ts +3 -0
  88. package/dist/server/repository.d.ts +12 -1
  89. package/dist/server/repository.js +195 -23
  90. package/dist/swagger/flow-surfaces.d.ts +175 -0
  91. package/dist/swagger/flow-surfaces.js +130 -51
  92. package/dist/swagger/index.d.ts +175 -0
  93. package/package.json +2 -2
@@ -588,12 +588,16 @@ function prepareFlowSurfaceApplyBlueprintDocument(input) {
588
588
  if (tabs.length > 1 && (page == null ? void 0 : page.enableTabs) === false) {
589
589
  (0, import_errors.throwBadRequest)(`flowSurfaces applyBlueprint page.enableTabs cannot be false when tabs.length > 1`);
590
590
  }
591
+ const normalizedPage = tabs.length === 1 ? {
592
+ ...page || {},
593
+ enableTabs: false
594
+ } : page;
591
595
  return {
592
596
  version: "1",
593
597
  mode,
594
598
  ...target ? { target } : {},
595
599
  ...navigation ? { navigation } : {},
596
- ...page ? { page } : {},
600
+ ...normalizedPage ? { page: normalizedPage } : {},
597
601
  ...defaults ? { defaults } : {},
598
602
  tabs,
599
603
  assets,
@@ -119,6 +119,10 @@ const FILTER_GROUP_SCHEMA = {
119
119
  additionalProperties: false,
120
120
  "x-flowSurfaceFormat": "filter-group"
121
121
  };
122
+ const LINKAGE_RULES_SCHEMA = {
123
+ type: "array",
124
+ "x-flowSurfaceFormat": "linkage-rules"
125
+ };
122
126
  const DEFAULT_DIRECT_EVENTS = ["beforeRender"];
123
127
  const ACTION_DIRECT_EVENTS = ["click", "beforeRender"];
124
128
  const ACTION_OBJECT_EVENTS = ["click"];
@@ -207,7 +211,7 @@ const ACTION_BUTTON_SETTINGS_GROUP = {
207
211
  "general.type": STRING_SCHEMA,
208
212
  "general.danger": BOOLEAN_SCHEMA,
209
213
  "general.color": STRING_SCHEMA,
210
- "linkageRules.value": ARRAY_SCHEMA
214
+ "linkageRules.value": LINKAGE_RULES_SCHEMA
211
215
  }
212
216
  };
213
217
  const TRIGGER_WORKFLOWS_SETTINGS_GROUP = {
@@ -302,7 +306,7 @@ const EVENT_SETTINGS_GROUP = {
302
306
  allowedPaths: ["linkageRules.value"],
303
307
  eventBindingSteps: ["linkageRules"],
304
308
  pathSchemas: {
305
- "linkageRules.value": ARRAY_SCHEMA
309
+ "linkageRules.value": LINKAGE_RULES_SCHEMA
306
310
  }
307
311
  };
308
312
  const CREATE_FORM_SETTINGS_EVENT_ONLY_GROUP = {
@@ -323,7 +327,7 @@ const DETAILS_SETTINGS_GROUP = {
323
327
  ...FORM_LAYOUT_PATH_SCHEMAS,
324
328
  "dataScope.filter": FILTER_GROUP_SCHEMA,
325
329
  "defaultSorting.sort": ARRAY_SCHEMA,
326
- "linkageRules.value": ARRAY_SCHEMA
330
+ "linkageRules.value": LINKAGE_RULES_SCHEMA
327
331
  }
328
332
  };
329
333
  const FILTER_FORM_BLOCK_SETTINGS_GROUP = {
@@ -350,7 +354,7 @@ const BLOCK_CARD_SETTINGS_GROUP = {
350
354
  "titleDescription.description": STRING_SCHEMA,
351
355
  "blockHeight.heightMode": BLOCK_HEIGHT_MODE_SCHEMA,
352
356
  "blockHeight.height": NUMBER_SCHEMA,
353
- "linkageRules.value": ARRAY_SCHEMA
357
+ "linkageRules.value": LINKAGE_RULES_SCHEMA
354
358
  }
355
359
  };
356
360
  const CALENDAR_SETTINGS_GROUP = {
@@ -2191,7 +2195,7 @@ CALENDAR_READONLY_ACTION_CONTRACT.domains.stepParams = groupedDomain({
2191
2195
  mergeStrategy: "deep",
2192
2196
  eventBindingSteps: ["linkageRules"],
2193
2197
  pathSchemas: {
2194
- "linkageRules.value": ARRAY_SCHEMA
2198
+ "linkageRules.value": LINKAGE_RULES_SCHEMA
2195
2199
  }
2196
2200
  }
2197
2201
  });
@@ -64,7 +64,91 @@ __export(chart_config_exports, {
64
64
  module.exports = __toCommonJS(chart_config_exports);
65
65
  var import_lodash = __toESM(require("lodash"));
66
66
  var import_errors = require("./errors");
67
+ var import_filter_group = require("./filter-group");
67
68
  const CHART_REPAIR_HINT = "This is a chart payload shape problem. Repair the current chart query/visual mappings and keep the chart block type. Do not change this block type to table, jsBlock, actionPanel, gridCard, or another block type. KPI / summary numbers should use jsBlock; charts are for trends, distributions, rankings, and visual analysis.";
69
+ const CHART_FORBIDDEN_FALLBACKS = [
70
+ "table",
71
+ "list",
72
+ "jsBlock",
73
+ "actionPanel",
74
+ "gridCard",
75
+ "markdown",
76
+ "drop chart",
77
+ "defer chart"
78
+ ];
79
+ const CHART_REPAIR_STEPS = [
80
+ "Keep the block type as chart.",
81
+ "Repair the chart query and visual mappings on the current chart payload.",
82
+ "Retry the chart payload instead of replacing the chart with another block type, omitting it, or deferring it."
83
+ ];
84
+ const CHART_EXPECTED_SHAPE = {
85
+ settings: {
86
+ query: {
87
+ mode: "builder",
88
+ resource: {
89
+ dataSourceKey: "main",
90
+ collectionName: "employees"
91
+ },
92
+ measures: [
93
+ {
94
+ field: "id",
95
+ aggregation: "count",
96
+ alias: "employeeCount"
97
+ }
98
+ ]
99
+ },
100
+ visual: {
101
+ mode: "basic",
102
+ type: "bar",
103
+ mappings: {
104
+ x: "status",
105
+ y: "employeeCount"
106
+ }
107
+ }
108
+ }
109
+ };
110
+ function withChartRepairDetails(details = {}) {
111
+ return {
112
+ ...details,
113
+ requiredBlockType: "chart",
114
+ fixStrategy: "repair_same_block_type",
115
+ repairHint: CHART_REPAIR_HINT,
116
+ repairSteps: CHART_REPAIR_STEPS,
117
+ expectedShape: CHART_EXPECTED_SHAPE,
118
+ repairExample: {
119
+ settings: {
120
+ query: {
121
+ mode: "builder",
122
+ resource: {
123
+ dataSourceKey: "main",
124
+ collectionName: "<collectionName>"
125
+ },
126
+ measures: [
127
+ {
128
+ field: "id",
129
+ aggregation: "count",
130
+ alias: "recordCount"
131
+ }
132
+ ],
133
+ dimensions: [
134
+ {
135
+ field: "<dimensionField>"
136
+ }
137
+ ]
138
+ },
139
+ visual: {
140
+ mode: "basic",
141
+ type: "bar",
142
+ mappings: {
143
+ x: "<dimensionField>",
144
+ y: "recordCount"
145
+ }
146
+ }
147
+ }
148
+ },
149
+ forbiddenFallbacks: CHART_FORBIDDEN_FALLBACKS
150
+ };
151
+ }
68
152
  function withChartRepairMessage(message) {
69
153
  return `${message}. ${CHART_REPAIR_HINT}`;
70
154
  }
@@ -86,10 +170,6 @@ const CHART_SORT_DIRECTIONS = ["asc", "desc"];
86
170
  const CHART_SORT_NULLS = ["default", "first", "last"];
87
171
  const CHART_LABEL_TYPES = ["value", "percent"];
88
172
  const CHART_FUNNEL_SORTS = ["descending", "ascending"];
89
- const EMPTY_FILTER_GROUP = {
90
- logic: "$and",
91
- items: []
92
- };
93
173
  const CHART_SAFE_DEFAULT_HINTS = [
94
174
  {
95
175
  key: "builder_basic_minimal",
@@ -375,6 +455,17 @@ function normalizeFieldPathValue(input, label, options = {}) {
375
455
  }
376
456
  throw new import_errors.FlowSurfaceBadRequestError(`${label} must be a string or string[]`);
377
457
  }
458
+ function normalizeChartQueryFieldPathValue(input, label, options = {}) {
459
+ const normalized = normalizeFieldPathValue(input, label, options);
460
+ if (typeof normalized !== "string" || !normalized.includes(".")) {
461
+ return normalized;
462
+ }
463
+ const segments = normalized.split(".").map((segment) => segment.trim());
464
+ if (segments.some((segment) => !segment)) {
465
+ throw new import_errors.FlowSurfaceBadRequestError(`${label} cannot contain empty path segments`);
466
+ }
467
+ return segments;
468
+ }
378
469
  function aliasOfFieldValue(input) {
379
470
  if (Array.isArray(input)) {
380
471
  return input.filter(Boolean).map((item) => String(item)).join(".");
@@ -406,7 +497,7 @@ function fromPersistedOrder(input) {
406
497
  return CHART_SORT_DIRECTION_SET.has(normalized) ? normalized : void 0;
407
498
  }
408
499
  function createEmptyFilterGroup() {
409
- return import_lodash.default.cloneDeep(EMPTY_FILTER_GROUP);
500
+ return import_lodash.default.cloneDeep(import_filter_group.FLOW_SURFACE_EMPTY_FILTER_GROUP);
410
501
  }
411
502
  function assertAllowedKeys(input, allowed, label) {
412
503
  const unknownKeys = Object.keys(input).filter((key) => !allowed.has(key));
@@ -482,25 +573,29 @@ function normalizeMergedChartResource(query, options = {}) {
482
573
  function normalizeChartMeasure(input, index) {
483
574
  const label = `chart query.measures[${index}]`;
484
575
  const normalized = ensurePlainObject(input, label);
576
+ const field = normalizeChartQueryFieldPathValue(normalized.field, `${label}.field`, { required: true });
577
+ const alias = normalizeOptionalTrimmedString(normalized.alias, `${label}.alias`);
485
578
  const aggregation = normalizeOptionalEnumValue(
486
579
  normalized.aggregation,
487
580
  CHART_QUERY_AGGREGATION_SET,
488
581
  `${label}.aggregation`
489
582
  );
490
583
  return buildDefinedObject({
491
- field: normalizeFieldPathValue(normalized.field, `${label}.field`, { required: true }),
584
+ field,
492
585
  aggregation,
493
- alias: normalizeOptionalTrimmedString(normalized.alias, `${label}.alias`),
586
+ alias: alias || (Array.isArray(field) && field.length > 1 ? aliasOfFieldValue(field) : void 0),
494
587
  distinct: normalizeOptionalBoolean(normalized.distinct, `${label}.distinct`)
495
588
  });
496
589
  }
497
590
  function normalizeChartDimension(input, index) {
498
591
  const label = `chart query.dimensions[${index}]`;
499
592
  const normalized = ensurePlainObject(input, label);
593
+ const field = normalizeChartQueryFieldPathValue(normalized.field, `${label}.field`, { required: true });
594
+ const alias = normalizeOptionalTrimmedString(normalized.alias, `${label}.alias`);
500
595
  return buildDefinedObject({
501
- field: normalizeFieldPathValue(normalized.field, `${label}.field`, { required: true }),
596
+ field,
502
597
  format: normalizeOptionalTrimmedString(normalized.format, `${label}.format`),
503
- alias: normalizeOptionalTrimmedString(normalized.alias, `${label}.alias`)
598
+ alias: alias || (Array.isArray(field) && field.length > 1 ? aliasOfFieldValue(field) : void 0)
504
599
  });
505
600
  }
506
601
  function normalizeBuilderCountMeasureFieldForRuntime(measure, dimensions) {
@@ -511,6 +606,12 @@ function normalizeBuilderCountMeasureFieldForRuntime(measure, dimensions) {
511
606
  if (!fallbackDimension) {
512
607
  return measure;
513
608
  }
609
+ if (Array.isArray(fallbackDimension.field) && fallbackDimension.field.length > 1) {
610
+ return measure;
611
+ }
612
+ if (typeof fallbackDimension.field === "string" && fallbackDimension.field.includes(".")) {
613
+ return measure;
614
+ }
514
615
  return {
515
616
  ...measure,
516
617
  field: import_lodash.default.cloneDeep(fallbackDimension.field)
@@ -525,18 +626,113 @@ function normalizeChartSortingItem(input, index) {
525
626
  `${label}.${hasOwn(normalized, "direction") ? "direction" : "order"}`
526
627
  );
527
628
  return buildDefinedObject({
528
- field: normalizeFieldPathValue(normalized.field, `${label}.field`, { required: true }),
629
+ field: normalizeChartQueryFieldPathValue(normalized.field, `${label}.field`, { required: true }),
529
630
  order: toPersistedOrder(direction),
530
631
  nulls: normalizeOptionalEnumValue(normalized.nulls, CHART_SORT_NULLS_SET, `${label}.nulls`)
531
632
  });
532
633
  }
634
+ function isFilterGroupLike(input) {
635
+ return import_lodash.default.isPlainObject(input) && isBackendQueryLogicKey(input.logic) && Array.isArray(input.items);
636
+ }
637
+ function assertFilterGroupKeys(input, label) {
638
+ if (!isFilterGroupLike(input)) {
639
+ return;
640
+ }
641
+ const unsupportedKeys = Object.keys(input).filter((key) => key !== "logic" && key !== "items");
642
+ if (unsupportedKeys.length) {
643
+ throw new import_errors.FlowSurfaceBadRequestError(`${label} does not support: ${unsupportedKeys.join(", ")}`);
644
+ }
645
+ if (Array.isArray(input.items)) {
646
+ input.items.forEach((item, index) => {
647
+ assertFilterGroupKeys(item, `${label}.items[${index}]`);
648
+ });
649
+ }
650
+ }
651
+ function isBackendQueryLogicKey(key) {
652
+ return key === "$and" || key === "$or";
653
+ }
654
+ function getBackendQueryLogicKey(input, label) {
655
+ const keys = Object.keys(input);
656
+ const logicKeys = keys.filter(isBackendQueryLogicKey);
657
+ if (!logicKeys.length) {
658
+ return void 0;
659
+ }
660
+ if (logicKeys.length > 1 || keys.length > 1) {
661
+ throw new import_errors.FlowSurfaceBadRequestError(
662
+ `${label}: cannot convert backend query filter with mixed logical and field conditions`
663
+ );
664
+ }
665
+ return logicKeys[0];
666
+ }
667
+ function convertBackendFieldConditionToFilterItems(field, condition, label) {
668
+ if (!field.trim() || field.startsWith("$")) {
669
+ throw new import_errors.FlowSurfaceBadRequestError(`${label}: cannot convert backend query filter field "${field}"`);
670
+ }
671
+ if (!import_lodash.default.isPlainObject(condition)) {
672
+ throw new import_errors.FlowSurfaceBadRequestError(`${label}.${field}: backend query filter condition must be an object`);
673
+ }
674
+ const operators = Object.keys(condition);
675
+ if (!operators.length) {
676
+ throw new import_errors.FlowSurfaceBadRequestError(`${label}.${field}: backend query filter condition cannot be empty`);
677
+ }
678
+ return operators.map((operator) => {
679
+ if (!operator.startsWith("$")) {
680
+ (0, import_filter_group.assertFlowSurfaceFilterOperator)(operator, `${label}.${field}.${operator}`);
681
+ }
682
+ if (!operator.startsWith("$") || isBackendQueryLogicKey(operator)) {
683
+ throw new import_errors.FlowSurfaceBadRequestError(
684
+ `${label}.${field}: cannot convert backend query filter operator "${operator}"`
685
+ );
686
+ }
687
+ return {
688
+ path: field,
689
+ operator,
690
+ value: import_lodash.default.cloneDeep(condition[operator])
691
+ };
692
+ });
693
+ }
694
+ function convertBackendQueryFilterToFilterGroup(input, label) {
695
+ const logicKey = getBackendQueryLogicKey(input, label);
696
+ if (logicKey) {
697
+ const operands = input[logicKey];
698
+ if (!Array.isArray(operands)) {
699
+ throw new import_errors.FlowSurfaceBadRequestError(`${label}.${logicKey}: backend query filter operands must be an array`);
700
+ }
701
+ return {
702
+ logic: logicKey,
703
+ items: operands.map(
704
+ (operand, index) => convertBackendQueryOperandToFilterItem(operand, `${label}.${logicKey}[${index}]`)
705
+ )
706
+ };
707
+ }
708
+ return {
709
+ logic: "$and",
710
+ items: Object.entries(input).flatMap(
711
+ ([field, condition]) => convertBackendFieldConditionToFilterItems(field, condition, label)
712
+ )
713
+ };
714
+ }
715
+ function convertBackendQueryOperandToFilterItem(input, label) {
716
+ if (isFilterGroupLike(input)) {
717
+ throw new import_errors.FlowSurfaceBadRequestError(`${label}: cannot mix filter groups with backend query filters`);
718
+ }
719
+ const group = convertBackendQueryFilterToFilterGroup(ensurePlainObject(input, label), label);
720
+ if (group.logic === "$and" && group.items.length === 1) {
721
+ return group.items[0];
722
+ }
723
+ return group;
724
+ }
533
725
  function normalizeFilterGroupValue(input, label) {
534
726
  if (import_lodash.default.isUndefined(input) || import_lodash.default.isNull(input)) {
535
727
  return void 0;
536
728
  }
537
729
  const normalized = ensurePlainObject(input, label);
538
- validateFilterGroupPaths(normalized, label);
539
- return import_lodash.default.cloneDeep(normalized);
730
+ assertFilterGroupKeys(normalized, label);
731
+ const filterGroup = !Object.keys(normalized).length || isFilterGroupLike(normalized) ? (0, import_filter_group.normalizeFlowSurfaceFilterGroupValue)(normalized, label, { strictDateValues: true }) : (0, import_filter_group.normalizeFlowSurfaceFilterGroupValue)(convertBackendQueryFilterToFilterGroup(normalized, label), label, {
732
+ strictDateValues: true
733
+ });
734
+ validateFilterGroupPaths(filterGroup, label);
735
+ return filterGroup;
540
736
  }
541
737
  function validateFilterGroupPaths(input, label) {
542
738
  const items = Array.isArray(input == null ? void 0 : input.items) ? input.items : [];
@@ -568,6 +764,7 @@ function inferQueryMode(query) {
568
764
  }
569
765
  function validateLooseChartQuery(query) {
570
766
  inferQueryMode(query);
767
+ validateChartQueryFilterOperators(query);
571
768
  if (!hasOwn(query, "resource") || !hasOwn(query, "collectionPath")) {
572
769
  return;
573
770
  }
@@ -582,6 +779,11 @@ function validateLooseChartQuery(query) {
582
779
  );
583
780
  }
584
781
  }
782
+ function validateChartQueryFilterOperators(query) {
783
+ if (hasOwn(query, "filter")) {
784
+ normalizeFilterGroupValue(query.filter, "chart query.filter");
785
+ }
786
+ }
585
787
  function canStrictNormalizeChartQuery(query) {
586
788
  validateLooseChartQuery(query);
587
789
  const mode = inferQueryMode(query);
@@ -605,7 +807,10 @@ function mergeChartQuerySection(current, patch) {
605
807
  const nextMode = inferQueryMode(normalizedPatch);
606
808
  const modeChanged = currentMode && currentMode !== nextMode;
607
809
  const base = modeChanged ? {} : current || {};
608
- const merged = mergeReplaceArrays(base, normalizedPatch);
810
+ const merged = mergeReplaceArrays(base, import_lodash.default.omit(normalizedPatch, ["filter"]));
811
+ if (hasOwn(normalizedPatch, "filter")) {
812
+ merged.filter = import_lodash.default.cloneDeep(normalizedPatch.filter);
813
+ }
609
814
  if (nextMode !== "builder") {
610
815
  return merged;
611
816
  }
@@ -1092,10 +1297,9 @@ function assertBasicVisualMappingsAgainstBuilderQuery(builderVisual, query) {
1092
1297
  ),
1093
1298
  void 0,
1094
1299
  {
1095
- details: {
1096
- repairHint: CHART_REPAIR_HINT,
1300
+ details: withChartRepairDetails({
1097
1301
  allowedOutputs: Array.from(allowedOutputs)
1098
- }
1302
+ })
1099
1303
  }
1100
1304
  );
1101
1305
  }
@@ -165,7 +165,7 @@ class FlowSurfaceContractGuard {
165
165
  if (typeof on === "string" && !allowedDirectEvents.has(eventName)) {
166
166
  (0, import_errors.throwBadRequest)(`flowSurfaces flow '${key}' event '${eventName}' is not allowed on '${node == null ? void 0 : node.use}'`);
167
167
  }
168
- if (typeof on !== "string" && !allowedObjectEvents.has(eventName)) {
168
+ if (typeof on !== "string" && !allowedObjectEvents.has(eventName) && !allowedDirectEvents.has(eventName)) {
169
169
  (0, import_errors.throwBadRequest)(`flowSurfaces flow '${key}' event '${eventName}' is not allowed on '${node == null ? void 0 : node.use}'`);
170
170
  }
171
171
  const phase = onObj == null ? void 0 : onObj.phase;
@@ -349,33 +349,67 @@ function collectSchemaValueErrors(value, schema, path) {
349
349
  function normalizeDomainValue(value, contract, context) {
350
350
  const normalized = import_lodash.default.cloneDeep(value);
351
351
  Object.entries(contract.pathSchemas || {}).forEach(([path, schema]) => {
352
- if (!import_lodash.default.has(normalized, path) || !isFilterGroupSchema(schema)) {
352
+ if (!import_lodash.default.has(normalized, path)) {
353
353
  return;
354
354
  }
355
- import_lodash.default.set(normalized, path, normalizeFilterGroupValue(import_lodash.default.get(normalized, path), context, path));
355
+ if (isFilterGroupSchema(schema)) {
356
+ import_lodash.default.set(normalized, path, normalizeFilterGroupValue(import_lodash.default.get(normalized, path), context, path));
357
+ } else if (isLinkageRulesSchema(schema)) {
358
+ import_lodash.default.set(normalized, path, normalizeLinkageRulesValue(import_lodash.default.get(normalized, path), context, path));
359
+ }
356
360
  });
357
361
  return normalized;
358
362
  }
359
363
  function normalizeGroupValue(value, groupContract, context) {
360
364
  const normalized = import_lodash.default.cloneDeep(value);
361
365
  Object.entries(groupContract.pathSchemas || {}).forEach(([path, schema]) => {
362
- if (!import_lodash.default.has(normalized, path) || !isFilterGroupSchema(schema)) {
366
+ if (!import_lodash.default.has(normalized, path)) {
363
367
  return;
364
368
  }
365
- import_lodash.default.set(normalized, path, normalizeFilterGroupValue(import_lodash.default.get(normalized, path), context, path));
369
+ if (isFilterGroupSchema(schema)) {
370
+ import_lodash.default.set(normalized, path, normalizeFilterGroupValue(import_lodash.default.get(normalized, path), context, path));
371
+ } else if (isLinkageRulesSchema(schema)) {
372
+ import_lodash.default.set(normalized, path, normalizeLinkageRulesValue(import_lodash.default.get(normalized, path), context, path));
373
+ }
366
374
  });
367
375
  return normalized;
368
376
  }
369
377
  function isFilterGroupSchema(schema) {
370
378
  return (schema == null ? void 0 : schema["x-flowSurfaceFormat"]) === "filter-group";
371
379
  }
380
+ function isLinkageRulesSchema(schema) {
381
+ return (schema == null ? void 0 : schema["x-flowSurfaceFormat"]) === "linkage-rules";
382
+ }
372
383
  function normalizeFilterGroupValue(value, context, path) {
373
384
  const domainPath = context.groupKey ? `${context.domain}.${context.groupKey}.${path}` : `${context.domain}.${path}`;
374
385
  return (0, import_filter_group.normalizeFlowSurfaceFilterGroupValue)(
375
386
  value,
376
- `flowSurfaces updateSettings domain '${domainPath}' on '${context.use}' expects FilterGroup like ${import_filter_group.FLOW_SURFACE_FILTER_GROUP_EXAMPLE}`
387
+ `flowSurfaces updateSettings domain '${domainPath}' on '${context.use}' expects FilterGroup like ${import_filter_group.FLOW_SURFACE_FILTER_GROUP_EXAMPLE}`,
388
+ { strictDateValues: true }
377
389
  );
378
390
  }
391
+ function normalizeLinkageRulesValue(value, context, path) {
392
+ if (!Array.isArray(value)) {
393
+ return value;
394
+ }
395
+ return value.map((rule, index) => {
396
+ if (!import_lodash.default.isPlainObject(rule) || !import_lodash.default.has(rule, "condition")) {
397
+ return rule;
398
+ }
399
+ const normalizedRule = import_lodash.default.cloneDeep(rule);
400
+ const domainPath = context.groupKey ? `${context.domain}.${context.groupKey}.${path}[${index}].condition` : `${context.domain}.${path}[${index}].condition`;
401
+ import_lodash.default.set(
402
+ normalizedRule,
403
+ "condition",
404
+ (0, import_filter_group.normalizeFlowSurfaceCompatibleFilterGroupValue)(
405
+ import_lodash.default.get(normalizedRule, "condition"),
406
+ `flowSurfaces updateSettings domain '${domainPath}' on '${context.use}' expects FilterGroup or backend query filter like ${import_filter_group.FLOW_SURFACE_FILTER_GROUP_EXAMPLE}`,
407
+ { strictDateValues: true }
408
+ )
409
+ );
410
+ return normalizedRule;
411
+ });
412
+ }
379
413
  function isContractDefinedFlowGroup(groupContract) {
380
414
  if (!groupContract) {
381
415
  return false;
@@ -104,6 +104,8 @@ const FLOW_SURFACE_DEFAULT_BLOCK_ACTIONS = {
104
104
  ],
105
105
  calendar: [
106
106
  { type: "filter", scope: "actions" },
107
+ { type: "turnPages", scope: "actions" },
108
+ { type: "selectView", scope: "actions" },
107
109
  { type: "refresh", scope: "actions" },
108
110
  {
109
111
  type: "addNew",
@@ -8,6 +8,7 @@
8
8
  */
9
9
  export type FlowSurfaceErrorType = 'bad_request' | 'forbidden' | 'conflict' | 'internal_error';
10
10
  export interface FlowSurfaceErrorItem {
11
+ index?: number;
11
12
  message: string;
12
13
  type: FlowSurfaceErrorType;
13
14
  code: string;
@@ -48,6 +49,20 @@ export declare class FlowSurfaceAggregateError extends FlowSurfaceError {
48
49
  readonly errors: FlowSurfaceErrorItem[];
49
50
  constructor(errors: FlowSurfaceErrorItemInput[], message?: string);
50
51
  toResponseBody(): {
52
+ message: string;
53
+ errorCount: number;
54
+ details: {
55
+ requiredBlockPolicy?: {
56
+ requiredBlockTypes: string[];
57
+ fixStrategy: string;
58
+ doNotReplaceOrDrop: boolean;
59
+ };
60
+ errorCount: number;
61
+ mustFixAllErrorsBeforeRetry: boolean;
62
+ retryPolicy: string;
63
+ sameWriteRetryRequired: boolean;
64
+ agentInstruction: string;
65
+ };
51
66
  errors: FlowSurfaceErrorItem[];
52
67
  };
53
68
  }
@@ -88,14 +88,27 @@ class FlowSurfaceInternalError extends FlowSurfaceError {
88
88
  }
89
89
  class FlowSurfaceAggregateError extends FlowSurfaceError {
90
90
  errors;
91
- constructor(errors, message = "flowSurfaces authoring validation failed") {
92
- const normalizedErrors = errors.map((error) => normalizeFlowSurfaceErrorItemInput(error));
93
- super(message, 400, "bad_request", "FLOW_SURFACE_AUTHORING_VALIDATION_FAILED");
91
+ constructor(errors, message) {
92
+ const normalizedErrors = errors.map(
93
+ (error, index) => normalizeFlowSurfaceErrorItemInput({
94
+ ...error,
95
+ index: index + 1
96
+ })
97
+ );
98
+ super(
99
+ message || buildAggregateBadRequestMessage(normalizedErrors.length),
100
+ 400,
101
+ "bad_request",
102
+ "FLOW_SURFACE_AUTHORING_VALIDATION_FAILED"
103
+ );
94
104
  this.name = "FlowSurfaceAggregateError";
95
105
  this.errors = normalizedErrors;
96
106
  }
97
107
  toResponseBody() {
98
108
  return {
109
+ message: this.message,
110
+ errorCount: this.errors.length,
111
+ details: buildAggregateBadRequestDetails(this.errors),
99
112
  errors: this.errors
100
113
  };
101
114
  }
@@ -162,6 +175,9 @@ function buildDefinedErrorItem(input) {
162
175
  code: input.code,
163
176
  status: input.status
164
177
  };
178
+ if (typeof input.index !== "undefined") {
179
+ output.index = input.index;
180
+ }
165
181
  if (typeof input.path !== "undefined") {
166
182
  output.path = input.path;
167
183
  }
@@ -176,6 +192,7 @@ function buildDefinedErrorItem(input) {
176
192
  function normalizeFlowSurfaceErrorItemInput(input) {
177
193
  return buildDefinedErrorItem({
178
194
  message: input.message,
195
+ index: input.index,
179
196
  type: input.type || "bad_request",
180
197
  code: input.code || "FLOW_SURFACE_AUTHORING_VALIDATION_ERROR",
181
198
  status: input.status || 400,
@@ -184,6 +201,35 @@ function normalizeFlowSurfaceErrorItemInput(input) {
184
201
  details: input.details
185
202
  });
186
203
  }
204
+ function buildAggregateBadRequestMessage(errorCount) {
205
+ return `flowSurfaces authoring validation failed with ${errorCount} error(s); fix all errors before retrying the same write`;
206
+ }
207
+ function buildAggregateBadRequestDetails(errors) {
208
+ const requiredBlockTypes = Array.from(
209
+ new Set(
210
+ errors.map((error) => {
211
+ var _a;
212
+ return (_a = error.details) == null ? void 0 : _a.requiredBlockType;
213
+ }).filter(
214
+ (requiredBlockType) => typeof requiredBlockType === "string" && !!requiredBlockType
215
+ )
216
+ )
217
+ );
218
+ return {
219
+ errorCount: errors.length,
220
+ mustFixAllErrorsBeforeRetry: true,
221
+ retryPolicy: "fix_all_errors_before_retry_same_write",
222
+ sameWriteRetryRequired: true,
223
+ agentInstruction: "Read the complete errors[] array. Fix every listed error in one payload revision before retrying the same write. Do not fix only the first error and immediately retry. Do not drop, defer, or replace required chart, jsBlock, or JS/RunJS work to bypass validation.",
224
+ ...requiredBlockTypes.length ? {
225
+ requiredBlockPolicy: {
226
+ requiredBlockTypes,
227
+ fixStrategy: "repair_same_block_type",
228
+ doNotReplaceOrDrop: true
229
+ }
230
+ } : {}
231
+ };
232
+ }
187
233
  // Annotate the CommonJS export names for ESM import in node:
188
234
  0 && (module.exports = {
189
235
  FlowSurfaceAggregateError,
@@ -0,0 +1,19 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+ export type FlowSurfaceEventFlowRecord = Record<string, unknown>;
10
+ export type FlowSurfaceEventFlowRegistry = Record<string, FlowSurfaceEventFlowRecord>;
11
+ export declare function buildFlowSurfaceEmptyEventCondition(): {
12
+ logic: string;
13
+ items: any[];
14
+ };
15
+ export declare function normalizeFlowSurfaceEventFlowOn(on: unknown): unknown;
16
+ export declare function normalizeFlowSurfaceEventFlow(actionName: string, key: string, flowInput: unknown): FlowSurfaceEventFlowRecord;
17
+ export declare function normalizeFlowSurfaceEventFlowRegistry(actionName: string, flowRegistry: Record<string, unknown>): FlowSurfaceEventFlowRegistry;
18
+ export declare function normalizeFlowSurfaceEventFlowRegistry<T>(actionName: string, flowRegistry: T): T;
19
+ export declare function isFlowSurfaceBeforeAllEventFlow(flow: unknown): boolean;