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

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 (96) 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 +15 -1
  89. package/dist/server/repository.js +262 -23
  90. package/dist/server/template/contexts.d.ts +2 -0
  91. package/dist/server/template/contexts.js +34 -0
  92. package/dist/server/template/resolver.js +233 -22
  93. package/dist/swagger/flow-surfaces.d.ts +175 -0
  94. package/dist/swagger/flow-surfaces.js +130 -51
  95. package/dist/swagger/index.d.ts +175 -0
  96. package/package.json +2 -2
@@ -0,0 +1,128 @@
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
+
10
+ var __create = Object.create;
11
+ var __defProp = Object.defineProperty;
12
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
13
+ var __getOwnPropNames = Object.getOwnPropertyNames;
14
+ var __getProtoOf = Object.getPrototypeOf;
15
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
16
+ var __export = (target, all) => {
17
+ for (var name in all)
18
+ __defProp(target, name, { get: all[name], enumerable: true });
19
+ };
20
+ var __copyProps = (to, from, except, desc) => {
21
+ if (from && typeof from === "object" || typeof from === "function") {
22
+ for (let key of __getOwnPropNames(from))
23
+ if (!__hasOwnProp.call(to, key) && key !== except)
24
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
25
+ }
26
+ return to;
27
+ };
28
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
29
+ // If the importer is in node compatibility mode or this is not an ESM
30
+ // file that has been converted to a CommonJS file using a Babel-
31
+ // compatible transform (i.e. "__esModule" has not been set), then set
32
+ // "default" to the CommonJS "module.exports" for node compatibility.
33
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
34
+ mod
35
+ ));
36
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
37
+ var event_flow_normalizer_exports = {};
38
+ __export(event_flow_normalizer_exports, {
39
+ buildFlowSurfaceEmptyEventCondition: () => buildFlowSurfaceEmptyEventCondition,
40
+ isFlowSurfaceBeforeAllEventFlow: () => isFlowSurfaceBeforeAllEventFlow,
41
+ normalizeFlowSurfaceEventFlow: () => normalizeFlowSurfaceEventFlow,
42
+ normalizeFlowSurfaceEventFlowOn: () => normalizeFlowSurfaceEventFlowOn,
43
+ normalizeFlowSurfaceEventFlowRegistry: () => normalizeFlowSurfaceEventFlowRegistry
44
+ });
45
+ module.exports = __toCommonJS(event_flow_normalizer_exports);
46
+ var import_lodash = __toESM(require("lodash"));
47
+ var import_errors = require("./errors");
48
+ function asPlainRecord(value) {
49
+ return import_lodash.default.isPlainObject(value) ? value : null;
50
+ }
51
+ function buildFlowSurfaceEmptyEventCondition() {
52
+ return { logic: "$and", items: [] };
53
+ }
54
+ function normalizeFlowSurfaceEventFlowOn(on) {
55
+ if (typeof on === "string") {
56
+ const eventName2 = on.trim();
57
+ if (!eventName2) {
58
+ return on;
59
+ }
60
+ return {
61
+ eventName: eventName2,
62
+ defaultParams: {
63
+ condition: buildFlowSurfaceEmptyEventCondition()
64
+ }
65
+ };
66
+ }
67
+ const onRecord = asPlainRecord(on);
68
+ if (!onRecord) {
69
+ return on;
70
+ }
71
+ const next = import_lodash.default.cloneDeep(onRecord);
72
+ const eventName = String(next.eventName || "").trim();
73
+ if (eventName) {
74
+ next.eventName = eventName;
75
+ }
76
+ const phase = String(next.phase || "").trim();
77
+ if (!phase || phase === "beforeAllFlows") {
78
+ delete next.phase;
79
+ } else {
80
+ next.phase = phase;
81
+ }
82
+ const defaultParams = asPlainRecord(next.defaultParams) || {};
83
+ if (!asPlainRecord(defaultParams.condition)) {
84
+ defaultParams.condition = buildFlowSurfaceEmptyEventCondition();
85
+ }
86
+ next.defaultParams = defaultParams;
87
+ return next;
88
+ }
89
+ function normalizeFlowSurfaceEventFlow(actionName, key, flowInput) {
90
+ const flowRecord = asPlainRecord(flowInput);
91
+ if (!flowRecord) {
92
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} flow '${key}' must be an object`);
93
+ }
94
+ const flow = import_lodash.default.cloneDeep(flowRecord);
95
+ flow.key = key;
96
+ if (asPlainRecord(flow.on) || typeof flow.on === "string") {
97
+ flow.on = normalizeFlowSurfaceEventFlowOn(flow.on);
98
+ }
99
+ if (import_lodash.default.isUndefined(flow.steps)) {
100
+ flow.steps = {};
101
+ }
102
+ return flow;
103
+ }
104
+ function normalizeFlowSurfaceEventFlowRegistry(actionName, flowRegistry) {
105
+ const registryRecord = asPlainRecord(flowRegistry);
106
+ if (!registryRecord) {
107
+ return flowRegistry;
108
+ }
109
+ return Object.fromEntries(
110
+ Object.entries(registryRecord).map(([key, flow]) => [key, normalizeFlowSurfaceEventFlow(actionName, key, flow)])
111
+ );
112
+ }
113
+ function isFlowSurfaceBeforeAllEventFlow(flow) {
114
+ const flowRecord = asPlainRecord(flow);
115
+ if (!flowRecord) {
116
+ return false;
117
+ }
118
+ const onRecord = asPlainRecord(normalizeFlowSurfaceEventFlowOn(flowRecord.on));
119
+ return Boolean(onRecord) && typeof (onRecord == null ? void 0 : onRecord.eventName) === "string" && (typeof onRecord.phase === "undefined" || onRecord.phase === "beforeAllFlows");
120
+ }
121
+ // Annotate the CommonJS export names for ESM import in node:
122
+ 0 && (module.exports = {
123
+ buildFlowSurfaceEmptyEventCondition,
124
+ isFlowSurfaceBeforeAllEventFlow,
125
+ normalizeFlowSurfaceEventFlow,
126
+ normalizeFlowSurfaceEventFlowOn,
127
+ normalizeFlowSurfaceEventFlowRegistry
128
+ });
@@ -11,5 +11,13 @@ export declare const FLOW_SURFACE_EMPTY_FILTER_GROUP: {
11
11
  items: any[];
12
12
  };
13
13
  export declare const FLOW_SURFACE_FILTER_GROUP_EXAMPLE: string;
14
- export declare function normalizeFlowSurfaceFilterGroupValue(value: any, errorPrefix: string): any;
14
+ export declare function assertFlowSurfaceFilterOperator(operator: unknown, path: string): void;
15
+ export declare function normalizeFlowSurfaceFilterDateValue(operator: unknown, value: unknown, path: string): unknown;
16
+ export declare function normalizeFlowSurfaceStrictFilterDateValue(operator: unknown, value: unknown, path: string): unknown;
17
+ export declare function normalizeFlowSurfaceFilterGroupValue(value: any, errorPrefix: string, options?: {
18
+ strictDateValues?: boolean;
19
+ }): any;
20
+ export declare function normalizeFlowSurfaceCompatibleFilterGroupValue(value: unknown, errorPrefix: string, options?: {
21
+ strictDateValues?: boolean;
22
+ }): any;
15
23
  export declare function assertFlowSurfaceFilterGroupShape(filter: any): void;
@@ -39,24 +39,168 @@ __export(filter_group_exports, {
39
39
  FLOW_SURFACE_EMPTY_FILTER_GROUP: () => FLOW_SURFACE_EMPTY_FILTER_GROUP,
40
40
  FLOW_SURFACE_FILTER_GROUP_EXAMPLE: () => FLOW_SURFACE_FILTER_GROUP_EXAMPLE,
41
41
  assertFlowSurfaceFilterGroupShape: () => assertFlowSurfaceFilterGroupShape,
42
- normalizeFlowSurfaceFilterGroupValue: () => normalizeFlowSurfaceFilterGroupValue
42
+ assertFlowSurfaceFilterOperator: () => assertFlowSurfaceFilterOperator,
43
+ normalizeFlowSurfaceCompatibleFilterGroupValue: () => normalizeFlowSurfaceCompatibleFilterGroupValue,
44
+ normalizeFlowSurfaceFilterDateValue: () => normalizeFlowSurfaceFilterDateValue,
45
+ normalizeFlowSurfaceFilterGroupValue: () => normalizeFlowSurfaceFilterGroupValue,
46
+ normalizeFlowSurfaceStrictFilterDateValue: () => normalizeFlowSurfaceStrictFilterDateValue
43
47
  });
44
48
  module.exports = __toCommonJS(filter_group_exports);
49
+ var import_database = require("@nocobase/database");
45
50
  var import_utils = require("@nocobase/utils");
46
51
  var import_lodash = __toESM(require("lodash"));
52
+ var import_sequelize = require("sequelize");
47
53
  var import_errors = require("./errors");
48
54
  const FLOW_SURFACE_EMPTY_FILTER_GROUP = {
49
55
  logic: "$and",
50
56
  items: []
51
57
  };
52
58
  const FLOW_SURFACE_FILTER_GROUP_EXAMPLE = JSON.stringify(FLOW_SURFACE_EMPTY_FILTER_GROUP);
53
- function normalizeFlowSurfaceFilterGroupValue(value, errorPrefix) {
59
+ const FLOW_SURFACE_FILTER_OPERATOR_REPAIR_HINT = "FilterGroup operators must use NocoBase operator names such as $notIn and $dateBefore.";
60
+ const FLOW_SURFACE_FILTER_OPERATOR_REPAIR_EXAMPLE = {
61
+ logic: "$and",
62
+ items: [
63
+ {
64
+ path: "stage",
65
+ operator: "$notIn",
66
+ value: ["won", "lost"]
67
+ }
68
+ ]
69
+ };
70
+ const FLOW_SURFACE_DATE_FILTER_OPERATORS = /* @__PURE__ */ new Set([
71
+ "$dateOn",
72
+ "$dateNotOn",
73
+ "$dateBefore",
74
+ "$dateAfter",
75
+ "$dateNotBefore",
76
+ "$dateNotAfter",
77
+ "$dateBetween"
78
+ ]);
79
+ const FLOW_SURFACE_DATE_RANGE_TYPES = /* @__PURE__ */ new Set([
80
+ "today",
81
+ "yesterday",
82
+ "tomorrow",
83
+ "thisWeek",
84
+ "lastWeek",
85
+ "nextWeek",
86
+ "thisMonth",
87
+ "lastMonth",
88
+ "nextMonth",
89
+ "thisQuarter",
90
+ "lastQuarter",
91
+ "nextQuarter",
92
+ "thisYear",
93
+ "lastYear",
94
+ "nextYear",
95
+ "past",
96
+ "next"
97
+ ]);
98
+ const FLOW_SURFACE_DATE_RANGE_UNITS = /* @__PURE__ */ new Set(["day", "week", "month", "year"]);
99
+ const FLOW_SURFACE_RELATIVE_DATE_DESCRIPTOR_KEYS = /* @__PURE__ */ new Set(["type", "number", "unit"]);
100
+ const FLOW_SURFACE_EXACT_DATE_VALUE_FORMATS = ["YYYY-MM-DD", "YYYY-MM", "YYYY", "YYYY[Q]Q", "YYYY-[Q]Q"];
101
+ const FLOW_SURFACE_DATE_VALUE_REPAIR_HINT = 'Date filter values must match the NocoBase filter UI contract: exact values like "2026-05-17", "2026-05", "2026", "2026-Q2", ranges like ["2026-05-01","2026-05-31"], or relative date descriptors like {"type":"past","number":14,"unit":"day"} and {"type":"thisWeek"}.';
102
+ const FLOW_SURFACE_DATE_VALUE_REPAIR_EXAMPLE = {
103
+ logic: "$and",
104
+ items: [
105
+ {
106
+ path: "lastFollowUpAt",
107
+ operator: "$dateBefore",
108
+ value: { type: "past", number: 14, unit: "day" }
109
+ }
110
+ ]
111
+ };
112
+ const FLOW_SURFACE_KNOWN_FILTER_OPERATORS = buildFlowSurfaceKnownFilterOperators();
113
+ function buildFlowSurfaceKnownFilterOperators() {
114
+ const operators = new Set(Object.keys(import_database.operators));
115
+ for (const key in import_sequelize.Op) {
116
+ operators.add(`$${key}`);
117
+ const underscored = import_sequelize.Utils.underscoredIf(key, true);
118
+ operators.add(`$${underscored}`);
119
+ operators.add(`$${underscored.replace(/_/g, "")}`);
120
+ }
121
+ return operators;
122
+ }
123
+ function getSuggestedFlowSurfaceFilterOperator(operator) {
124
+ if (operator.startsWith("$")) {
125
+ return void 0;
126
+ }
127
+ const suggestedOperator = `$${operator}`;
128
+ return FLOW_SURFACE_KNOWN_FILTER_OPERATORS.has(suggestedOperator) ? suggestedOperator : void 0;
129
+ }
130
+ function assertFlowSurfaceFilterOperator(operator, path) {
131
+ if (typeof operator !== "string" || !operator.trim()) {
132
+ (0, import_errors.throwBadRequest)(`${path} must be a non-empty operator string`, {
133
+ path,
134
+ ruleId: "filter-group-operator-invalid",
135
+ details: {
136
+ invalidOperator: operator,
137
+ repairHint: FLOW_SURFACE_FILTER_OPERATOR_REPAIR_HINT,
138
+ repairExample: FLOW_SURFACE_FILTER_OPERATOR_REPAIR_EXAMPLE
139
+ }
140
+ });
141
+ }
142
+ if (!operator.startsWith("$")) {
143
+ const suggestedOperator = getSuggestedFlowSurfaceFilterOperator(operator);
144
+ (0, import_errors.throwBadRequest)(
145
+ suggestedOperator ? `${path} must start with "$"; use "${suggestedOperator}" instead of "${operator}"` : `${path} must start with "$"`,
146
+ {
147
+ path,
148
+ ruleId: "filter-group-operator-missing-dollar",
149
+ details: {
150
+ invalidOperator: operator,
151
+ ...suggestedOperator ? { suggestedOperator } : {},
152
+ repairHint: FLOW_SURFACE_FILTER_OPERATOR_REPAIR_HINT,
153
+ repairExample: FLOW_SURFACE_FILTER_OPERATOR_REPAIR_EXAMPLE
154
+ }
155
+ }
156
+ );
157
+ }
158
+ }
159
+ function normalizeFlowSurfaceFilterDateValue(operator, value, path) {
160
+ if (typeof operator !== "string" || !FLOW_SURFACE_DATE_FILTER_OPERATORS.has(operator)) {
161
+ return value;
162
+ }
163
+ return normalizeFlowSurfaceDateValue(value, path);
164
+ }
165
+ function normalizeFlowSurfaceStrictFilterDateValue(operator, value, path) {
166
+ if (typeof operator !== "string" || !FLOW_SURFACE_DATE_FILTER_OPERATORS.has(operator)) {
167
+ return value;
168
+ }
169
+ if (import_lodash.default.isNil(value) || value === "") {
170
+ throwInvalidFlowSurfaceDateValue(path, value, {
171
+ invalidReason: "date filter value is required"
172
+ });
173
+ }
174
+ return normalizeFlowSurfaceDateValue(value, path);
175
+ }
176
+ function normalizeFlowSurfaceFilterGroupValue(value, errorPrefix, options = {}) {
54
177
  const normalized = value === null || import_lodash.default.isPlainObject(value) && !Object.keys(value).length ? import_lodash.default.cloneDeep(FLOW_SURFACE_EMPTY_FILTER_GROUP) : import_lodash.default.cloneDeep(value);
55
178
  try {
56
179
  assertFlowSurfaceFilterGroupShape(normalized);
180
+ assertFlowSurfaceFilterGroupOperators(normalized, errorPrefix);
181
+ normalizeFlowSurfaceFilterGroupDateValues(normalized, errorPrefix, options);
57
182
  (0, import_utils.transformFilter)(normalized);
58
183
  return normalized;
59
184
  } catch (error) {
185
+ if (error instanceof import_errors.FlowSurfaceBadRequestError) {
186
+ throw error;
187
+ }
188
+ const reason = error instanceof Error ? error.message : String(error);
189
+ (0, import_errors.throwBadRequest)(`${errorPrefix}: ${reason}`);
190
+ }
191
+ }
192
+ function normalizeFlowSurfaceCompatibleFilterGroupValue(value, errorPrefix, options = {}) {
193
+ const input = value === null || import_lodash.default.isPlainObject(value) && !Object.keys(value).length ? import_lodash.default.cloneDeep(FLOW_SURFACE_EMPTY_FILTER_GROUP) : import_lodash.default.cloneDeep(value);
194
+ if (isFlowSurfaceFilterGroupLike(input)) {
195
+ return normalizeFlowSurfaceFilterGroupValue(input, errorPrefix, options);
196
+ }
197
+ try {
198
+ const converted = convertBackendQueryFilterToFlowSurfaceFilterGroup(input, errorPrefix);
199
+ return normalizeFlowSurfaceFilterGroupValue(converted, errorPrefix, options);
200
+ } catch (error) {
201
+ if (error instanceof import_errors.FlowSurfaceBadRequestError) {
202
+ throw error;
203
+ }
60
204
  const reason = error instanceof Error ? error.message : String(error);
61
205
  (0, import_errors.throwBadRequest)(`${errorPrefix}: ${reason}`);
62
206
  }
@@ -65,6 +209,10 @@ function assertFlowSurfaceFilterGroupShape(filter) {
65
209
  if (!import_lodash.default.isPlainObject(filter)) {
66
210
  throw new Error("Invalid filter: filter must be an object");
67
211
  }
212
+ const unsupportedKeys = Object.keys(filter).filter((key) => key !== "logic" && key !== "items");
213
+ if (unsupportedKeys.length) {
214
+ throw new Error(`Invalid filter: filter group does not support: ${unsupportedKeys.join(", ")}`);
215
+ }
68
216
  if (!("logic" in filter) || !("items" in filter)) {
69
217
  throw new Error("Invalid filter: filter must have logic and items properties");
70
218
  }
@@ -85,10 +233,261 @@ function assertFlowSurfaceFilterGroupShape(filter) {
85
233
  throw new Error("Invalid filter item type");
86
234
  });
87
235
  }
236
+ function isFlowSurfaceFilterGroupLike(value) {
237
+ if (!import_lodash.default.isPlainObject(value)) {
238
+ return false;
239
+ }
240
+ const filter = value;
241
+ return "logic" in filter && "items" in filter;
242
+ }
243
+ function isBackendQueryLogicKey(key) {
244
+ return key === "$and" || key === "$or";
245
+ }
246
+ function convertBackendQueryFilterToFlowSurfaceFilterGroup(input, label) {
247
+ if (!import_lodash.default.isPlainObject(input)) {
248
+ throw new Error("Invalid filter: filter must be an object");
249
+ }
250
+ const keys = Object.keys(input);
251
+ const logicKeys = keys.filter(isBackendQueryLogicKey);
252
+ if (logicKeys.length > 1 || logicKeys.length === 1 && keys.length > 1) {
253
+ throw new Error("cannot convert backend query filter with mixed logical and field conditions");
254
+ }
255
+ if (logicKeys.length === 1) {
256
+ const logic = logicKeys[0];
257
+ const operands = input[logic];
258
+ if (!Array.isArray(operands)) {
259
+ throw new Error(`${logic}: backend query filter operands must be an array`);
260
+ }
261
+ return {
262
+ logic,
263
+ items: operands.map((operand, index) => convertBackendQueryOperandToFlowSurfaceFilterItem(operand, label, index))
264
+ };
265
+ }
266
+ if (keys.some((key) => key.startsWith("$"))) {
267
+ throw new Error("cannot convert backend query filter with unsupported logical operator");
268
+ }
269
+ return {
270
+ logic: "$and",
271
+ items: Object.entries(input).flatMap(
272
+ ([field, condition]) => convertBackendFieldConditionToFlowSurfaceFilterItems(field, condition, label)
273
+ )
274
+ };
275
+ }
276
+ function convertBackendQueryOperandToFlowSurfaceFilterItem(input, label, index) {
277
+ if (isFlowSurfaceFilterGroupLike(input)) {
278
+ throw new Error(`${label}.$operand[${index}]: cannot mix filter groups with backend query filters`);
279
+ }
280
+ const group = convertBackendQueryFilterToFlowSurfaceFilterGroup(input, `${label}.$operand[${index}]`);
281
+ if (group.logic === "$and" && group.items.length === 1) {
282
+ return group.items[0];
283
+ }
284
+ return group;
285
+ }
286
+ function convertBackendFieldConditionToFlowSurfaceFilterItems(field, condition, label) {
287
+ if (!field.trim() || field.startsWith("$")) {
288
+ throw new Error(`cannot convert backend query filter field "${field}"`);
289
+ }
290
+ if (!import_lodash.default.isPlainObject(condition)) {
291
+ throw new Error(`${field}: backend query filter condition must be an object`);
292
+ }
293
+ const keys = Object.keys(condition);
294
+ if (!keys.length) {
295
+ throw new Error(`${field}: backend query filter condition cannot be empty`);
296
+ }
297
+ const operatorKeys = keys.filter((key) => key.startsWith("$"));
298
+ if (operatorKeys.length) {
299
+ if (operatorKeys.length !== keys.length) {
300
+ throw new Error(`${field}: cannot mix backend query operators with nested field conditions`);
301
+ }
302
+ return operatorKeys.map((operator) => {
303
+ if (isBackendQueryLogicKey(operator)) {
304
+ throw new Error(`${field}: cannot convert backend query filter operator "${operator}"`);
305
+ }
306
+ assertFlowSurfaceFilterOperator(operator, `${label}.${field}.${operator}`);
307
+ return {
308
+ path: field,
309
+ operator,
310
+ value: import_lodash.default.cloneDeep(import_lodash.default.get(condition, operator))
311
+ };
312
+ });
313
+ }
314
+ return Object.entries(condition).flatMap(
315
+ ([nestedField, nestedCondition]) => convertBackendFieldConditionToFlowSurfaceFilterItems(`${field}.${nestedField}`, nestedCondition, label)
316
+ );
317
+ }
318
+ function assertFlowSurfaceFilterGroupOperators(filter, errorPrefix) {
319
+ filter.items.forEach((item, index) => {
320
+ const itemPath = `${errorPrefix}.items[${index}]`;
321
+ if (import_lodash.default.isPlainObject(item) && "logic" in item && "items" in item) {
322
+ assertFlowSurfaceFilterGroupOperators(item, itemPath);
323
+ return;
324
+ }
325
+ assertFlowSurfaceFilterOperator(item.operator, `${itemPath}.operator`);
326
+ });
327
+ }
328
+ function normalizeFlowSurfaceFilterGroupDateValues(filter, errorPrefix, options) {
329
+ filter.items.forEach((item, index) => {
330
+ const itemPath = `${errorPrefix}.items[${index}]`;
331
+ if (import_lodash.default.isPlainObject(item) && "logic" in item && "items" in item) {
332
+ normalizeFlowSurfaceFilterGroupDateValues(item, itemPath, options);
333
+ return;
334
+ }
335
+ item.value = options.strictDateValues ? normalizeFlowSurfaceStrictFilterDateValue(item.operator, item.value, `${itemPath}.value`) : normalizeFlowSurfaceFilterDateValue(item.operator, item.value, `${itemPath}.value`);
336
+ });
337
+ }
338
+ function normalizeFlowSurfaceDateValue(value, path) {
339
+ if (import_lodash.default.isNil(value) || value === "") {
340
+ return value;
341
+ }
342
+ if (Array.isArray(value)) {
343
+ return normalizeFlowSurfaceDateArrayValue(value, path);
344
+ }
345
+ return normalizeFlowSurfaceDateValuePart(value, path);
346
+ }
347
+ function normalizeFlowSurfaceDateArrayValue(value, path) {
348
+ if (value.length !== 2) {
349
+ throwInvalidFlowSurfaceDateValue(path, value, {
350
+ invalidReason: "date range arrays must contain exactly start and end values"
351
+ });
352
+ }
353
+ return value.map((item, index) => normalizeFlowSurfaceExactDateValuePart(item, `${path}[${index}]`));
354
+ }
355
+ function normalizeFlowSurfaceDateValuePart(value, path) {
356
+ if (import_lodash.default.isNil(value) || value === "" || isTemplateDateString(value)) {
357
+ return value;
358
+ }
359
+ if (typeof value === "string") {
360
+ return normalizeFlowSurfaceExactDateValuePart(value, path);
361
+ }
362
+ if (import_lodash.default.isPlainObject(value)) {
363
+ return normalizeRelativeDateDescriptor(value, path);
364
+ }
365
+ throwInvalidFlowSurfaceDateValue(path, value, {
366
+ invalidReason: "date filter value must be an exact date string, date range array, or relative date descriptor"
367
+ });
368
+ }
369
+ function normalizeFlowSurfaceExactDateValuePart(value, path) {
370
+ if (isTemplateDateString(value)) {
371
+ return value;
372
+ }
373
+ if (typeof value === "string") {
374
+ const normalized = value.trim();
375
+ if (isFlowSurfaceExactDateValue(normalized)) {
376
+ return normalized;
377
+ }
378
+ }
379
+ throwInvalidFlowSurfaceDateValue(path, value, {
380
+ invalidReason: "date filter strings must use UI exact date formats YYYY-MM-DD, YYYY-MM, YYYY, YYYYQn, or YYYY-Qn"
381
+ });
382
+ }
383
+ function isFlowSurfaceExactDateValue(value) {
384
+ return FLOW_SURFACE_EXACT_DATE_VALUE_FORMATS.some((format) => {
385
+ const parsed = (0, import_utils.dayjs)(value, format, true);
386
+ return parsed.isValid() && parsed.format(format) === value;
387
+ });
388
+ }
389
+ function normalizeRelativeDateDescriptor(value, path) {
390
+ const invalidKeys = Object.keys(value).filter((key) => !FLOW_SURFACE_RELATIVE_DATE_DESCRIPTOR_KEYS.has(key));
391
+ if (invalidKeys.length) {
392
+ throwInvalidFlowSurfaceDateValue(path, value, {
393
+ invalidReason: `relative date descriptor contains unsupported keys: ${invalidKeys.join(", ")}`
394
+ });
395
+ }
396
+ const rawType = value.type;
397
+ const type = typeof rawType === "string" ? rawType.trim() : "";
398
+ if (!isTemplateDateString(rawType) && !FLOW_SURFACE_DATE_RANGE_TYPES.has(type)) {
399
+ throwInvalidFlowSurfaceDateValue(path, value, {
400
+ invalidReason: type ? `unsupported relative date type "${type}"` : "relative date descriptor must include type"
401
+ });
402
+ }
403
+ const normalized = {
404
+ ...value,
405
+ type: isTemplateDateString(rawType) ? rawType : type
406
+ };
407
+ if (type === "past" || type === "next") {
408
+ if (import_lodash.default.isUndefined(value.number)) {
409
+ throwInvalidFlowSurfaceDateValue(path, value, {
410
+ invalidReason: "past/next relative date descriptor must include number"
411
+ });
412
+ } else if (!isTemplateDateString(value.number)) {
413
+ if (typeof value.number !== "number" || !Number.isFinite(value.number) || value.number <= 0) {
414
+ throwInvalidFlowSurfaceDateValue(path, value, {
415
+ invalidReason: "past/next relative date descriptor number must be greater than 0"
416
+ });
417
+ }
418
+ normalized.number = value.number;
419
+ }
420
+ if (import_lodash.default.isUndefined(value.unit)) {
421
+ throwInvalidFlowSurfaceDateValue(path, value, {
422
+ invalidReason: "past/next relative date descriptor must include unit"
423
+ });
424
+ } else if (!isTemplateDateString(value.unit)) {
425
+ const unit = typeof value.unit === "string" ? value.unit.trim() : "";
426
+ if (!FLOW_SURFACE_DATE_RANGE_UNITS.has(unit)) {
427
+ throwInvalidFlowSurfaceDateValue(path, value, {
428
+ invalidReason: `unsupported relative date unit "${unit}"`
429
+ });
430
+ }
431
+ normalized.unit = unit;
432
+ }
433
+ } else {
434
+ if (!import_lodash.default.isUndefined(value.number)) {
435
+ throwInvalidFlowSurfaceDateValue(path, value, {
436
+ invalidReason: `relative date descriptor type "${type}" must not include number`
437
+ });
438
+ }
439
+ if (!import_lodash.default.isUndefined(value.unit)) {
440
+ throwInvalidFlowSurfaceDateValue(path, value, {
441
+ invalidReason: `relative date descriptor type "${type}" must not include unit`
442
+ });
443
+ }
444
+ }
445
+ if (!hasTemplateDateValue(normalized)) {
446
+ try {
447
+ (0, import_utils.getDayRangeByParams)(normalized);
448
+ } catch (error) {
449
+ throwInvalidFlowSurfaceDateValue(path, value, {
450
+ invalidReason: error instanceof Error ? error.message : String(error)
451
+ });
452
+ }
453
+ }
454
+ return normalized;
455
+ }
456
+ function isTemplateDateString(value) {
457
+ return typeof value === "string" && /^\s*\{\{[\s\S]*\}\}\s*$/.test(value);
458
+ }
459
+ function hasTemplateDateValue(value) {
460
+ if (isTemplateDateString(value)) {
461
+ return true;
462
+ }
463
+ if (Array.isArray(value)) {
464
+ return value.some((item) => hasTemplateDateValue(item));
465
+ }
466
+ if (import_lodash.default.isPlainObject(value)) {
467
+ return Object.values(value).some((item) => hasTemplateDateValue(item));
468
+ }
469
+ return false;
470
+ }
471
+ function throwInvalidFlowSurfaceDateValue(path, value, details = {}) {
472
+ (0, import_errors.throwBadRequest)(`${path} must be a valid date filter value`, {
473
+ path,
474
+ ruleId: "filter-group-date-value-invalid",
475
+ details: {
476
+ invalidValue: value,
477
+ ...details,
478
+ repairHint: FLOW_SURFACE_DATE_VALUE_REPAIR_HINT,
479
+ repairExample: FLOW_SURFACE_DATE_VALUE_REPAIR_EXAMPLE
480
+ }
481
+ });
482
+ }
88
483
  // Annotate the CommonJS export names for ESM import in node:
89
484
  0 && (module.exports = {
90
485
  FLOW_SURFACE_EMPTY_FILTER_GROUP,
91
486
  FLOW_SURFACE_FILTER_GROUP_EXAMPLE,
92
487
  assertFlowSurfaceFilterGroupShape,
93
- normalizeFlowSurfaceFilterGroupValue
488
+ assertFlowSurfaceFilterOperator,
489
+ normalizeFlowSurfaceCompatibleFilterGroupValue,
490
+ normalizeFlowSurfaceFilterDateValue,
491
+ normalizeFlowSurfaceFilterGroupValue,
492
+ normalizeFlowSurfaceStrictFilterDateValue
94
493
  });
@@ -263,7 +263,8 @@ function normalizeFlowSurfacePublicBlockDefaultFilter(actionName, defaultFilter,
263
263
  }
264
264
  const normalized = (0, import_filter_group.normalizeFlowSurfaceFilterGroupValue)(
265
265
  defaultFilter,
266
- `flowSurfaces ${actionName} ${fieldPath} expects FilterGroup like ${import_filter_group.FLOW_SURFACE_FILTER_GROUP_EXAMPLE}`
266
+ `flowSurfaces ${actionName} ${fieldPath} expects FilterGroup like ${import_filter_group.FLOW_SURFACE_FILTER_GROUP_EXAMPLE}`,
267
+ { strictDateValues: true }
267
268
  );
268
269
  return normalized;
269
270
  }
@@ -166,7 +166,7 @@ class FlowSurfaceRouteSync {
166
166
  await this.removeRouteAnchorChildren(schemaUid, transaction);
167
167
  }
168
168
  async persistPageSettings(target, current, nextPayload, transaction) {
169
- var _a;
169
+ var _a, _b;
170
170
  const route = await this.hydrateRoute(target.pageRoute, transaction);
171
171
  const routeValues = this.buildPageRoutePatch(current, nextPayload, route);
172
172
  if (Object.keys(routeValues).length) {
@@ -175,8 +175,25 @@ class FlowSurfaceRouteSync {
175
175
  values: routeValues,
176
176
  transaction
177
177
  });
178
+ if (Object.prototype.hasOwnProperty.call(routeValues, "enableTabs")) {
179
+ const tabRouteHidden = !routeValues.enableTabs;
180
+ await Promise.all(
181
+ import_lodash.default.castArray(((_a = route == null ? void 0 : route.get) == null ? void 0 : _a.call(route, "children")) || (route == null ? void 0 : route.children) || []).map((tabRoute) => {
182
+ var _a2;
183
+ return ((_a2 = tabRoute == null ? void 0 : tabRoute.get) == null ? void 0 : _a2.call(tabRoute, "id")) ?? (tabRoute == null ? void 0 : tabRoute.id);
184
+ }).filter((routeId) => !import_lodash.default.isNil(routeId) && routeId !== "").map(
185
+ (routeId) => this.db.getRepository("desktopRoutes").update({
186
+ filterByTk: String(routeId),
187
+ values: {
188
+ hidden: tabRouteHidden
189
+ },
190
+ transaction
191
+ })
192
+ )
193
+ );
194
+ }
178
195
  }
179
- const pageSchemaUid = ((_a = route == null ? void 0 : route.get) == null ? void 0 : _a.call(route, "schemaUid")) || (route == null ? void 0 : route.schemaUid);
196
+ const pageSchemaUid = ((_b = route == null ? void 0 : route.get) == null ? void 0 : _b.call(route, "schemaUid")) || (route == null ? void 0 : route.schemaUid);
180
197
  const pageModel = target.pageModel || (pageSchemaUid ? await this.repository.findModelByParentId(pageSchemaUid, {
181
198
  transaction,
182
199
  subKey: "page",