@nocobase/plugin-flow-engine 2.2.0-beta.9 → 2.3.0-alpha.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 (37) hide show
  1. package/dist/ai/ai-employees/nathan/skills/frontend-developer/tools/getContextApis.js +2 -2
  2. package/dist/ai/ai-employees/nathan/skills/frontend-developer/tools/getContextEnvs.js +2 -2
  3. package/dist/ai/ai-employees/nathan/skills/frontend-developer/tools/getContextVars.js +2 -2
  4. package/dist/ai/ai-employees/nathan/skills/frontend-developer/tools/lintAndTestJS.js +2 -2
  5. package/dist/ai/ai-employees/nathan/skills/frontend-developer/tools/patchJSCode.js +2 -2
  6. package/dist/ai/ai-employees/nathan/skills/frontend-developer/tools/readJSCode.js +2 -2
  7. package/dist/ai/ai-employees/nathan/skills/frontend-developer/tools/writeJSCode.js +2 -2
  8. package/dist/ai/docs/runjs/context/ai.md +206 -0
  9. package/dist/externalVersion.js +9 -9
  10. package/dist/node_modules/@ant-design/icons-svg/package.json +1 -1
  11. package/dist/node_modules/acorn/package.json +1 -1
  12. package/dist/node_modules/acorn-jsx/package.json +1 -1
  13. package/dist/node_modules/acorn-walk/package.json +1 -1
  14. package/dist/node_modules/ses/package.json +1 -1
  15. package/dist/node_modules/zod/package.json +1 -1
  16. package/dist/server/flow-surfaces/authoring-validation.d.ts +2 -1
  17. package/dist/server/flow-surfaces/authoring-validation.js +167 -19
  18. package/dist/server/flow-surfaces/blueprint/compile-blocks.js +7 -3
  19. package/dist/server/flow-surfaces/blueprint/compile-plan.js +19 -15
  20. package/dist/server/flow-surfaces/blueprint/normalize-document.js +18 -2
  21. package/dist/server/flow-surfaces/blueprint/public-types.d.ts +1 -0
  22. package/dist/server/flow-surfaces/builder.js +3 -0
  23. package/dist/server/flow-surfaces/constants.d.ts +9 -2
  24. package/dist/server/flow-surfaces/constants.js +1 -0
  25. package/dist/server/flow-surfaces/contract-guard.js +20 -10
  26. package/dist/server/flow-surfaces/errors.d.ts +2 -2
  27. package/dist/server/flow-surfaces/errors.js +4 -4
  28. package/dist/server/flow-surfaces/navigation-targets.d.ts +73 -0
  29. package/dist/server/flow-surfaces/navigation-targets.js +439 -0
  30. package/dist/server/flow-surfaces/runjs-authoring/runtime/constants.js +1 -0
  31. package/dist/server/flow-surfaces/service.d.ts +14 -2
  32. package/dist/server/flow-surfaces/service.js +471 -115
  33. package/dist/server/variables/records.js +7 -2
  34. package/dist/swagger/flow-surfaces.d.ts +96 -0
  35. package/dist/swagger/flow-surfaces.js +88 -7
  36. package/dist/swagger/index.d.ts +96 -0
  37. package/package.json +2 -2
@@ -0,0 +1,73 @@
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
+ import type { Database, Transaction } from '@nocobase/database';
10
+ export declare const DEFAULT_ADMIN_UI_LAYOUT_UID = "admin-layout-model";
11
+ export declare const DEFAULT_MOBILE_UI_LAYOUT_UID = "mobile-layout-model";
12
+ export declare const DEFAULT_ADMIN_MULTI_PORTAL_UID = "__default_admin__";
13
+ export declare const DEFAULT_MOBILE_MULTI_PORTAL_UID = "__default_mobile__";
14
+ export type FlowSurfaceNavigationRequestRoles = readonly string[] | string;
15
+ export type FlowSurfaceResolvedMultiPortal = {
16
+ uid: string;
17
+ title: string;
18
+ icon?: string | null;
19
+ routeName?: string;
20
+ routePath?: string;
21
+ authCheck?: boolean;
22
+ enabled: true;
23
+ layoutUid: string;
24
+ layoutType?: string;
25
+ };
26
+ export type FlowSurfaceNavigationTarget = {
27
+ kind: 'layout' | 'portal';
28
+ uid: string;
29
+ title: string;
30
+ icon?: string | null;
31
+ layoutUid: string;
32
+ layoutType?: string;
33
+ routeName?: string;
34
+ routePath?: string;
35
+ authCheck?: boolean;
36
+ default?: boolean;
37
+ portalUid?: string;
38
+ };
39
+ export type FlowSurfaceNavigationTargetsResult = {
40
+ version: '1';
41
+ capabilities: {
42
+ multiPortal: boolean;
43
+ };
44
+ targets: FlowSurfaceNavigationTarget[];
45
+ };
46
+ type PortalResolveOptions = {
47
+ actionName: string;
48
+ path: string;
49
+ currentRoles?: FlowSurfaceNavigationRequestRoles;
50
+ transaction?: Transaction;
51
+ };
52
+ export declare class FlowSurfaceNavigationTargetsService {
53
+ private readonly db;
54
+ constructor(db: Database);
55
+ hasMultiPortalCapability(): boolean;
56
+ hasUiLayoutCapability(): boolean;
57
+ normalizePortalUid(value: unknown): string;
58
+ listNavigationTargets(currentRoles?: FlowSurfaceNavigationRequestRoles, transaction?: Transaction): Promise<FlowSurfaceNavigationTargetsResult>;
59
+ resolvePortal(portalUidValue: unknown, options: PortalResolveOptions): Promise<FlowSurfaceResolvedMultiPortal>;
60
+ readRoutePortalUids(routeId: unknown, transaction?: Transaction): Promise<string[]>;
61
+ assertRouteBelongsToPortal(actionName: string, routeId: unknown, portalUid: string, path: string, transaction?: Transaction): Promise<void>;
62
+ attachRouteTreeToPortals(routeId: unknown, portalUids: string[], options: {
63
+ portalOnly: boolean;
64
+ transaction?: Transaction;
65
+ }): Promise<void>;
66
+ private listLayoutTargets;
67
+ private listAccessiblePortalTargets;
68
+ private canAccessPortal;
69
+ private collectRouteTreeIds;
70
+ private removeDefaultLayoutRoutePermissions;
71
+ private grantDefaultPortalRouteAccess;
72
+ }
73
+ export {};
@@ -0,0 +1,439 @@
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 __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var navigation_targets_exports = {};
28
+ __export(navigation_targets_exports, {
29
+ DEFAULT_ADMIN_MULTI_PORTAL_UID: () => DEFAULT_ADMIN_MULTI_PORTAL_UID,
30
+ DEFAULT_ADMIN_UI_LAYOUT_UID: () => DEFAULT_ADMIN_UI_LAYOUT_UID,
31
+ DEFAULT_MOBILE_MULTI_PORTAL_UID: () => DEFAULT_MOBILE_MULTI_PORTAL_UID,
32
+ DEFAULT_MOBILE_UI_LAYOUT_UID: () => DEFAULT_MOBILE_UI_LAYOUT_UID,
33
+ FlowSurfaceNavigationTargetsService: () => FlowSurfaceNavigationTargetsService
34
+ });
35
+ module.exports = __toCommonJS(navigation_targets_exports);
36
+ var import_errors = require("./errors");
37
+ const DEFAULT_ADMIN_UI_LAYOUT_UID = "admin-layout-model";
38
+ const DEFAULT_MOBILE_UI_LAYOUT_UID = "mobile-layout-model";
39
+ const DEFAULT_ADMIN_MULTI_PORTAL_UID = "__default_admin__";
40
+ const DEFAULT_MOBILE_MULTI_PORTAL_UID = "__default_mobile__";
41
+ const RESERVED_MULTI_PORTAL_UIDS = /* @__PURE__ */ new Set([DEFAULT_ADMIN_MULTI_PORTAL_UID, DEFAULT_MOBILE_MULTI_PORTAL_UID]);
42
+ function readRecordField(record, field) {
43
+ if (!record || typeof record !== "object") {
44
+ return void 0;
45
+ }
46
+ const model = record;
47
+ if (typeof model.get === "function") {
48
+ return model.get(field);
49
+ }
50
+ return record[field];
51
+ }
52
+ function readStringField(record, field) {
53
+ const value = readRecordField(record, field);
54
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
55
+ }
56
+ function normalizeRoles(currentRoles) {
57
+ const roles = Array.isArray(currentRoles) ? currentRoles : typeof currentRoles === "string" ? [currentRoles] : [];
58
+ return roles.map((role) => String(role || "").trim()).filter(Boolean);
59
+ }
60
+ function normalizeRelationRouteId(routeId) {
61
+ return routeId === null || typeof routeId === "undefined" ? void 0 : routeId;
62
+ }
63
+ class FlowSurfaceNavigationTargetsService {
64
+ constructor(db) {
65
+ this.db = db;
66
+ }
67
+ hasMultiPortalCapability() {
68
+ var _a, _b;
69
+ try {
70
+ return !!this.db.getCollection("multiPortals") && !!((_b = (_a = this.db.getCollection("desktopRoutes")) == null ? void 0 : _a.getField) == null ? void 0 : _b.call(_a, "multiPortals"));
71
+ } catch (error) {
72
+ return false;
73
+ }
74
+ }
75
+ hasUiLayoutCapability() {
76
+ var _a, _b;
77
+ try {
78
+ return !!this.db.getCollection("uiLayouts") && !!((_b = (_a = this.db.getCollection("desktopRoutes")) == null ? void 0 : _a.getField) == null ? void 0 : _b.call(_a, "uiLayouts"));
79
+ } catch (error) {
80
+ return false;
81
+ }
82
+ }
83
+ normalizePortalUid(value) {
84
+ const portalUid = String(value || "").trim();
85
+ return portalUid || void 0;
86
+ }
87
+ async listNavigationTargets(currentRoles, transaction) {
88
+ const layoutTargets = await this.listLayoutTargets(transaction);
89
+ const multiPortal = this.hasMultiPortalCapability();
90
+ const portalTargets = multiPortal ? await this.listAccessiblePortalTargets(currentRoles, transaction) : [];
91
+ return {
92
+ version: "1",
93
+ capabilities: {
94
+ multiPortal
95
+ },
96
+ targets: [...layoutTargets, ...portalTargets]
97
+ };
98
+ }
99
+ async resolvePortal(portalUidValue, options) {
100
+ const portalUid = this.normalizePortalUid(portalUidValue);
101
+ if (!portalUid) {
102
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${options.actionName} ${options.path} must be a non-empty string`, {
103
+ ruleId: "navigation-portal-invalid",
104
+ path: options.path
105
+ });
106
+ }
107
+ if (!this.hasMultiPortalCapability()) {
108
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${options.actionName} ${options.path} requires the Multi-portal capability`, {
109
+ ruleId: "navigation-portal-unsupported",
110
+ path: options.path,
111
+ details: { portalUid }
112
+ });
113
+ }
114
+ if (RESERVED_MULTI_PORTAL_UIDS.has(portalUid)) {
115
+ (0, import_errors.throwBadRequest)(
116
+ `flowSurfaces ${options.actionName} ${options.path} cannot use reserved default portal uid '${portalUid}'; use layoutUid semantics instead`,
117
+ {
118
+ ruleId: "navigation-portal-reserved",
119
+ path: options.path,
120
+ details: { portalUid }
121
+ }
122
+ );
123
+ }
124
+ const portal = await this.db.getRepository("multiPortals").findOne({
125
+ filter: { uid: portalUid },
126
+ fields: ["uid", "title", "icon", "routeName", "routePath", "authCheck", "enabled", "uiLayoutUid"],
127
+ transaction: options.transaction
128
+ });
129
+ if (!portal) {
130
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${options.actionName} ${options.path} references missing portal '${portalUid}'`, {
131
+ ruleId: "navigation-portal-not-found",
132
+ path: options.path,
133
+ details: { portalUid }
134
+ });
135
+ }
136
+ if (readRecordField(portal, "enabled") !== true) {
137
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${options.actionName} portal '${portalUid}' is disabled`, {
138
+ ruleId: "navigation-portal-disabled",
139
+ path: options.path,
140
+ details: { portalUid }
141
+ });
142
+ }
143
+ const layoutUid = readStringField(portal, "uiLayoutUid");
144
+ if (!layoutUid || !this.db.getCollection("uiLayouts")) {
145
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${options.actionName} portal '${portalUid}' has no available backing UI layout`, {
146
+ ruleId: "navigation-portal-layout-not-found",
147
+ path: options.path,
148
+ details: { portalUid, layoutUid: layoutUid || null }
149
+ });
150
+ }
151
+ const layout = await this.db.getRepository("uiLayouts").findOne({
152
+ filter: { uid: layoutUid },
153
+ fields: ["uid", "layoutType", "enabled"],
154
+ transaction: options.transaction
155
+ });
156
+ if (!layout) {
157
+ (0, import_errors.throwBadRequest)(
158
+ `flowSurfaces ${options.actionName} portal '${portalUid}' backing UI layout '${layoutUid}' does not exist`,
159
+ {
160
+ ruleId: "navigation-portal-layout-not-found",
161
+ path: options.path,
162
+ details: { portalUid, layoutUid }
163
+ }
164
+ );
165
+ }
166
+ if (readRecordField(layout, "enabled") !== true) {
167
+ (0, import_errors.throwBadRequest)(
168
+ `flowSurfaces ${options.actionName} portal '${portalUid}' backing UI layout '${layoutUid}' is disabled`,
169
+ {
170
+ ruleId: "navigation-portal-layout-disabled",
171
+ path: options.path,
172
+ details: { portalUid, layoutUid }
173
+ }
174
+ );
175
+ }
176
+ if (!await this.canAccessPortal(portalUid, options.currentRoles, options.transaction)) {
177
+ (0, import_errors.throwForbidden)(
178
+ `flowSurfaces ${options.actionName} current roles cannot access portal '${portalUid}'`,
179
+ "FLOW_SURFACE_NAVIGATION_PORTAL_FORBIDDEN",
180
+ {
181
+ ruleId: "navigation-portal-forbidden",
182
+ path: options.path,
183
+ details: { portalUid }
184
+ }
185
+ );
186
+ }
187
+ return {
188
+ uid: portalUid,
189
+ title: readStringField(portal, "title") || portalUid,
190
+ icon: readStringField(portal, "icon") || null,
191
+ routeName: readStringField(portal, "routeName"),
192
+ routePath: readStringField(portal, "routePath"),
193
+ authCheck: readRecordField(portal, "authCheck") === true,
194
+ enabled: true,
195
+ layoutUid,
196
+ layoutType: readStringField(layout, "layoutType")
197
+ };
198
+ }
199
+ async readRoutePortalUids(routeId, transaction) {
200
+ const relationRouteId = normalizeRelationRouteId(routeId);
201
+ if (typeof relationRouteId === "undefined" || !this.hasMultiPortalCapability()) {
202
+ return [];
203
+ }
204
+ const portals = await this.db.getRepository("desktopRoutes.multiPortals", relationRouteId).find({ fields: ["uid"], transaction });
205
+ return Array.from(
206
+ new Set(
207
+ portals.map((portal) => readStringField(portal, "uid")).filter((portalUid) => !!portalUid)
208
+ )
209
+ );
210
+ }
211
+ async assertRouteBelongsToPortal(actionName, routeId, portalUid, path, transaction) {
212
+ const routePortalUids = await this.readRoutePortalUids(routeId, transaction);
213
+ if (routePortalUids.includes(portalUid)) {
214
+ return;
215
+ }
216
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${path} does not belong to portal '${portalUid}'`, {
217
+ ruleId: "navigation-route-portal-mismatch",
218
+ path,
219
+ details: {
220
+ routeId,
221
+ portalUid,
222
+ routePortalUids
223
+ }
224
+ });
225
+ }
226
+ async attachRouteTreeToPortals(routeId, portalUids, options) {
227
+ const normalizedPortalUids = Array.from(new Set(portalUids.map((uid) => String(uid || "").trim()).filter(Boolean)));
228
+ const relationRouteId = normalizeRelationRouteId(routeId);
229
+ if (typeof relationRouteId === "undefined" || !normalizedPortalUids.length || !this.hasMultiPortalCapability()) {
230
+ return;
231
+ }
232
+ const routeIds = await this.collectRouteTreeIds(relationRouteId, options.transaction);
233
+ for (const currentRouteId of routeIds) {
234
+ await this.db.getRepository("desktopRoutes.multiPortals", currentRouteId).set({ tk: normalizedPortalUids, transaction: options.transaction });
235
+ if (options.portalOnly && this.hasUiLayoutCapability()) {
236
+ await this.db.getRepository("desktopRoutes.uiLayouts", currentRouteId).set({ tk: [], transaction: options.transaction });
237
+ }
238
+ }
239
+ if (options.portalOnly) {
240
+ await this.removeDefaultLayoutRoutePermissions(routeIds, options.transaction);
241
+ }
242
+ for (const portalUid of normalizedPortalUids) {
243
+ await this.grantDefaultPortalRouteAccess(portalUid, routeIds, options.transaction);
244
+ }
245
+ }
246
+ async listLayoutTargets(transaction) {
247
+ const targets = [];
248
+ if (this.db.getCollection("uiLayouts")) {
249
+ const layouts = await this.db.getRepository("uiLayouts").find({
250
+ filter: { enabled: true },
251
+ fields: ["uid", "title", "layoutType", "routeName", "routePath", "authCheck"],
252
+ sort: ["uid"],
253
+ transaction
254
+ });
255
+ for (const layout of layouts) {
256
+ const layoutUid = readStringField(layout, "uid");
257
+ if (!layoutUid) {
258
+ continue;
259
+ }
260
+ targets.push({
261
+ kind: "layout",
262
+ uid: layoutUid,
263
+ title: readStringField(layout, "title") || layoutUid,
264
+ layoutUid,
265
+ layoutType: readStringField(layout, "layoutType"),
266
+ routeName: readStringField(layout, "routeName"),
267
+ routePath: readStringField(layout, "routePath"),
268
+ authCheck: readRecordField(layout, "authCheck") === true,
269
+ ...layoutUid === DEFAULT_ADMIN_UI_LAYOUT_UID ? { default: true } : {}
270
+ });
271
+ }
272
+ }
273
+ if (!targets.some((target) => target.uid === DEFAULT_ADMIN_UI_LAYOUT_UID)) {
274
+ targets.unshift({
275
+ kind: "layout",
276
+ uid: DEFAULT_ADMIN_UI_LAYOUT_UID,
277
+ title: "Admin",
278
+ layoutUid: DEFAULT_ADMIN_UI_LAYOUT_UID,
279
+ layoutType: "desktop",
280
+ routeName: "admin",
281
+ routePath: "/admin",
282
+ authCheck: true,
283
+ default: true
284
+ });
285
+ }
286
+ return targets.sort((left, right) => {
287
+ if (left.default) {
288
+ return -1;
289
+ }
290
+ if (right.default) {
291
+ return 1;
292
+ }
293
+ return left.uid.localeCompare(right.uid);
294
+ });
295
+ }
296
+ async listAccessiblePortalTargets(currentRoles, transaction) {
297
+ const roles = normalizeRoles(currentRoles);
298
+ let accessiblePortalUids;
299
+ if (!roles.includes("root")) {
300
+ if (!roles.length || !this.db.getCollection("rolesMultiPortals")) {
301
+ return [];
302
+ }
303
+ const grants = await this.db.getRepository("rolesMultiPortals").find({
304
+ fields: ["multiPortalUid"],
305
+ filter: { roleName: roles },
306
+ transaction
307
+ });
308
+ accessiblePortalUids = Array.from(
309
+ new Set(
310
+ grants.map((grant) => readStringField(grant, "multiPortalUid")).filter((portalUid) => !!portalUid)
311
+ )
312
+ );
313
+ if (!accessiblePortalUids.length) {
314
+ return [];
315
+ }
316
+ }
317
+ const accessiblePortalUidSet = accessiblePortalUids ? new Set(accessiblePortalUids) : void 0;
318
+ const filter = {
319
+ enabled: true,
320
+ "uid.$notIn": Array.from(RESERVED_MULTI_PORTAL_UIDS)
321
+ };
322
+ const portals = await this.db.getRepository("multiPortals").find({
323
+ filter,
324
+ fields: ["uid", "title", "icon", "routeName", "routePath", "authCheck", "enabled", "uiLayoutUid"],
325
+ sort: ["uid"],
326
+ transaction
327
+ });
328
+ const targets = [];
329
+ for (const portal of portals) {
330
+ const portalUid = readStringField(portal, "uid");
331
+ const layoutUid = readStringField(portal, "uiLayoutUid");
332
+ if (!portalUid || accessiblePortalUidSet && !accessiblePortalUidSet.has(portalUid) || !layoutUid || !this.db.getCollection("uiLayouts")) {
333
+ continue;
334
+ }
335
+ const layout = await this.db.getRepository("uiLayouts").findOne({
336
+ filter: { uid: layoutUid, enabled: true },
337
+ fields: ["layoutType"],
338
+ transaction
339
+ });
340
+ if (!layout) {
341
+ continue;
342
+ }
343
+ targets.push({
344
+ kind: "portal",
345
+ uid: portalUid,
346
+ portalUid,
347
+ title: readStringField(portal, "title") || portalUid,
348
+ icon: readStringField(portal, "icon") || null,
349
+ layoutUid,
350
+ layoutType: readStringField(layout, "layoutType"),
351
+ routeName: readStringField(portal, "routeName"),
352
+ routePath: readStringField(portal, "routePath"),
353
+ authCheck: readRecordField(portal, "authCheck") === true
354
+ });
355
+ }
356
+ return targets;
357
+ }
358
+ async canAccessPortal(portalUid, currentRoles, transaction) {
359
+ const roles = normalizeRoles(currentRoles);
360
+ if (roles.includes("root")) {
361
+ return true;
362
+ }
363
+ if (!roles.length || !this.db.getCollection("rolesMultiPortals")) {
364
+ return false;
365
+ }
366
+ const count = await this.db.getRepository("rolesMultiPortals").count({
367
+ filter: {
368
+ roleName: roles,
369
+ multiPortalUid: portalUid
370
+ },
371
+ transaction
372
+ });
373
+ return count > 0;
374
+ }
375
+ async collectRouteTreeIds(routeId, transaction) {
376
+ const routeIds = [routeId];
377
+ const children = await this.db.getRepository("desktopRoutes").find({
378
+ fields: ["id"],
379
+ filter: { parentId: routeId },
380
+ transaction
381
+ });
382
+ for (const child of children) {
383
+ const childId = normalizeRelationRouteId(readRecordField(child, "id"));
384
+ if (typeof childId !== "undefined") {
385
+ routeIds.push(...await this.collectRouteTreeIds(childId, transaction));
386
+ }
387
+ }
388
+ return routeIds;
389
+ }
390
+ async removeDefaultLayoutRoutePermissions(routeIds, transaction) {
391
+ if (!routeIds.length || !this.db.getCollection("rolesDesktopRoutes")) {
392
+ return;
393
+ }
394
+ await this.db.getRepository("rolesDesktopRoutes").destroy({
395
+ filter: { desktopRouteId: routeIds },
396
+ transaction
397
+ });
398
+ }
399
+ async grantDefaultPortalRouteAccess(portalUid, routeIds, transaction) {
400
+ if (!routeIds.length || !this.db.getCollection("rolesMultiPortalRoutePolicies") || !this.db.getCollection("rolesMultiPortalDesktopRoutes")) {
401
+ return;
402
+ }
403
+ const policies = await this.db.getRepository("rolesMultiPortalRoutePolicies").find({
404
+ fields: ["roleName"],
405
+ filter: {
406
+ multiPortalUid: portalUid,
407
+ allowNewMenu: true
408
+ },
409
+ transaction
410
+ });
411
+ const roleNames = Array.from(
412
+ new Set(
413
+ policies.map((policy) => readStringField(policy, "roleName")).filter((roleName) => !!roleName)
414
+ )
415
+ );
416
+ const repository = this.db.getRepository("rolesMultiPortalDesktopRoutes");
417
+ for (const roleName of roleNames) {
418
+ for (const desktopRouteId of routeIds) {
419
+ await repository.firstOrCreate({
420
+ filterKeys: ["roleName", "multiPortalUid", "desktopRouteId"],
421
+ values: {
422
+ roleName,
423
+ multiPortalUid: portalUid,
424
+ desktopRouteId
425
+ },
426
+ transaction
427
+ });
428
+ }
429
+ }
430
+ }
431
+ }
432
+ // Annotate the CommonJS export names for ESM import in node:
433
+ 0 && (module.exports = {
434
+ DEFAULT_ADMIN_MULTI_PORTAL_UID,
435
+ DEFAULT_ADMIN_UI_LAYOUT_UID,
436
+ DEFAULT_MOBILE_MULTI_PORTAL_UID,
437
+ DEFAULT_MOBILE_UI_LAYOUT_UID,
438
+ FlowSurfaceNavigationTargetsService
439
+ });
@@ -159,6 +159,7 @@ const SURFACE_ALLOWED_MODEL_USES = {
159
159
  };
160
160
  const ALLOWED_CTX_ROOTS = /* @__PURE__ */ new Set([
161
161
  "acl",
162
+ "ai",
162
163
  "antd",
163
164
  "antdIcons",
164
165
  "api",
@@ -54,6 +54,7 @@ export declare class FlowSurfacesService {
54
54
  get repository(): FlowModelRepository;
55
55
  get locator(): SurfaceLocator;
56
56
  private get routeSync();
57
+ private get navigationTargets();
57
58
  private getFlowTemplateRepository;
58
59
  private getFlowTemplateRepositorySafe;
59
60
  private getFlowTemplateUsageRepository;
@@ -93,9 +94,13 @@ export declare class FlowSurfacesService {
93
94
  private normalizeExplicitDesktopRouteLayoutUid;
94
95
  private normalizeDesktopRouteLayoutUidFilter;
95
96
  private resolveDesktopRouteLayoutUidFilter;
97
+ private assertNavigationTargetIsExclusive;
98
+ private readDesktopRouteScope;
99
+ private resolveRequestedDesktopRouteScope;
100
+ private resolveExistingDesktopRouteScope;
101
+ private attachDesktopRouteScopeToRouteAndChildren;
96
102
  private assertEnabledDesktopRouteUiLayoutUid;
97
103
  private assertDesktopRouteBelongsToUiLayout;
98
- private resolveRequestedDesktopRouteUiLayoutUids;
99
104
  private setDesktopRouteUiLayouts;
100
105
  private attachDesktopRouteUiLayoutsToRouteAndChildren;
101
106
  private ensureDesktopRouteUiLayouts;
@@ -223,7 +228,7 @@ export declare class FlowSurfacesService {
223
228
  private resolveApplyBlueprintReplaceTargetInfo;
224
229
  private resolveApplyBlueprintCreateNavigationGroup;
225
230
  private normalizeApplyBlueprintCreateMobileNavigation;
226
- private assertApplyBlueprintCreateNavigationLayout;
231
+ private assertApplyBlueprintCreateNavigationTarget;
227
232
  private resolveApplyBlueprintCreatePageIdentity;
228
233
  private prepareApplyBlueprintRequest;
229
234
  private prevalidateApplyBlueprintChartAssets;
@@ -391,8 +396,13 @@ export declare class FlowSurfacesService {
391
396
  uid: any;
392
397
  updated: string[];
393
398
  }>;
399
+ listNavigationTargets(_values?: Record<string, any>, options?: {
400
+ transaction?: any;
401
+ currentRoles?: FlowSurfaceRequestRoles;
402
+ }): Promise<import("./navigation-targets").FlowSurfaceNavigationTargetsResult>;
394
403
  createMenu(values: Record<string, any>, options?: {
395
404
  transaction?: any;
405
+ currentRoles?: FlowSurfaceRequestRoles;
396
406
  }): Promise<{
397
407
  routeId: any;
398
408
  type: any;
@@ -400,6 +410,7 @@ export declare class FlowSurfacesService {
400
410
  }>;
401
411
  updateMenu(values: Record<string, any>, options?: {
402
412
  transaction?: any;
413
+ currentRoles?: FlowSurfaceRequestRoles;
403
414
  }): Promise<{
404
415
  routeId: any;
405
416
  type: any;
@@ -408,6 +419,7 @@ export declare class FlowSurfacesService {
408
419
  private initializeFlowPageForRoute;
409
420
  createPage(values: Record<string, any>, options?: {
410
421
  transaction?: any;
422
+ currentRoles?: FlowSurfaceRequestRoles;
411
423
  }): Promise<any>;
412
424
  destroyPage(values: Record<string, any>, options?: {
413
425
  transaction?: any;