@dyrected/core 2.15.0 → 2.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{app-Cmp5lFLJ.d.cts → app-CLdT_0se.d.cts} +1342 -1178
- package/dist/{app-Cmp5lFLJ.d.ts → app-CLdT_0se.d.ts} +1342 -1178
- package/dist/index.cjs +758 -1
- package/dist/index.d.cts +133 -3
- package/dist/index.d.ts +133 -3
- package/dist/index.js +739 -1
- package/dist/server.cjs +1052 -24
- package/dist/server.d.cts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +1052 -24
- package/package.json +1 -1
package/dist/server.cjs
CHANGED
|
@@ -6466,6 +6466,134 @@ function isPlainObject2(value) {
|
|
|
6466
6466
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6467
6467
|
}
|
|
6468
6468
|
|
|
6469
|
+
// src/utils/id.ts
|
|
6470
|
+
var import_node_crypto2 = require("crypto");
|
|
6471
|
+
var NANOID_ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-";
|
|
6472
|
+
var BASE62_ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
6473
|
+
var CROCKFORD_BASE32 = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
6474
|
+
var COMMON_SLUG_PREFIXES = {
|
|
6475
|
+
users: "usr",
|
|
6476
|
+
members: "mem",
|
|
6477
|
+
accounts: "acc",
|
|
6478
|
+
applications: "app",
|
|
6479
|
+
customers: "cus",
|
|
6480
|
+
products: "prd",
|
|
6481
|
+
orders: "ord",
|
|
6482
|
+
reports: "rpt",
|
|
6483
|
+
sessions: "ses",
|
|
6484
|
+
transactions: "txn",
|
|
6485
|
+
wallets: "wal",
|
|
6486
|
+
media: "med",
|
|
6487
|
+
files: "fil",
|
|
6488
|
+
posts: "post",
|
|
6489
|
+
pages: "page",
|
|
6490
|
+
tags: "tag",
|
|
6491
|
+
categories: "cat",
|
|
6492
|
+
comments: "com"
|
|
6493
|
+
};
|
|
6494
|
+
function nanoid(size = 21, alphabet = NANOID_ALPHABET) {
|
|
6495
|
+
const mask = (2 << 31 - Math.clz32(alphabet.length - 1 | 1)) - 1;
|
|
6496
|
+
const step = Math.ceil(1.6 * mask * size / alphabet.length);
|
|
6497
|
+
let id = "";
|
|
6498
|
+
while (true) {
|
|
6499
|
+
const bytes = (0, import_node_crypto2.randomBytes)(step);
|
|
6500
|
+
for (let i = 0; i < step; i++) {
|
|
6501
|
+
const byte = bytes[i] & mask;
|
|
6502
|
+
if (alphabet[byte]) {
|
|
6503
|
+
id += alphabet[byte];
|
|
6504
|
+
if (id.length === size) return id;
|
|
6505
|
+
}
|
|
6506
|
+
}
|
|
6507
|
+
}
|
|
6508
|
+
}
|
|
6509
|
+
function encodeUlidTime(now2, len = 10) {
|
|
6510
|
+
let str = "";
|
|
6511
|
+
let time = Math.floor(now2);
|
|
6512
|
+
for (let i = len - 1; i >= 0; i--) {
|
|
6513
|
+
const mod = time % 32;
|
|
6514
|
+
str = CROCKFORD_BASE32[mod] + str;
|
|
6515
|
+
time = (time - mod) / 32;
|
|
6516
|
+
}
|
|
6517
|
+
return str;
|
|
6518
|
+
}
|
|
6519
|
+
function encodeUlidRandom(bytes) {
|
|
6520
|
+
let str = "";
|
|
6521
|
+
let bitBuffer = 0;
|
|
6522
|
+
let bitsInBuffer = 0;
|
|
6523
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
6524
|
+
bitBuffer = bitBuffer << 8 | bytes[i];
|
|
6525
|
+
bitsInBuffer += 8;
|
|
6526
|
+
while (bitsInBuffer >= 5) {
|
|
6527
|
+
bitsInBuffer -= 5;
|
|
6528
|
+
const index = bitBuffer >> bitsInBuffer & 31;
|
|
6529
|
+
str += CROCKFORD_BASE32[index];
|
|
6530
|
+
}
|
|
6531
|
+
}
|
|
6532
|
+
return str;
|
|
6533
|
+
}
|
|
6534
|
+
function ulid(seedTime = Date.now()) {
|
|
6535
|
+
const timePart = encodeUlidTime(seedTime);
|
|
6536
|
+
const randPart = encodeUlidRandom((0, import_node_crypto2.randomBytes)(10));
|
|
6537
|
+
return timePart + randPart;
|
|
6538
|
+
}
|
|
6539
|
+
function uuid() {
|
|
6540
|
+
return (0, import_node_crypto2.randomUUID)();
|
|
6541
|
+
}
|
|
6542
|
+
function resolvePrefix(slug, explicitPrefix) {
|
|
6543
|
+
if (explicitPrefix && typeof explicitPrefix === "string" && explicitPrefix.trim().length > 0) {
|
|
6544
|
+
const cleaned = explicitPrefix.trim().toLowerCase().replace(/[^a-z0-9_]/g, "");
|
|
6545
|
+
if (cleaned.length > 0) return cleaned;
|
|
6546
|
+
}
|
|
6547
|
+
if (!slug || typeof slug !== "string") return "col";
|
|
6548
|
+
const s = slug.trim().toLowerCase();
|
|
6549
|
+
if (COMMON_SLUG_PREFIXES[s]) return COMMON_SLUG_PREFIXES[s];
|
|
6550
|
+
const pieces = s.split(/[-_]/).filter(Boolean);
|
|
6551
|
+
if (pieces.length > 1 && pieces[0].length >= 2) {
|
|
6552
|
+
const first2 = pieces[0].replace(/[^a-z0-9]/g, "");
|
|
6553
|
+
if (first2.length >= 2) return first2.slice(0, 4);
|
|
6554
|
+
}
|
|
6555
|
+
const cleanWord = s.replace(/[^a-z0-9]/g, "");
|
|
6556
|
+
if (cleanWord.length <= 4) return cleanWord || "col";
|
|
6557
|
+
return cleanWord.slice(0, 3) || "col";
|
|
6558
|
+
}
|
|
6559
|
+
function prefixedId(prefix = "col", size = 16) {
|
|
6560
|
+
const cleanPrefix = (prefix || "col").toLowerCase().replace(/[^a-z0-9_]/g, "") || "col";
|
|
6561
|
+
return `${cleanPrefix}_${nanoid(size, BASE62_ALPHABET)}`;
|
|
6562
|
+
}
|
|
6563
|
+
function generateId(options) {
|
|
6564
|
+
if (typeof options === "string") {
|
|
6565
|
+
return prefixedId(resolvePrefix(options));
|
|
6566
|
+
}
|
|
6567
|
+
const opts = options || {};
|
|
6568
|
+
const type = opts.type || "prefixed-nanoid";
|
|
6569
|
+
switch (type) {
|
|
6570
|
+
case "uuid":
|
|
6571
|
+
return uuid();
|
|
6572
|
+
case "ulid":
|
|
6573
|
+
return ulid();
|
|
6574
|
+
case "nanoid":
|
|
6575
|
+
return nanoid(opts.size || 21);
|
|
6576
|
+
case "prefixed-nanoid":
|
|
6577
|
+
default:
|
|
6578
|
+
return prefixedId(opts.prefix || "col", opts.size || 16);
|
|
6579
|
+
}
|
|
6580
|
+
}
|
|
6581
|
+
function generateDocumentId(collectionOrSlug) {
|
|
6582
|
+
if (!collectionOrSlug) {
|
|
6583
|
+
return prefixedId("col");
|
|
6584
|
+
}
|
|
6585
|
+
if (typeof collectionOrSlug === "string") {
|
|
6586
|
+
const prefix2 = resolvePrefix(collectionOrSlug);
|
|
6587
|
+
return prefixedId(prefix2);
|
|
6588
|
+
}
|
|
6589
|
+
if (typeof collectionOrSlug.idGenerator === "function") {
|
|
6590
|
+
return collectionOrSlug.idGenerator(collectionOrSlug.slug);
|
|
6591
|
+
}
|
|
6592
|
+
const type = collectionOrSlug.idType || "prefixed-nanoid";
|
|
6593
|
+
const prefix = resolvePrefix(collectionOrSlug.slug, collectionOrSlug.idPrefix);
|
|
6594
|
+
return generateId({ prefix, type });
|
|
6595
|
+
}
|
|
6596
|
+
|
|
6469
6597
|
// src/workflows.ts
|
|
6470
6598
|
var WORKFLOW_HISTORY_COLLECTION = "__workflow_history";
|
|
6471
6599
|
var LIFECYCLE_EVENTS_COLLECTION = "__lifecycle_events";
|
|
@@ -7434,6 +7562,9 @@ var CollectionController = class {
|
|
|
7434
7562
|
surface: "collection.beforeChange",
|
|
7435
7563
|
path: `collection:${this.collection.slug}.hooks.beforeChange`
|
|
7436
7564
|
});
|
|
7565
|
+
if (!data.id) {
|
|
7566
|
+
data = { ...data, id: generateDocumentId(this.collection) };
|
|
7567
|
+
}
|
|
7437
7568
|
const doc = this.collection.workflow ? (await createWorkflowDocument({
|
|
7438
7569
|
config,
|
|
7439
7570
|
collection: this.collection,
|
|
@@ -7584,6 +7715,9 @@ var CollectionController = class {
|
|
|
7584
7715
|
surface: "collection.beforeChange",
|
|
7585
7716
|
path: `collection:${this.collection.slug}.hooks.beforeChange`
|
|
7586
7717
|
});
|
|
7718
|
+
if (!data.id) {
|
|
7719
|
+
data = { ...data, id: generateDocumentId(this.collection) };
|
|
7720
|
+
}
|
|
7587
7721
|
const doc = await db.create({
|
|
7588
7722
|
collection: this.collection.slug,
|
|
7589
7723
|
data
|
|
@@ -7849,7 +7983,8 @@ var CollectionController = class {
|
|
|
7849
7983
|
}
|
|
7850
7984
|
const body = await c.req.json().catch(() => ({}));
|
|
7851
7985
|
const requestedIds = Array.isArray(body?.ids) ? body.ids.filter((value) => typeof value === "string") : typeof body?.id === "string" ? [body.id] : [];
|
|
7852
|
-
|
|
7986
|
+
const isHeaderAction = action.type === "header";
|
|
7987
|
+
if (!requestedIds.length && !isHeaderAction) {
|
|
7853
7988
|
return c.json(
|
|
7854
7989
|
{ error: true, message: "Provide an `id` or an `ids` array of documents to act on." },
|
|
7855
7990
|
400
|
|
@@ -7877,6 +8012,30 @@ var CollectionController = class {
|
|
|
7877
8012
|
return c.json({ error: true, message: `Access denied: action "${action.name}"` }, 403);
|
|
7878
8013
|
}
|
|
7879
8014
|
}
|
|
8015
|
+
if (isHeaderAction && !requestedIds.length) {
|
|
8016
|
+
if (typeof action.handler === "function") {
|
|
8017
|
+
try {
|
|
8018
|
+
const handlerResult = await action.handler({
|
|
8019
|
+
doc: null,
|
|
8020
|
+
docs: [],
|
|
8021
|
+
user: user ?? null,
|
|
8022
|
+
input,
|
|
8023
|
+
collection: {
|
|
8024
|
+
slug: this.collection.slug,
|
|
8025
|
+
label: this.collection.labels?.singular ?? this.collection.slug
|
|
8026
|
+
}
|
|
8027
|
+
});
|
|
8028
|
+
return c.json(handlerResult ?? { success: true });
|
|
8029
|
+
} catch (error) {
|
|
8030
|
+
const status = typeof error.statusCode === "number" ? error.statusCode : 500;
|
|
8031
|
+
return c.json(
|
|
8032
|
+
{ error: true, message: error instanceof Error ? error.message : String(error) },
|
|
8033
|
+
status
|
|
8034
|
+
);
|
|
8035
|
+
}
|
|
8036
|
+
}
|
|
8037
|
+
return c.json({ success: true });
|
|
8038
|
+
}
|
|
7880
8039
|
const results = [];
|
|
7881
8040
|
for (const id of requestedIds) {
|
|
7882
8041
|
const targetDoc = await db.findOne({ collection: this.collection.slug, id });
|
|
@@ -9285,7 +9444,7 @@ var MediaFolderController = class {
|
|
|
9285
9444
|
};
|
|
9286
9445
|
|
|
9287
9446
|
// src/controllers/auth.controller.ts
|
|
9288
|
-
var
|
|
9447
|
+
var import_node_crypto3 = require("crypto");
|
|
9289
9448
|
|
|
9290
9449
|
// src/auth/lockout.ts
|
|
9291
9450
|
var DEFAULT_MAX_LOGIN_ATTEMPTS = 5;
|
|
@@ -9596,7 +9755,7 @@ var AuthController = class {
|
|
|
9596
9755
|
const data = {
|
|
9597
9756
|
...safeExtraFields,
|
|
9598
9757
|
email,
|
|
9599
|
-
password: await hashPassword((0,
|
|
9758
|
+
password: await hashPassword((0, import_node_crypto3.randomBytes)(32).toString("hex"))
|
|
9600
9759
|
};
|
|
9601
9760
|
if (this.hasField("status")) {
|
|
9602
9761
|
data.status = "pending";
|
|
@@ -10199,7 +10358,7 @@ var AuthController = class {
|
|
|
10199
10358
|
};
|
|
10200
10359
|
|
|
10201
10360
|
// src/controllers/admin-auth.controller.ts
|
|
10202
|
-
var
|
|
10361
|
+
var import_node_crypto4 = require("crypto");
|
|
10203
10362
|
var import_node_util2 = require("util");
|
|
10204
10363
|
var import_jose2 = require("jose");
|
|
10205
10364
|
var AdminAuthController = class {
|
|
@@ -10409,7 +10568,7 @@ var AdminAuthController = class {
|
|
|
10409
10568
|
access.roles,
|
|
10410
10569
|
access.data
|
|
10411
10570
|
),
|
|
10412
|
-
password: await hashPassword((0,
|
|
10571
|
+
password: await hashPassword((0, import_node_crypto4.randomBytes)(32).toString("hex"))
|
|
10413
10572
|
}
|
|
10414
10573
|
});
|
|
10415
10574
|
} else if (user) {
|
|
@@ -10496,7 +10655,7 @@ var AdminAuthController = class {
|
|
|
10496
10655
|
}
|
|
10497
10656
|
async buildOidcStartUrl(provider, returnTo, siteId, origin) {
|
|
10498
10657
|
const discovery = await this.getOidcDiscovery(provider);
|
|
10499
|
-
const nonce = (0,
|
|
10658
|
+
const nonce = (0, import_node_crypto4.randomBytes)(16).toString("hex");
|
|
10500
10659
|
const state = await this.signState({
|
|
10501
10660
|
providerId: provider.id,
|
|
10502
10661
|
returnTo,
|
|
@@ -11057,7 +11216,7 @@ function formatAIErrorMessage(error) {
|
|
|
11057
11216
|
}
|
|
11058
11217
|
return msg;
|
|
11059
11218
|
}
|
|
11060
|
-
function
|
|
11219
|
+
function generateId2() {
|
|
11061
11220
|
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
|
11062
11221
|
}
|
|
11063
11222
|
function buildDyrectedSystemPrompt(context) {
|
|
@@ -11203,7 +11362,7 @@ var AIAgent = class {
|
|
|
11203
11362
|
}
|
|
11204
11363
|
async createThread(title, id) {
|
|
11205
11364
|
const thread = {
|
|
11206
|
-
id: id ||
|
|
11365
|
+
id: id || generateId2(),
|
|
11207
11366
|
projectId: this.projectId,
|
|
11208
11367
|
userId: this.userId,
|
|
11209
11368
|
title: title || "New Conversation",
|
|
@@ -11270,7 +11429,7 @@ var AIAgent = class {
|
|
|
11270
11429
|
}
|
|
11271
11430
|
async persistUserMessage(threadId, content) {
|
|
11272
11431
|
const message = {
|
|
11273
|
-
id:
|
|
11432
|
+
id: generateId2(),
|
|
11274
11433
|
threadId,
|
|
11275
11434
|
role: "user",
|
|
11276
11435
|
content,
|
|
@@ -11286,7 +11445,7 @@ var AIAgent = class {
|
|
|
11286
11445
|
}
|
|
11287
11446
|
async persistAssistantMessage(threadId, content, metadata, parts) {
|
|
11288
11447
|
const message = {
|
|
11289
|
-
id:
|
|
11448
|
+
id: generateId2(),
|
|
11290
11449
|
threadId,
|
|
11291
11450
|
role: "assistant",
|
|
11292
11451
|
content,
|
|
@@ -13670,6 +13829,537 @@ function getSwaggerHtml(specUrl) {
|
|
|
13670
13829
|
`;
|
|
13671
13830
|
}
|
|
13672
13831
|
|
|
13832
|
+
// src/types/navigation.ts
|
|
13833
|
+
var CURRENT_NAV_PREFERENCES_VERSION = 1;
|
|
13834
|
+
var DEFAULT_USER_NAV_PREFERENCES = {
|
|
13835
|
+
_version: CURRENT_NAV_PREFERENCES_VERSION,
|
|
13836
|
+
pinned: [],
|
|
13837
|
+
hidden: [],
|
|
13838
|
+
groupOrder: [],
|
|
13839
|
+
itemOrder: {},
|
|
13840
|
+
groups: [],
|
|
13841
|
+
items: []
|
|
13842
|
+
};
|
|
13843
|
+
|
|
13844
|
+
// src/utils/navigation-reconciler.ts
|
|
13845
|
+
var normalizeKey = (val) => (val || "").toLowerCase().replace(/[^a-z0-9]/g, "-");
|
|
13846
|
+
function reconcileNavigation(baseTree, prefs, schemas, options) {
|
|
13847
|
+
if (!baseTree) {
|
|
13848
|
+
return {
|
|
13849
|
+
groups: [],
|
|
13850
|
+
ungrouped: [],
|
|
13851
|
+
pinnedItems: []
|
|
13852
|
+
};
|
|
13853
|
+
}
|
|
13854
|
+
const includeHidden = options?.includeHidden ?? false;
|
|
13855
|
+
const effectivePrefs = prefs || DEFAULT_USER_NAV_PREFERENCES;
|
|
13856
|
+
const hiddenSet = new Set(effectivePrefs.hidden || []);
|
|
13857
|
+
const knownCollectionSlugs = new Set((schemas?.collections || []).map((c) => c.slug));
|
|
13858
|
+
const knownGlobalSlugs = new Set((schemas?.globals || []).map((g) => g.slug));
|
|
13859
|
+
const groupsList = [];
|
|
13860
|
+
const findGroup = (query) => {
|
|
13861
|
+
const qNorm = normalizeKey(query);
|
|
13862
|
+
return groupsList.find(
|
|
13863
|
+
(g) => g.id === query || g.slug === query || g.name === query || normalizeKey(g.id) === qNorm || normalizeKey(g.slug) === qNorm || normalizeKey(g.name) === qNorm
|
|
13864
|
+
);
|
|
13865
|
+
};
|
|
13866
|
+
for (const g of baseTree.groups || []) {
|
|
13867
|
+
groupsList.push({
|
|
13868
|
+
...g,
|
|
13869
|
+
items: (g.items || []).map((item) => ({ ...item }))
|
|
13870
|
+
});
|
|
13871
|
+
}
|
|
13872
|
+
for (const ug of effectivePrefs.groups || []) {
|
|
13873
|
+
const existing = findGroup(ug.slug || ug.name);
|
|
13874
|
+
if (!existing) {
|
|
13875
|
+
groupsList.push({
|
|
13876
|
+
id: ug.slug ? `group_${ug.slug}` : `group_${normalizeKey(ug.name)}`,
|
|
13877
|
+
name: ug.name,
|
|
13878
|
+
slug: ug.slug || normalizeKey(ug.name),
|
|
13879
|
+
icon: ug.icon || "Folder",
|
|
13880
|
+
defaultExpanded: ug.defaultExpanded ?? true,
|
|
13881
|
+
order: ug.order ?? 100,
|
|
13882
|
+
items: []
|
|
13883
|
+
});
|
|
13884
|
+
}
|
|
13885
|
+
}
|
|
13886
|
+
for (const itemOpt of effectivePrefs.items || []) {
|
|
13887
|
+
const targetGroup = typeof itemOpt.group === "object" ? itemOpt.group?.name : itemOpt.group;
|
|
13888
|
+
const groupKey = targetGroup || "Custom";
|
|
13889
|
+
let group = findGroup(groupKey);
|
|
13890
|
+
if (!group) {
|
|
13891
|
+
group = {
|
|
13892
|
+
id: `group_${normalizeKey(groupKey)}`,
|
|
13893
|
+
name: groupKey,
|
|
13894
|
+
slug: normalizeKey(groupKey),
|
|
13895
|
+
icon: "Folder",
|
|
13896
|
+
defaultExpanded: true,
|
|
13897
|
+
order: 99,
|
|
13898
|
+
items: []
|
|
13899
|
+
};
|
|
13900
|
+
groupsList.push(group);
|
|
13901
|
+
}
|
|
13902
|
+
const itemId = itemOpt.slug ? `workspace_${itemOpt.slug}` : itemOpt.collection ? `collection_${itemOpt.collection}` : `custom_${Math.random()}`;
|
|
13903
|
+
for (const otherGroup of groupsList) {
|
|
13904
|
+
if (otherGroup !== group) {
|
|
13905
|
+
otherGroup.items = otherGroup.items.filter((i) => i.slug !== itemOpt.slug && i.id !== itemId);
|
|
13906
|
+
}
|
|
13907
|
+
}
|
|
13908
|
+
const existingIndex = group.items.findIndex((i) => i.id === itemId || i.slug === itemOpt.slug);
|
|
13909
|
+
const existingItem = existingIndex >= 0 ? group.items[existingIndex] : void 0;
|
|
13910
|
+
const col = schemas?.collections?.find((c) => c.slug === itemOpt.collection);
|
|
13911
|
+
const colViews = col?.views || [];
|
|
13912
|
+
const baseViews = existingItem?.views || [];
|
|
13913
|
+
const userViews = itemOpt.views || [];
|
|
13914
|
+
const userViewSlugs = new Set(userViews.map((v) => v.slug));
|
|
13915
|
+
let mergedViews = [
|
|
13916
|
+
...baseViews.filter((v) => !userViewSlugs.has(v.slug)),
|
|
13917
|
+
...userViews
|
|
13918
|
+
];
|
|
13919
|
+
if (mergedViews.length === 0 && itemOpt.collection) {
|
|
13920
|
+
if (colViews.length > 0) {
|
|
13921
|
+
mergedViews = [...colViews];
|
|
13922
|
+
} else {
|
|
13923
|
+
mergedViews = [
|
|
13924
|
+
{
|
|
13925
|
+
slug: "default",
|
|
13926
|
+
label: col?.label || col?.labels?.plural || itemOpt.label || "All Records",
|
|
13927
|
+
layout: "table",
|
|
13928
|
+
collection: itemOpt.collection
|
|
13929
|
+
}
|
|
13930
|
+
];
|
|
13931
|
+
}
|
|
13932
|
+
}
|
|
13933
|
+
mergedViews = mergedViews.map((v) => ({
|
|
13934
|
+
...v,
|
|
13935
|
+
collection: v.collection || itemOpt.collection || existingItem?.collection
|
|
13936
|
+
}));
|
|
13937
|
+
const compiledItem = {
|
|
13938
|
+
id: itemId,
|
|
13939
|
+
type: itemOpt.slug ? "workspace" : itemOpt.collection ? "collection" : itemOpt.global ? "global" : "workspace",
|
|
13940
|
+
slug: itemOpt.slug || itemOpt.collection || itemOpt.global || "item",
|
|
13941
|
+
label: itemOpt.label || itemOpt.slug || "Item",
|
|
13942
|
+
icon: itemOpt.icon || existingItem?.icon || col?.admin?.icon || "Briefcase",
|
|
13943
|
+
group: group.name,
|
|
13944
|
+
order: itemOpt.order ?? existingItem?.order ?? 100,
|
|
13945
|
+
views: mergedViews,
|
|
13946
|
+
collection: itemOpt.collection || existingItem?.collection,
|
|
13947
|
+
global: itemOpt.global || existingItem?.global,
|
|
13948
|
+
badge: itemOpt.badge || existingItem?.badge,
|
|
13949
|
+
access: itemOpt.access || existingItem?.access
|
|
13950
|
+
};
|
|
13951
|
+
if (existingIndex >= 0) {
|
|
13952
|
+
group.items[existingIndex] = compiledItem;
|
|
13953
|
+
} else {
|
|
13954
|
+
group.items.push(compiledItem);
|
|
13955
|
+
}
|
|
13956
|
+
}
|
|
13957
|
+
const allAvailableItems = [];
|
|
13958
|
+
const reconciledGroups = [];
|
|
13959
|
+
for (const group of groupsList) {
|
|
13960
|
+
const isGroupHidden = hiddenSet.has(group.id) || !!group.slug && hiddenSet.has(group.slug) || hiddenSet.has(group.name);
|
|
13961
|
+
if (!includeHidden && isGroupHidden) {
|
|
13962
|
+
continue;
|
|
13963
|
+
}
|
|
13964
|
+
const visibleItems = [];
|
|
13965
|
+
for (const item of group.items) {
|
|
13966
|
+
const isItemHidden = hiddenSet.has(item.id) || !!item.slug && hiddenSet.has(item.slug);
|
|
13967
|
+
if (!includeHidden && isItemHidden) {
|
|
13968
|
+
continue;
|
|
13969
|
+
}
|
|
13970
|
+
const allViews = item.views || [];
|
|
13971
|
+
const visibleViews = includeHidden ? allViews : allViews.filter((v) => {
|
|
13972
|
+
const compoundKey = `${item.slug}_${v.slug}`;
|
|
13973
|
+
return !hiddenSet.has(compoundKey) && !hiddenSet.has(v.slug);
|
|
13974
|
+
});
|
|
13975
|
+
let isTombstone = false;
|
|
13976
|
+
if (schemas && schemas.collections && schemas.collections.length > 0) {
|
|
13977
|
+
if (item.collection && !knownCollectionSlugs.has(item.collection)) {
|
|
13978
|
+
isTombstone = true;
|
|
13979
|
+
}
|
|
13980
|
+
}
|
|
13981
|
+
if (schemas && schemas.globals && schemas.globals.length > 0) {
|
|
13982
|
+
if (item.global && !knownGlobalSlugs.has(item.global)) {
|
|
13983
|
+
isTombstone = true;
|
|
13984
|
+
}
|
|
13985
|
+
}
|
|
13986
|
+
const processedItem = {
|
|
13987
|
+
...item,
|
|
13988
|
+
views: visibleViews,
|
|
13989
|
+
...isTombstone ? { isTombstone: true } : {}
|
|
13990
|
+
};
|
|
13991
|
+
visibleItems.push(processedItem);
|
|
13992
|
+
allAvailableItems.push(processedItem);
|
|
13993
|
+
}
|
|
13994
|
+
const groupKey = group.slug || group.name;
|
|
13995
|
+
const itemOrderList = effectivePrefs.itemOrder?.[group.id] || effectivePrefs.itemOrder?.[groupKey];
|
|
13996
|
+
if (itemOrderList && itemOrderList.length > 0) {
|
|
13997
|
+
visibleItems.sort((a, b) => {
|
|
13998
|
+
const aIdx = itemOrderList.indexOf(a.id) >= 0 ? itemOrderList.indexOf(a.id) : a.slug ? itemOrderList.indexOf(a.slug) : -1;
|
|
13999
|
+
const bIdx = itemOrderList.indexOf(b.id) >= 0 ? itemOrderList.indexOf(b.id) : b.slug ? itemOrderList.indexOf(b.slug) : -1;
|
|
14000
|
+
if (aIdx >= 0 && bIdx >= 0) return aIdx - bIdx;
|
|
14001
|
+
if (aIdx >= 0) return -1;
|
|
14002
|
+
if (bIdx >= 0) return 1;
|
|
14003
|
+
return (a.order ?? 100) - (b.order ?? 100);
|
|
14004
|
+
});
|
|
14005
|
+
} else {
|
|
14006
|
+
visibleItems.sort((a, b) => (a.order ?? 100) - (b.order ?? 100));
|
|
14007
|
+
}
|
|
14008
|
+
reconciledGroups.push({
|
|
14009
|
+
...group,
|
|
14010
|
+
items: visibleItems
|
|
14011
|
+
});
|
|
14012
|
+
}
|
|
14013
|
+
if (effectivePrefs.groupOrder && effectivePrefs.groupOrder.length > 0) {
|
|
14014
|
+
reconciledGroups.sort((a, b) => {
|
|
14015
|
+
const aIdx = effectivePrefs.groupOrder.indexOf(a.id) >= 0 ? effectivePrefs.groupOrder.indexOf(a.id) : a.slug ? effectivePrefs.groupOrder.indexOf(a.slug) : effectivePrefs.groupOrder.indexOf(a.name);
|
|
14016
|
+
const bIdx = effectivePrefs.groupOrder.indexOf(b.id) >= 0 ? effectivePrefs.groupOrder.indexOf(b.id) : b.slug ? effectivePrefs.groupOrder.indexOf(b.slug) : effectivePrefs.groupOrder.indexOf(b.name);
|
|
14017
|
+
if (aIdx >= 0 && bIdx >= 0) return aIdx - bIdx;
|
|
14018
|
+
if (aIdx >= 0) return -1;
|
|
14019
|
+
if (bIdx >= 0) return 1;
|
|
14020
|
+
return (a.order ?? 100) - (b.order ?? 100);
|
|
14021
|
+
});
|
|
14022
|
+
} else {
|
|
14023
|
+
reconciledGroups.sort((a, b) => (a.order ?? 100) - (b.order ?? 100));
|
|
14024
|
+
}
|
|
14025
|
+
const reconciledUngrouped = (baseTree.ungrouped || []).filter((item) => {
|
|
14026
|
+
const isItemHidden = hiddenSet.has(item.id) || !!item.slug && hiddenSet.has(item.slug);
|
|
14027
|
+
return includeHidden || !isItemHidden;
|
|
14028
|
+
}).map((item) => {
|
|
14029
|
+
const allViews = item.views || [];
|
|
14030
|
+
const visibleViews = includeHidden ? allViews : allViews.filter((v) => {
|
|
14031
|
+
const compoundKey = `${item.slug}_${v.slug}`;
|
|
14032
|
+
return !hiddenSet.has(compoundKey) && !hiddenSet.has(v.slug);
|
|
14033
|
+
});
|
|
14034
|
+
const processed = { ...item, views: visibleViews };
|
|
14035
|
+
allAvailableItems.push(processed);
|
|
14036
|
+
return processed;
|
|
14037
|
+
});
|
|
14038
|
+
const pinnedItems = [];
|
|
14039
|
+
for (const pin of effectivePrefs.pinned || []) {
|
|
14040
|
+
const match = allAvailableItems.find((i) => i.slug === pin.slug || i.id === pin.slug);
|
|
14041
|
+
if (match) {
|
|
14042
|
+
pinnedItems.push({
|
|
14043
|
+
...match,
|
|
14044
|
+
id: `pin_${match.id}`,
|
|
14045
|
+
label: pin.label || match.label,
|
|
14046
|
+
icon: pin.icon || match.icon
|
|
14047
|
+
});
|
|
14048
|
+
} else {
|
|
14049
|
+
pinnedItems.push({
|
|
14050
|
+
id: `pin_${pin.slug}`,
|
|
14051
|
+
type: pin.type,
|
|
14052
|
+
slug: pin.slug,
|
|
14053
|
+
label: pin.label || pin.slug,
|
|
14054
|
+
icon: pin.icon || "Star",
|
|
14055
|
+
order: 0,
|
|
14056
|
+
views: []
|
|
14057
|
+
});
|
|
14058
|
+
}
|
|
14059
|
+
}
|
|
14060
|
+
return {
|
|
14061
|
+
groups: reconciledGroups,
|
|
14062
|
+
ungrouped: reconciledUngrouped,
|
|
14063
|
+
pinnedItems
|
|
14064
|
+
};
|
|
14065
|
+
}
|
|
14066
|
+
|
|
14067
|
+
// src/utils/navigation.ts
|
|
14068
|
+
var RESERVED_NAVIGATION_SLUGS = /* @__PURE__ */ new Set([
|
|
14069
|
+
"collections",
|
|
14070
|
+
"globals",
|
|
14071
|
+
"setup",
|
|
14072
|
+
"api",
|
|
14073
|
+
"login",
|
|
14074
|
+
"logout",
|
|
14075
|
+
"settings",
|
|
14076
|
+
"admin",
|
|
14077
|
+
"preferences",
|
|
14078
|
+
"auth"
|
|
14079
|
+
]);
|
|
14080
|
+
function assertValidNavigationSlugs(navigation) {
|
|
14081
|
+
for (const item of navigation) {
|
|
14082
|
+
if (item.slug) {
|
|
14083
|
+
const normalizedSlug = item.slug.toLowerCase().trim().replace(/^\//, "");
|
|
14084
|
+
if (RESERVED_NAVIGATION_SLUGS.has(normalizedSlug)) {
|
|
14085
|
+
throw new Error(
|
|
14086
|
+
`[Dyrected Config] The slug '${item.slug}' in navigation item '${item.label || item.slug}' is a reserved system path and cannot be used as an operational workspace slug.`
|
|
14087
|
+
);
|
|
14088
|
+
}
|
|
14089
|
+
}
|
|
14090
|
+
}
|
|
14091
|
+
}
|
|
14092
|
+
function resolveGroupMeta(groupProp, defaultGroupName = "Collections") {
|
|
14093
|
+
if (!groupProp) {
|
|
14094
|
+
return { name: defaultGroupName };
|
|
14095
|
+
}
|
|
14096
|
+
if (typeof groupProp === "string") {
|
|
14097
|
+
return { name: groupProp };
|
|
14098
|
+
}
|
|
14099
|
+
return { name: groupProp.name, meta: groupProp };
|
|
14100
|
+
}
|
|
14101
|
+
function compileNavigation(config) {
|
|
14102
|
+
const collections = config.collections || [];
|
|
14103
|
+
const globals = config.globals || [];
|
|
14104
|
+
const explicitNav = config.admin?.navigation || [];
|
|
14105
|
+
assertValidNavigationSlugs(explicitNav);
|
|
14106
|
+
const collectionsBySlug = /* @__PURE__ */ new Map();
|
|
14107
|
+
for (const col of collections) {
|
|
14108
|
+
collectionsBySlug.set(col.slug, col);
|
|
14109
|
+
}
|
|
14110
|
+
const globalsBySlug = /* @__PURE__ */ new Map();
|
|
14111
|
+
for (const gl of globals) {
|
|
14112
|
+
globalsBySlug.set(gl.slug, gl);
|
|
14113
|
+
}
|
|
14114
|
+
const mentionedCollections = /* @__PURE__ */ new Set();
|
|
14115
|
+
const mentionedGlobals = /* @__PURE__ */ new Set();
|
|
14116
|
+
const injectedViewsByCollection = /* @__PURE__ */ new Map();
|
|
14117
|
+
for (const item of explicitNav) {
|
|
14118
|
+
if (item.addToCollection) {
|
|
14119
|
+
const existing = injectedViewsByCollection.get(item.addToCollection) || [];
|
|
14120
|
+
if (item.views && item.views.length > 0) {
|
|
14121
|
+
injectedViewsByCollection.set(item.addToCollection, [...existing, ...item.views]);
|
|
14122
|
+
}
|
|
14123
|
+
}
|
|
14124
|
+
if (item.collection) mentionedCollections.add(item.collection);
|
|
14125
|
+
if (item.global) mentionedGlobals.add(item.global);
|
|
14126
|
+
}
|
|
14127
|
+
const groupMetadataMap = /* @__PURE__ */ new Map();
|
|
14128
|
+
const itemsByGroup = /* @__PURE__ */ new Map();
|
|
14129
|
+
const ungroupedItems = [];
|
|
14130
|
+
const registerItem = (groupName, item) => {
|
|
14131
|
+
if (!groupName) {
|
|
14132
|
+
ungroupedItems.push(item);
|
|
14133
|
+
} else {
|
|
14134
|
+
const list = itemsByGroup.get(groupName) || [];
|
|
14135
|
+
list.push(item);
|
|
14136
|
+
itemsByGroup.set(groupName, list);
|
|
14137
|
+
}
|
|
14138
|
+
};
|
|
14139
|
+
for (const item of explicitNav) {
|
|
14140
|
+
if (item.addToCollection && !item.slug && !item.collection && !item.global && !item.dashboard && !item.href) {
|
|
14141
|
+
continue;
|
|
14142
|
+
}
|
|
14143
|
+
const { name: groupName, meta: groupMeta } = resolveGroupMeta(item.group, void 0);
|
|
14144
|
+
if (groupName && groupMeta) {
|
|
14145
|
+
groupMetadataMap.set(groupName, { ...groupMetadataMap.get(groupName) || {}, ...groupMeta });
|
|
14146
|
+
}
|
|
14147
|
+
if (item.dashboard) {
|
|
14148
|
+
registerItem(groupName, {
|
|
14149
|
+
id: "dashboard",
|
|
14150
|
+
type: "dashboard",
|
|
14151
|
+
slug: "dashboard",
|
|
14152
|
+
label: item.label || "Dashboard",
|
|
14153
|
+
icon: item.icon || "LayoutDashboard",
|
|
14154
|
+
group: groupName,
|
|
14155
|
+
order: item.order ?? 0,
|
|
14156
|
+
views: [],
|
|
14157
|
+
access: item.access
|
|
14158
|
+
});
|
|
14159
|
+
continue;
|
|
14160
|
+
}
|
|
14161
|
+
if (item.collection) {
|
|
14162
|
+
const col = collectionsBySlug.get(item.collection);
|
|
14163
|
+
const combinedViews = [
|
|
14164
|
+
...col?.views || [],
|
|
14165
|
+
...injectedViewsByCollection.get(item.collection) || [],
|
|
14166
|
+
...item.views || []
|
|
14167
|
+
];
|
|
14168
|
+
registerItem(groupName, {
|
|
14169
|
+
id: item.slug || `collection_${item.collection}`,
|
|
14170
|
+
type: item.slug ? "workspace" : "collection",
|
|
14171
|
+
slug: item.slug || item.collection,
|
|
14172
|
+
collection: item.collection,
|
|
14173
|
+
label: item.label || col?.labels?.plural || item.collection,
|
|
14174
|
+
icon: item.icon || col?.admin?.icon || "Folder",
|
|
14175
|
+
group: groupName,
|
|
14176
|
+
order: item.order ?? col?.admin?.order ?? 100,
|
|
14177
|
+
views: combinedViews,
|
|
14178
|
+
badge: item.badge,
|
|
14179
|
+
access: item.access || col?.access?.read
|
|
14180
|
+
});
|
|
14181
|
+
continue;
|
|
14182
|
+
}
|
|
14183
|
+
if (item.global) {
|
|
14184
|
+
const gl = globalsBySlug.get(item.global);
|
|
14185
|
+
registerItem(groupName, {
|
|
14186
|
+
id: item.slug || `global_${item.global}`,
|
|
14187
|
+
type: "global",
|
|
14188
|
+
slug: item.slug || item.global,
|
|
14189
|
+
global: item.global,
|
|
14190
|
+
label: item.label || gl?.label || item.global,
|
|
14191
|
+
icon: item.icon || "Settings",
|
|
14192
|
+
group: groupName,
|
|
14193
|
+
order: item.order ?? 100,
|
|
14194
|
+
views: [],
|
|
14195
|
+
badge: item.badge,
|
|
14196
|
+
access: item.access
|
|
14197
|
+
});
|
|
14198
|
+
continue;
|
|
14199
|
+
}
|
|
14200
|
+
if (item.href) {
|
|
14201
|
+
registerItem(groupName, {
|
|
14202
|
+
id: `link_${item.slug || item.href}`,
|
|
14203
|
+
type: "link",
|
|
14204
|
+
slug: item.slug || "link",
|
|
14205
|
+
label: item.label || "Link",
|
|
14206
|
+
href: item.href,
|
|
14207
|
+
icon: item.icon || "ExternalLink",
|
|
14208
|
+
group: groupName,
|
|
14209
|
+
order: item.order ?? 100,
|
|
14210
|
+
views: [],
|
|
14211
|
+
badge: item.badge,
|
|
14212
|
+
access: item.access
|
|
14213
|
+
});
|
|
14214
|
+
continue;
|
|
14215
|
+
}
|
|
14216
|
+
const workspaceSlug = item.slug || "workspace";
|
|
14217
|
+
registerItem(groupName, {
|
|
14218
|
+
id: `workspace_${workspaceSlug}`,
|
|
14219
|
+
type: "workspace",
|
|
14220
|
+
slug: workspaceSlug,
|
|
14221
|
+
label: item.label || workspaceSlug,
|
|
14222
|
+
icon: item.icon || "Briefcase",
|
|
14223
|
+
group: groupName,
|
|
14224
|
+
order: item.order ?? 100,
|
|
14225
|
+
views: item.views || [],
|
|
14226
|
+
badge: item.badge,
|
|
14227
|
+
access: item.access
|
|
14228
|
+
});
|
|
14229
|
+
}
|
|
14230
|
+
for (const col of collections) {
|
|
14231
|
+
if (mentionedCollections.has(col.slug)) continue;
|
|
14232
|
+
if (col.admin?.hidden) continue;
|
|
14233
|
+
const groupProp = col.admin?.group;
|
|
14234
|
+
const { name: groupName, meta: groupMeta } = resolveGroupMeta(groupProp, "Collections");
|
|
14235
|
+
if (groupMeta) {
|
|
14236
|
+
groupMetadataMap.set(groupName, { ...groupMetadataMap.get(groupName) || {}, ...groupMeta });
|
|
14237
|
+
}
|
|
14238
|
+
const combinedViews = [
|
|
14239
|
+
...col.views || [],
|
|
14240
|
+
...injectedViewsByCollection.get(col.slug) || []
|
|
14241
|
+
];
|
|
14242
|
+
registerItem(groupName, {
|
|
14243
|
+
id: `collection_${col.slug}`,
|
|
14244
|
+
type: "collection",
|
|
14245
|
+
slug: col.slug,
|
|
14246
|
+
collection: col.slug,
|
|
14247
|
+
label: col.labels?.plural || col.slug,
|
|
14248
|
+
icon: col.admin?.icon || "Folder",
|
|
14249
|
+
group: groupName,
|
|
14250
|
+
order: col?.admin?.order ?? 100,
|
|
14251
|
+
views: combinedViews,
|
|
14252
|
+
access: col.access?.read
|
|
14253
|
+
});
|
|
14254
|
+
}
|
|
14255
|
+
for (const gl of globals) {
|
|
14256
|
+
if (mentionedGlobals.has(gl.slug)) continue;
|
|
14257
|
+
const groupName = "Configuration";
|
|
14258
|
+
registerItem(groupName, {
|
|
14259
|
+
id: `global_${gl.slug}`,
|
|
14260
|
+
type: "global",
|
|
14261
|
+
slug: gl.slug,
|
|
14262
|
+
global: gl.slug,
|
|
14263
|
+
label: gl.label || gl.slug,
|
|
14264
|
+
icon: "Settings",
|
|
14265
|
+
group: groupName,
|
|
14266
|
+
order: 100,
|
|
14267
|
+
views: []
|
|
14268
|
+
});
|
|
14269
|
+
}
|
|
14270
|
+
const sortAndSpliceItems = (items) => {
|
|
14271
|
+
const sorted = [...items].sort((a, b) => a.order - b.order);
|
|
14272
|
+
const explicitMap = /* @__PURE__ */ new Map();
|
|
14273
|
+
for (const opt of explicitNav) {
|
|
14274
|
+
if (opt.slug) explicitMap.set(opt.slug, opt);
|
|
14275
|
+
if (opt.collection) explicitMap.set(opt.collection, opt);
|
|
14276
|
+
if (opt.global) explicitMap.set(opt.global, opt);
|
|
14277
|
+
}
|
|
14278
|
+
for (const opt of explicitNav) {
|
|
14279
|
+
const itemKey = opt.slug || opt.collection || opt.global;
|
|
14280
|
+
if (!itemKey) continue;
|
|
14281
|
+
if (opt.after) {
|
|
14282
|
+
const itemIdx = sorted.findIndex((i) => i.slug === itemKey);
|
|
14283
|
+
const targetIdx = sorted.findIndex((i) => i.slug === opt.after);
|
|
14284
|
+
if (itemIdx !== -1 && targetIdx !== -1 && itemIdx !== targetIdx) {
|
|
14285
|
+
const [moved] = sorted.splice(itemIdx, 1);
|
|
14286
|
+
const newTargetIdx = sorted.findIndex((i) => i.slug === opt.after);
|
|
14287
|
+
sorted.splice(newTargetIdx + 1, 0, moved);
|
|
14288
|
+
}
|
|
14289
|
+
} else if (opt.before) {
|
|
14290
|
+
const itemIdx = sorted.findIndex((i) => i.slug === itemKey);
|
|
14291
|
+
const targetIdx = sorted.findIndex((i) => i.slug === opt.before);
|
|
14292
|
+
if (itemIdx !== -1 && targetIdx !== -1 && itemIdx !== targetIdx) {
|
|
14293
|
+
const [moved] = sorted.splice(itemIdx, 1);
|
|
14294
|
+
const newTargetIdx = sorted.findIndex((i) => i.slug === opt.before);
|
|
14295
|
+
sorted.splice(newTargetIdx, 0, moved);
|
|
14296
|
+
}
|
|
14297
|
+
} else if (opt.position === "first") {
|
|
14298
|
+
const itemIdx = sorted.findIndex((i) => i.slug === itemKey);
|
|
14299
|
+
if (itemIdx > 0) {
|
|
14300
|
+
const [moved] = sorted.splice(itemIdx, 1);
|
|
14301
|
+
sorted.unshift(moved);
|
|
14302
|
+
}
|
|
14303
|
+
} else if (opt.position === "last") {
|
|
14304
|
+
const itemIdx = sorted.findIndex((i) => i.slug === itemKey);
|
|
14305
|
+
if (itemIdx !== -1 && itemIdx < sorted.length - 1) {
|
|
14306
|
+
const [moved] = sorted.splice(itemIdx, 1);
|
|
14307
|
+
sorted.push(moved);
|
|
14308
|
+
}
|
|
14309
|
+
}
|
|
14310
|
+
}
|
|
14311
|
+
return sorted;
|
|
14312
|
+
};
|
|
14313
|
+
const compiledGroups = [];
|
|
14314
|
+
for (const [groupName, rawItems] of itemsByGroup.entries()) {
|
|
14315
|
+
const meta = groupMetadataMap.get(groupName);
|
|
14316
|
+
const sortedItems = sortAndSpliceItems(rawItems);
|
|
14317
|
+
compiledGroups.push({
|
|
14318
|
+
id: `group_${groupName.toLowerCase().replace(/\s+/g, "_")}`,
|
|
14319
|
+
name: groupName,
|
|
14320
|
+
slug: meta?.slug || groupName.toLowerCase().replace(/\s+/g, "-"),
|
|
14321
|
+
icon: meta?.icon,
|
|
14322
|
+
defaultExpanded: meta?.defaultExpanded ?? true,
|
|
14323
|
+
order: meta?.order ?? 100,
|
|
14324
|
+
items: sortedItems
|
|
14325
|
+
});
|
|
14326
|
+
}
|
|
14327
|
+
compiledGroups.sort((a, b) => a.order - b.order);
|
|
14328
|
+
return {
|
|
14329
|
+
groups: compiledGroups,
|
|
14330
|
+
ungrouped: sortAndSpliceItems(ungroupedItems)
|
|
14331
|
+
};
|
|
14332
|
+
}
|
|
14333
|
+
function pruneNavigationForUser(tree, user) {
|
|
14334
|
+
const userRoles = /* @__PURE__ */ new Set();
|
|
14335
|
+
if (user?.role) userRoles.add(user.role);
|
|
14336
|
+
if (Array.isArray(user?.roles)) {
|
|
14337
|
+
for (const r of user.roles) userRoles.add(r);
|
|
14338
|
+
}
|
|
14339
|
+
const isAllowed = (item) => {
|
|
14340
|
+
if (!item.access) return true;
|
|
14341
|
+
if (Array.isArray(item.access)) {
|
|
14342
|
+
if (item.access.length === 0) return true;
|
|
14343
|
+
return item.access.some((role) => userRoles.has(role));
|
|
14344
|
+
}
|
|
14345
|
+
return true;
|
|
14346
|
+
};
|
|
14347
|
+
const prunedGroups = [];
|
|
14348
|
+
for (const group of tree.groups) {
|
|
14349
|
+
const visibleItems = group.items.filter(isAllowed);
|
|
14350
|
+
if (visibleItems.length > 0) {
|
|
14351
|
+
prunedGroups.push({
|
|
14352
|
+
...group,
|
|
14353
|
+
items: visibleItems
|
|
14354
|
+
});
|
|
14355
|
+
}
|
|
14356
|
+
}
|
|
14357
|
+
return {
|
|
14358
|
+
groups: prunedGroups,
|
|
14359
|
+
ungrouped: tree.ungrouped.filter(isAllowed)
|
|
14360
|
+
};
|
|
14361
|
+
}
|
|
14362
|
+
|
|
13673
14363
|
// src/router.ts
|
|
13674
14364
|
init_access_control();
|
|
13675
14365
|
var import_http_exception5 = require("hono/http-exception");
|
|
@@ -14169,6 +14859,7 @@ function registerRoutes(app, config) {
|
|
|
14169
14859
|
const user = c.get("user");
|
|
14170
14860
|
const key = c.req.param("key");
|
|
14171
14861
|
const scope = c.req.query("scope");
|
|
14862
|
+
const roleParam = c.req.query("role");
|
|
14172
14863
|
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
14173
14864
|
if (!key) return c.json({ error: true, message: "Preference key is required." }, 400);
|
|
14174
14865
|
const getGlobalPreference = async () => {
|
|
@@ -14178,27 +14869,61 @@ function registerRoutes(app, config) {
|
|
|
14178
14869
|
});
|
|
14179
14870
|
return globalDoc ? globalDoc.value : null;
|
|
14180
14871
|
};
|
|
14181
|
-
|
|
14872
|
+
const getRolePreference = async (r) => {
|
|
14873
|
+
const roleDoc = await db.findOne({
|
|
14874
|
+
collection: "__role_preferences",
|
|
14875
|
+
id: `${r}_${key}`
|
|
14876
|
+
});
|
|
14877
|
+
return roleDoc ? roleDoc.value : null;
|
|
14878
|
+
};
|
|
14879
|
+
const getUserPreferences = async () => {
|
|
14880
|
+
if (!user?.collection || !user.sub) return null;
|
|
14881
|
+
const doc = await db.findOne({ collection: user.collection, id: user.sub });
|
|
14882
|
+
if (!doc) return null;
|
|
14883
|
+
return typeof doc.__preferences === "object" && doc.__preferences !== null ? doc.__preferences : {};
|
|
14884
|
+
};
|
|
14885
|
+
if (scope === "global") {
|
|
14182
14886
|
const globalValue2 = await getGlobalPreference();
|
|
14183
14887
|
return c.json({ key, value: globalValue2 });
|
|
14184
14888
|
}
|
|
14185
|
-
|
|
14186
|
-
|
|
14187
|
-
|
|
14188
|
-
|
|
14889
|
+
if (scope === "role") {
|
|
14890
|
+
if (roleParam) {
|
|
14891
|
+
const val = await getRolePreference(roleParam);
|
|
14892
|
+
return c.json({ key, value: val, role: roleParam });
|
|
14893
|
+
}
|
|
14894
|
+
const userRoles2 = Array.isArray(user?.roles) ? user.roles : typeof user?.role === "string" ? [user.role] : [];
|
|
14895
|
+
for (const r of userRoles2) {
|
|
14896
|
+
const val = await getRolePreference(r);
|
|
14897
|
+
if (val !== null && val !== void 0) {
|
|
14898
|
+
return c.json({ key, value: val, role: r });
|
|
14899
|
+
}
|
|
14900
|
+
}
|
|
14901
|
+
return c.json({ key, value: null });
|
|
14189
14902
|
}
|
|
14190
|
-
|
|
14191
|
-
|
|
14192
|
-
return c.json({ key, value:
|
|
14903
|
+
if (scope === "personal") {
|
|
14904
|
+
const prefs2 = await getUserPreferences();
|
|
14905
|
+
return c.json({ key, value: prefs2 && key in prefs2 ? prefs2[key] ?? null : null });
|
|
14906
|
+
}
|
|
14907
|
+
const prefs = await getUserPreferences();
|
|
14908
|
+
if (prefs && key in prefs && prefs[key] !== null && prefs[key] !== void 0) {
|
|
14909
|
+
return c.json({ key, value: prefs[key] });
|
|
14910
|
+
}
|
|
14911
|
+
const userRoles = Array.isArray(user?.roles) ? user.roles : typeof user?.role === "string" ? [user.role] : [];
|
|
14912
|
+
for (const r of userRoles) {
|
|
14913
|
+
const val = await getRolePreference(r);
|
|
14914
|
+
if (val !== null && val !== void 0) {
|
|
14915
|
+
return c.json({ key, value: val });
|
|
14916
|
+
}
|
|
14193
14917
|
}
|
|
14194
14918
|
const globalValue = await getGlobalPreference();
|
|
14195
|
-
return c.json({ key, value: globalValue });
|
|
14919
|
+
return c.json({ key, value: globalValue ?? null });
|
|
14196
14920
|
});
|
|
14197
14921
|
app.put("/api/preferences/:key", requireAuth(config), async (c) => {
|
|
14198
14922
|
const db = config.db;
|
|
14199
14923
|
const user = c.get("user");
|
|
14200
14924
|
const key = c.req.param("key");
|
|
14201
|
-
const scope = c.req.query("scope");
|
|
14925
|
+
const scope = c.req.query("scope") || "personal";
|
|
14926
|
+
const roleParam = c.req.query("role");
|
|
14202
14927
|
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
14203
14928
|
if (!user?.collection || !user.sub) return c.json({ error: true, message: "Authentication required." }, 401);
|
|
14204
14929
|
if (!key) return c.json({ error: true, message: "Preference key is required." }, 400);
|
|
@@ -14231,7 +14956,47 @@ function registerRoutes(app, config) {
|
|
|
14231
14956
|
data: { id: key, value: body.value }
|
|
14232
14957
|
});
|
|
14233
14958
|
}
|
|
14234
|
-
return c.json({ key, value: body.value });
|
|
14959
|
+
return c.json({ key, value: body.value, scope: "global" });
|
|
14960
|
+
}
|
|
14961
|
+
if (scope === "role") {
|
|
14962
|
+
const userCol = config.collections?.find((col) => col.slug === user?.collection);
|
|
14963
|
+
const isAdminUser = isUserAdmin(user, userCol);
|
|
14964
|
+
if (!isAdminUser) {
|
|
14965
|
+
return c.json(
|
|
14966
|
+
{
|
|
14967
|
+
error: true,
|
|
14968
|
+
message: "Only administrators can save role preferences."
|
|
14969
|
+
},
|
|
14970
|
+
403
|
|
14971
|
+
);
|
|
14972
|
+
}
|
|
14973
|
+
if (!roleParam) {
|
|
14974
|
+
return c.json(
|
|
14975
|
+
{
|
|
14976
|
+
error: true,
|
|
14977
|
+
message: "Role query parameter is required for role-scoped preferences."
|
|
14978
|
+
},
|
|
14979
|
+
400
|
|
14980
|
+
);
|
|
14981
|
+
}
|
|
14982
|
+
const roleDocId = `${roleParam}_${key}`;
|
|
14983
|
+
const existing = await db.findOne({
|
|
14984
|
+
collection: "__role_preferences",
|
|
14985
|
+
id: roleDocId
|
|
14986
|
+
});
|
|
14987
|
+
if (existing) {
|
|
14988
|
+
await db.update({
|
|
14989
|
+
collection: "__role_preferences",
|
|
14990
|
+
id: roleDocId,
|
|
14991
|
+
data: { value: body.value, role: roleParam, key }
|
|
14992
|
+
});
|
|
14993
|
+
} else {
|
|
14994
|
+
await db.create({
|
|
14995
|
+
collection: "__role_preferences",
|
|
14996
|
+
data: { id: roleDocId, role: roleParam, key, value: body.value }
|
|
14997
|
+
});
|
|
14998
|
+
}
|
|
14999
|
+
return c.json({ key, value: body.value, role: roleParam, scope: "role" });
|
|
14235
15000
|
}
|
|
14236
15001
|
const doc = await db.findOne({ collection: user.collection, id: user.sub });
|
|
14237
15002
|
if (!doc) return c.json({ error: true, message: "User not found." }, 404);
|
|
@@ -14242,13 +15007,14 @@ function registerRoutes(app, config) {
|
|
|
14242
15007
|
id: user.sub,
|
|
14243
15008
|
data: { __preferences: nextPreferences }
|
|
14244
15009
|
});
|
|
14245
|
-
return c.json({ key, value: body.value });
|
|
15010
|
+
return c.json({ key, value: body.value, scope: "personal" });
|
|
14246
15011
|
});
|
|
14247
15012
|
app.delete("/api/preferences/:key", requireAuth(config), async (c) => {
|
|
14248
15013
|
const db = config.db;
|
|
14249
15014
|
const user = c.get("user");
|
|
14250
15015
|
const key = c.req.param("key");
|
|
14251
|
-
const scope = c.req.query("scope");
|
|
15016
|
+
const scope = c.req.query("scope") || "personal";
|
|
15017
|
+
const roleParam = c.req.query("role");
|
|
14252
15018
|
if (!db) return c.json({ message: "Database not configured" }, 500);
|
|
14253
15019
|
if (!user?.collection || !user.sub) return c.json({ error: true, message: "Authentication required." }, 401);
|
|
14254
15020
|
if (!key) return c.json({ error: true, message: "Preference key is required." }, 400);
|
|
@@ -14267,6 +15033,30 @@ function registerRoutes(app, config) {
|
|
|
14267
15033
|
await db.delete({ collection: "__global_preferences", id: key });
|
|
14268
15034
|
return c.json({ success: true });
|
|
14269
15035
|
}
|
|
15036
|
+
if (scope === "role") {
|
|
15037
|
+
const userCol = config.collections?.find((col) => col.slug === user?.collection);
|
|
15038
|
+
const isAdminUser = isUserAdmin(user, userCol);
|
|
15039
|
+
if (!isAdminUser) {
|
|
15040
|
+
return c.json(
|
|
15041
|
+
{
|
|
15042
|
+
error: true,
|
|
15043
|
+
message: "Only administrators can delete role preferences."
|
|
15044
|
+
},
|
|
15045
|
+
403
|
|
15046
|
+
);
|
|
15047
|
+
}
|
|
15048
|
+
if (!roleParam) {
|
|
15049
|
+
return c.json(
|
|
15050
|
+
{
|
|
15051
|
+
error: true,
|
|
15052
|
+
message: "Role query parameter is required for role-scoped preferences."
|
|
15053
|
+
},
|
|
15054
|
+
400
|
|
15055
|
+
);
|
|
15056
|
+
}
|
|
15057
|
+
await db.delete({ collection: "__role_preferences", id: `${roleParam}_${key}` });
|
|
15058
|
+
return c.json({ success: true });
|
|
15059
|
+
}
|
|
14270
15060
|
const doc = await db.findOne({ collection: user.collection, id: user.sub });
|
|
14271
15061
|
if (!doc) return c.json({ error: true, message: "User not found." }, 404);
|
|
14272
15062
|
const preferences = typeof doc.__preferences === "object" && doc.__preferences !== null ? { ...doc.__preferences } : {};
|
|
@@ -14278,6 +15068,198 @@ function registerRoutes(app, config) {
|
|
|
14278
15068
|
});
|
|
14279
15069
|
return c.json({ success: true });
|
|
14280
15070
|
});
|
|
15071
|
+
app.get("/api/admin/navigation", optionalAuth(config), async (c) => {
|
|
15072
|
+
const user = c.get("user");
|
|
15073
|
+
const compiled = compileNavigation(config);
|
|
15074
|
+
const pruned = pruneNavigationForUser(compiled, user);
|
|
15075
|
+
return c.json(pruned);
|
|
15076
|
+
});
|
|
15077
|
+
app.on(["GET", "POST"], "/api/admin/navigation/badges", optionalAuth(config), async (c) => {
|
|
15078
|
+
const db = config.db;
|
|
15079
|
+
if (!db) return c.json({ badges: {} });
|
|
15080
|
+
const user = c.get("user");
|
|
15081
|
+
const compiled = compileNavigation(config);
|
|
15082
|
+
let userNavPrefs = null;
|
|
15083
|
+
const prefsQuery = c.req.query("prefs");
|
|
15084
|
+
if (prefsQuery) {
|
|
15085
|
+
try {
|
|
15086
|
+
userNavPrefs = JSON.parse(decodeURIComponent(prefsQuery));
|
|
15087
|
+
} catch {
|
|
15088
|
+
}
|
|
15089
|
+
}
|
|
15090
|
+
if (!userNavPrefs && c.req.method === "POST") {
|
|
15091
|
+
try {
|
|
15092
|
+
const body = await c.req.json();
|
|
15093
|
+
if (body?.preferences) userNavPrefs = body.preferences;
|
|
15094
|
+
} catch {
|
|
15095
|
+
}
|
|
15096
|
+
}
|
|
15097
|
+
if (!userNavPrefs && user?.collection && user?.sub) {
|
|
15098
|
+
try {
|
|
15099
|
+
const userDoc = await db.findOne({ collection: user.collection, id: user.sub });
|
|
15100
|
+
if (userDoc?.__preferences && typeof userDoc.__preferences === "object") {
|
|
15101
|
+
userNavPrefs = userDoc.__preferences["admin:navigation"];
|
|
15102
|
+
}
|
|
15103
|
+
} catch {
|
|
15104
|
+
}
|
|
15105
|
+
}
|
|
15106
|
+
if (!userNavPrefs) {
|
|
15107
|
+
try {
|
|
15108
|
+
const globalDoc = await db.findOne({
|
|
15109
|
+
collection: "__global_preferences",
|
|
15110
|
+
id: "admin:navigation"
|
|
15111
|
+
});
|
|
15112
|
+
if (globalDoc?.value) {
|
|
15113
|
+
userNavPrefs = globalDoc.value;
|
|
15114
|
+
}
|
|
15115
|
+
} catch {
|
|
15116
|
+
}
|
|
15117
|
+
}
|
|
15118
|
+
let allItems;
|
|
15119
|
+
if (userNavPrefs) {
|
|
15120
|
+
const reconciled = reconcileNavigation(compiled, userNavPrefs, {
|
|
15121
|
+
collections: config.collections,
|
|
15122
|
+
globals: config.globals
|
|
15123
|
+
});
|
|
15124
|
+
allItems = [
|
|
15125
|
+
...reconciled.ungrouped || [],
|
|
15126
|
+
...reconciled.pinnedItems || [],
|
|
15127
|
+
...(reconciled.groups || []).flatMap((g) => g.items || [])
|
|
15128
|
+
];
|
|
15129
|
+
} else {
|
|
15130
|
+
const pruned = pruneNavigationForUser(compiled, user);
|
|
15131
|
+
allItems = [
|
|
15132
|
+
...pruned.ungrouped,
|
|
15133
|
+
...pruned.groups.flatMap((g) => g.items)
|
|
15134
|
+
];
|
|
15135
|
+
}
|
|
15136
|
+
const badges = {};
|
|
15137
|
+
const requestsByCollection = /* @__PURE__ */ new Map();
|
|
15138
|
+
let reqCounter = 0;
|
|
15139
|
+
for (const item of allItems) {
|
|
15140
|
+
if (item.badge) {
|
|
15141
|
+
const itemBadge = item.badge;
|
|
15142
|
+
const badgeKey = item.slug || item.collection || item.global || item.id;
|
|
15143
|
+
if (typeof itemBadge === "string") {
|
|
15144
|
+
badges[badgeKey] = { count: itemBadge, variant: "default" };
|
|
15145
|
+
} else {
|
|
15146
|
+
const badgeConfig = itemBadge;
|
|
15147
|
+
const variant = badgeConfig.variant ?? "default";
|
|
15148
|
+
if (badgeConfig.text) {
|
|
15149
|
+
badges[badgeKey] = { count: badgeConfig.text, variant };
|
|
15150
|
+
} else {
|
|
15151
|
+
let targetCol;
|
|
15152
|
+
let targetWhere;
|
|
15153
|
+
if (badgeConfig.aggregate) {
|
|
15154
|
+
targetCol = badgeConfig.aggregate.collection;
|
|
15155
|
+
targetWhere = badgeConfig.aggregate.where;
|
|
15156
|
+
} else if (badgeConfig.count) {
|
|
15157
|
+
targetCol = item.collection || item.views?.[0]?.collection;
|
|
15158
|
+
const primaryView = item.views?.[0];
|
|
15159
|
+
if (primaryView?.filter) {
|
|
15160
|
+
targetWhere = primaryView.filter;
|
|
15161
|
+
}
|
|
15162
|
+
}
|
|
15163
|
+
if (targetCol) {
|
|
15164
|
+
const reqId = `agg_${reqCounter++}`;
|
|
15165
|
+
const list = requestsByCollection.get(targetCol) || [];
|
|
15166
|
+
list.push({
|
|
15167
|
+
id: reqId,
|
|
15168
|
+
where: targetWhere,
|
|
15169
|
+
onResult: (count2) => {
|
|
15170
|
+
badges[badgeKey] = { count: count2, variant };
|
|
15171
|
+
}
|
|
15172
|
+
});
|
|
15173
|
+
requestsByCollection.set(targetCol, list);
|
|
15174
|
+
}
|
|
15175
|
+
}
|
|
15176
|
+
}
|
|
15177
|
+
}
|
|
15178
|
+
if (item.views && item.views.length > 0) {
|
|
15179
|
+
for (const view of item.views) {
|
|
15180
|
+
if (!view.badge) continue;
|
|
15181
|
+
const viewBadge = view.badge;
|
|
15182
|
+
const viewKey = `${item.slug}:${view.slug}`;
|
|
15183
|
+
const altKey = `${item.slug}_${view.slug}`;
|
|
15184
|
+
const plainKey = view.slug;
|
|
15185
|
+
const setBadgeResult = (res) => {
|
|
15186
|
+
badges[viewKey] = res;
|
|
15187
|
+
badges[altKey] = res;
|
|
15188
|
+
if (!badges[plainKey]) {
|
|
15189
|
+
badges[plainKey] = res;
|
|
15190
|
+
}
|
|
15191
|
+
if (view.collection) {
|
|
15192
|
+
badges[`${view.collection}:${view.slug}`] = res;
|
|
15193
|
+
badges[`${view.collection}_${view.slug}`] = res;
|
|
15194
|
+
}
|
|
15195
|
+
};
|
|
15196
|
+
if (typeof viewBadge === "string") {
|
|
15197
|
+
setBadgeResult({ count: viewBadge, variant: "default" });
|
|
15198
|
+
continue;
|
|
15199
|
+
}
|
|
15200
|
+
const badgeConfig = viewBadge;
|
|
15201
|
+
const variant = badgeConfig.variant ?? "default";
|
|
15202
|
+
if (badgeConfig.text) {
|
|
15203
|
+
setBadgeResult({ count: badgeConfig.text, variant });
|
|
15204
|
+
continue;
|
|
15205
|
+
}
|
|
15206
|
+
const targetCol = badgeConfig.aggregate?.collection || view.collection || item.collection || (item.type === "collection" ? item.slug : void 0);
|
|
15207
|
+
const targetWhere = badgeConfig.aggregate?.where || (typeof view.filter === "object" ? view.filter : void 0);
|
|
15208
|
+
if (!targetCol) continue;
|
|
15209
|
+
const reqId = `agg_${reqCounter++}`;
|
|
15210
|
+
const list = requestsByCollection.get(targetCol) || [];
|
|
15211
|
+
list.push({
|
|
15212
|
+
id: reqId,
|
|
15213
|
+
where: targetWhere,
|
|
15214
|
+
onResult: (count2) => {
|
|
15215
|
+
setBadgeResult({ count: count2, variant });
|
|
15216
|
+
}
|
|
15217
|
+
});
|
|
15218
|
+
requestsByCollection.set(targetCol, list);
|
|
15219
|
+
}
|
|
15220
|
+
}
|
|
15221
|
+
}
|
|
15222
|
+
const collectionTasks = Array.from(requestsByCollection.entries()).map(async ([col, reqs]) => {
|
|
15223
|
+
if (typeof db.aggregate === "function") {
|
|
15224
|
+
try {
|
|
15225
|
+
const aggregates = {};
|
|
15226
|
+
for (const req of reqs) {
|
|
15227
|
+
aggregates[req.id] = { count: "*", where: req.where };
|
|
15228
|
+
}
|
|
15229
|
+
const agg = await db.aggregate({
|
|
15230
|
+
collection: col,
|
|
15231
|
+
aggregates
|
|
15232
|
+
});
|
|
15233
|
+
for (const req of reqs) {
|
|
15234
|
+
const val = agg?.[req.id];
|
|
15235
|
+
req.onResult(typeof val === "number" ? val : 0);
|
|
15236
|
+
}
|
|
15237
|
+
} catch {
|
|
15238
|
+
for (const req of reqs) {
|
|
15239
|
+
req.onResult(0);
|
|
15240
|
+
}
|
|
15241
|
+
}
|
|
15242
|
+
} else {
|
|
15243
|
+
await Promise.allSettled(
|
|
15244
|
+
reqs.map(async (req) => {
|
|
15245
|
+
try {
|
|
15246
|
+
const res = await db.find({
|
|
15247
|
+
collection: col,
|
|
15248
|
+
where: req.where,
|
|
15249
|
+
limit: 1
|
|
15250
|
+
});
|
|
15251
|
+
const total = res?.totalDocs ?? res?.total ?? 0;
|
|
15252
|
+
req.onResult(total);
|
|
15253
|
+
} catch {
|
|
15254
|
+
req.onResult(0);
|
|
15255
|
+
}
|
|
15256
|
+
})
|
|
15257
|
+
);
|
|
15258
|
+
}
|
|
15259
|
+
});
|
|
15260
|
+
await Promise.allSettled(collectionTasks);
|
|
15261
|
+
return c.json({ badges });
|
|
15262
|
+
});
|
|
14281
15263
|
app.get("/api/media/folders", async (c) => {
|
|
14282
15264
|
const folderController = new MediaFolderController("media");
|
|
14283
15265
|
return folderController.list(c);
|
|
@@ -14757,7 +15739,33 @@ function normalizeConfig(config) {
|
|
|
14757
15739
|
}
|
|
14758
15740
|
];
|
|
14759
15741
|
}
|
|
15742
|
+
if (!existingFieldNames.has("__preferences")) {
|
|
15743
|
+
fields = [
|
|
15744
|
+
...fields,
|
|
15745
|
+
{
|
|
15746
|
+
name: "__preferences",
|
|
15747
|
+
type: "json",
|
|
15748
|
+
label: "Preferences",
|
|
15749
|
+
promoted: true,
|
|
15750
|
+
admin: {
|
|
15751
|
+
hidden: true,
|
|
15752
|
+
readOnly: true
|
|
15753
|
+
}
|
|
15754
|
+
}
|
|
15755
|
+
];
|
|
15756
|
+
}
|
|
14760
15757
|
fields = fields.map((field) => {
|
|
15758
|
+
if (field.name === "__preferences") {
|
|
15759
|
+
return {
|
|
15760
|
+
...field,
|
|
15761
|
+
promoted: true,
|
|
15762
|
+
admin: {
|
|
15763
|
+
...field.admin || {},
|
|
15764
|
+
hidden: true,
|
|
15765
|
+
readOnly: true
|
|
15766
|
+
}
|
|
15767
|
+
};
|
|
15768
|
+
}
|
|
14761
15769
|
if (field.name === "email") {
|
|
14762
15770
|
return {
|
|
14763
15771
|
...field,
|
|
@@ -14848,11 +15856,31 @@ function normalizeConfig(config) {
|
|
|
14848
15856
|
}
|
|
14849
15857
|
const updatedFieldNames = new Set(fields.map((f) => f.name));
|
|
14850
15858
|
const fieldsToInject = SYSTEM_FIELDS.filter((f) => !updatedFieldNames.has(f.name));
|
|
15859
|
+
const indexedFieldNames = /* @__PURE__ */ new Set();
|
|
15860
|
+
if (col.indexes) {
|
|
15861
|
+
for (const idx of col.indexes) {
|
|
15862
|
+
if (Array.isArray(idx.fields)) {
|
|
15863
|
+
for (const f of idx.fields) {
|
|
15864
|
+
indexedFieldNames.add(f);
|
|
15865
|
+
}
|
|
15866
|
+
}
|
|
15867
|
+
}
|
|
15868
|
+
}
|
|
15869
|
+
const allFields = [...fields, ...fieldsToInject].map((field) => {
|
|
15870
|
+
if (field.unique || field.name && indexedFieldNames.has(field.name)) {
|
|
15871
|
+
return { ...field, promoted: true };
|
|
15872
|
+
}
|
|
15873
|
+
return field;
|
|
15874
|
+
});
|
|
14851
15875
|
const workflow = col.workflow || (col.drafts ? simplePublishingWorkflow() : void 0);
|
|
15876
|
+
const idPrefix = col.idPrefix || resolvePrefix(col.slug);
|
|
15877
|
+
const idType = col.idType || "prefixed-nanoid";
|
|
14852
15878
|
return {
|
|
14853
15879
|
...col,
|
|
15880
|
+
idPrefix,
|
|
15881
|
+
idType,
|
|
14854
15882
|
workflow,
|
|
14855
|
-
fields:
|
|
15883
|
+
fields: allFields
|
|
14856
15884
|
};
|
|
14857
15885
|
});
|
|
14858
15886
|
const hasAuditCollection = normalizedCollections.some((col) => col.slug === AUDIT_COLLECTION_SLUG);
|