@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/index.cjs
CHANGED
|
@@ -1789,9 +1789,14 @@ __export(index_exports, {
|
|
|
1789
1789
|
AI_CHUNKS_COLLECTION: () => AI_CHUNKS_COLLECTION,
|
|
1790
1790
|
AI_MESSAGES_COLLECTION: () => AI_MESSAGES_COLLECTION,
|
|
1791
1791
|
AI_THREADS_COLLECTION: () => AI_THREADS_COLLECTION,
|
|
1792
|
+
BASE62_ALPHABET: () => BASE62_ALPHABET,
|
|
1792
1793
|
BUILTIN_JEXL_HELPERS: () => BUILTIN_JEXL_HELPERS,
|
|
1794
|
+
CROCKFORD_BASE32: () => CROCKFORD_BASE32,
|
|
1795
|
+
CURRENT_NAV_PREFERENCES_VERSION: () => CURRENT_NAV_PREFERENCES_VERSION,
|
|
1793
1796
|
ConfigValidationError: () => ConfigValidationError,
|
|
1794
1797
|
ConflictError: () => ConflictError,
|
|
1798
|
+
DEFAULT_USER_NAV_PREFERENCES: () => DEFAULT_USER_NAV_PREFERENCES,
|
|
1799
|
+
DuplicateKeyError: () => DuplicateKeyError,
|
|
1795
1800
|
DyrectedAIError: () => DyrectedAIError,
|
|
1796
1801
|
DyrectedError: () => DyrectedError,
|
|
1797
1802
|
FieldConditionBuilder: () => FieldConditionBuilder,
|
|
@@ -1799,9 +1804,11 @@ __export(index_exports, {
|
|
|
1799
1804
|
LIFECYCLE_EVENTS_COLLECTION: () => LIFECYCLE_EVENTS_COLLECTION,
|
|
1800
1805
|
LIFECYCLE_EVENT_NAMES: () => LIFECYCLE_EVENT_NAMES,
|
|
1801
1806
|
MatchBuilder: () => MatchBuilder,
|
|
1807
|
+
NANOID_ALPHABET: () => NANOID_ALPHABET,
|
|
1802
1808
|
NON_NEGOTIABLE_CREDENTIAL_FIELDS: () => NON_NEGOTIABLE_CREDENTIAL_FIELDS,
|
|
1803
1809
|
NotFoundError: () => NotFoundError,
|
|
1804
1810
|
PII_REGEX_PATTERNS: () => PII_REGEX_PATTERNS,
|
|
1811
|
+
RESERVED_NAVIGATION_SLUGS: () => RESERVED_NAVIGATION_SLUGS,
|
|
1805
1812
|
ValidationError: () => ValidationError,
|
|
1806
1813
|
WORKFLOW_HISTORY_COLLECTION: () => WORKFLOW_HISTORY_COLLECTION,
|
|
1807
1814
|
abs: () => abs,
|
|
@@ -1812,6 +1819,7 @@ __export(index_exports, {
|
|
|
1812
1819
|
assertValidDeclarativeHookExpression: () => assertValidDeclarativeHookExpression,
|
|
1813
1820
|
assertValidDeclarativeHookResult: () => assertValidDeclarativeHookResult,
|
|
1814
1821
|
assertValidDeclarativeHooksInConfig: () => assertValidDeclarativeHooksInConfig,
|
|
1822
|
+
assertValidNavigationSlugs: () => assertValidNavigationSlugs,
|
|
1815
1823
|
assertValidPreviewUrlsInConfig: () => assertValidPreviewUrlsInConfig,
|
|
1816
1824
|
availableWorkflowTransitions: () => availableWorkflowTransitions,
|
|
1817
1825
|
buildSqlOrderBy: () => buildSqlOrderBy,
|
|
@@ -1826,6 +1834,7 @@ __export(index_exports, {
|
|
|
1826
1834
|
collectDeclarativeHookValidationIssues: () => collectDeclarativeHookValidationIssues,
|
|
1827
1835
|
collectPreviewUrlValidationIssues: () => collectPreviewUrlValidationIssues,
|
|
1828
1836
|
compact: () => compact,
|
|
1837
|
+
compileNavigation: () => compileNavigation,
|
|
1829
1838
|
count: () => count,
|
|
1830
1839
|
createLifecycleEvent: () => createLifecycleEvent,
|
|
1831
1840
|
createWorkflowDocument: () => createWorkflowDocument,
|
|
@@ -1866,6 +1875,7 @@ __export(index_exports, {
|
|
|
1866
1875
|
defineTimeField: () => defineTimeField,
|
|
1867
1876
|
defineUrlField: () => defineUrlField,
|
|
1868
1877
|
defineView: () => defineView,
|
|
1878
|
+
defineWorkspace: () => defineWorkspace,
|
|
1869
1879
|
diffDays: () => diffDays,
|
|
1870
1880
|
dispatchLifecycleEvent: () => dispatchLifecycleEvent,
|
|
1871
1881
|
dispatchPendingLifecycleEvents: () => dispatchPendingLifecycleEvents,
|
|
@@ -1894,6 +1904,8 @@ __export(index_exports, {
|
|
|
1894
1904
|
formatDate: () => formatDate,
|
|
1895
1905
|
formatJexlValue: () => formatJexlValue,
|
|
1896
1906
|
generateDefaultDetailSchema: () => generateDefaultDetailSchema,
|
|
1907
|
+
generateDocumentId: () => generateDocumentId,
|
|
1908
|
+
generateId: () => generateId,
|
|
1897
1909
|
generateOpenApi: () => generateOpenApi,
|
|
1898
1910
|
get: () => get,
|
|
1899
1911
|
getAdminAuthCollection: () => getAdminAuthCollection,
|
|
@@ -1920,6 +1932,7 @@ __export(index_exports, {
|
|
|
1920
1932
|
materializeWorkflowDocument: () => materializeWorkflowDocument,
|
|
1921
1933
|
max: () => max,
|
|
1922
1934
|
min: () => min,
|
|
1935
|
+
nanoid: () => nanoid,
|
|
1923
1936
|
normalizeConfig: () => normalizeConfig,
|
|
1924
1937
|
normalizeDetailItem: () => normalizeDetailItem,
|
|
1925
1938
|
now: () => now,
|
|
@@ -1928,13 +1941,17 @@ __export(index_exports, {
|
|
|
1928
1941
|
parseSort: () => parseSort,
|
|
1929
1942
|
parseSqlWhere: () => parseSqlWhere,
|
|
1930
1943
|
pow: () => pow,
|
|
1944
|
+
prefixedId: () => prefixedId,
|
|
1945
|
+
pruneNavigationForUser: () => pruneNavigationForUser,
|
|
1931
1946
|
publishedStateName: () => publishedStateName,
|
|
1932
1947
|
publishingWorkflow: () => publishingWorkflow,
|
|
1933
1948
|
readingTime: () => readingTime,
|
|
1949
|
+
reconcileNavigation: () => reconcileNavigation,
|
|
1934
1950
|
registerJexlHelpers: () => registerJexlHelpers,
|
|
1935
1951
|
replace: () => replace,
|
|
1936
1952
|
resolveAdminAuthCollection: () => resolveAdminAuthCollection,
|
|
1937
1953
|
resolveAuthorizedSiteId: () => resolveAuthorizedSiteId,
|
|
1954
|
+
resolvePrefix: () => resolvePrefix,
|
|
1938
1955
|
round: () => round,
|
|
1939
1956
|
runCollectionHooks: () => runCollectionHooks,
|
|
1940
1957
|
sanitizeDocForAI: () => sanitizeDocForAI,
|
|
@@ -1948,8 +1965,10 @@ __export(index_exports, {
|
|
|
1948
1965
|
transitionWorkflow: () => transitionWorkflow,
|
|
1949
1966
|
trim: () => trim,
|
|
1950
1967
|
truncate: () => truncate,
|
|
1968
|
+
ulid: () => ulid,
|
|
1951
1969
|
unique: () => unique,
|
|
1952
1970
|
upper: () => upper,
|
|
1971
|
+
uuid: () => uuid,
|
|
1953
1972
|
validateAdminConditionExpression: () => validateAdminConditionExpression,
|
|
1954
1973
|
validateDeclarativeAccessExpression: () => validateDeclarativeAccessExpression,
|
|
1955
1974
|
validateDeclarativeHookExpression: () => validateDeclarativeHookExpression,
|
|
@@ -2031,6 +2050,21 @@ var DyrectedAIError = class _DyrectedAIError extends Error {
|
|
|
2031
2050
|
}
|
|
2032
2051
|
};
|
|
2033
2052
|
|
|
2053
|
+
// src/types/navigation.ts
|
|
2054
|
+
function defineWorkspace(options) {
|
|
2055
|
+
return options;
|
|
2056
|
+
}
|
|
2057
|
+
var CURRENT_NAV_PREFERENCES_VERSION = 1;
|
|
2058
|
+
var DEFAULT_USER_NAV_PREFERENCES = {
|
|
2059
|
+
_version: CURRENT_NAV_PREFERENCES_VERSION,
|
|
2060
|
+
pinned: [],
|
|
2061
|
+
hidden: [],
|
|
2062
|
+
groupOrder: [],
|
|
2063
|
+
itemOrder: {},
|
|
2064
|
+
groups: [],
|
|
2065
|
+
items: []
|
|
2066
|
+
};
|
|
2067
|
+
|
|
2034
2068
|
// src/auth/token.ts
|
|
2035
2069
|
var import_jose = require("jose");
|
|
2036
2070
|
|
|
@@ -3549,6 +3583,134 @@ function assertValidDeclarativeAccessInConfig(config, source = "config") {
|
|
|
3549
3583
|
throw new ConfigValidationError(source, diagnostics);
|
|
3550
3584
|
}
|
|
3551
3585
|
|
|
3586
|
+
// src/utils/id.ts
|
|
3587
|
+
var import_node_crypto = require("crypto");
|
|
3588
|
+
var NANOID_ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-";
|
|
3589
|
+
var BASE62_ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
3590
|
+
var CROCKFORD_BASE32 = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
3591
|
+
var COMMON_SLUG_PREFIXES = {
|
|
3592
|
+
users: "usr",
|
|
3593
|
+
members: "mem",
|
|
3594
|
+
accounts: "acc",
|
|
3595
|
+
applications: "app",
|
|
3596
|
+
customers: "cus",
|
|
3597
|
+
products: "prd",
|
|
3598
|
+
orders: "ord",
|
|
3599
|
+
reports: "rpt",
|
|
3600
|
+
sessions: "ses",
|
|
3601
|
+
transactions: "txn",
|
|
3602
|
+
wallets: "wal",
|
|
3603
|
+
media: "med",
|
|
3604
|
+
files: "fil",
|
|
3605
|
+
posts: "post",
|
|
3606
|
+
pages: "page",
|
|
3607
|
+
tags: "tag",
|
|
3608
|
+
categories: "cat",
|
|
3609
|
+
comments: "com"
|
|
3610
|
+
};
|
|
3611
|
+
function nanoid(size = 21, alphabet = NANOID_ALPHABET) {
|
|
3612
|
+
const mask = (2 << 31 - Math.clz32(alphabet.length - 1 | 1)) - 1;
|
|
3613
|
+
const step = Math.ceil(1.6 * mask * size / alphabet.length);
|
|
3614
|
+
let id = "";
|
|
3615
|
+
while (true) {
|
|
3616
|
+
const bytes = (0, import_node_crypto.randomBytes)(step);
|
|
3617
|
+
for (let i = 0; i < step; i++) {
|
|
3618
|
+
const byte = bytes[i] & mask;
|
|
3619
|
+
if (alphabet[byte]) {
|
|
3620
|
+
id += alphabet[byte];
|
|
3621
|
+
if (id.length === size) return id;
|
|
3622
|
+
}
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3625
|
+
}
|
|
3626
|
+
function encodeUlidTime(now2, len = 10) {
|
|
3627
|
+
let str = "";
|
|
3628
|
+
let time = Math.floor(now2);
|
|
3629
|
+
for (let i = len - 1; i >= 0; i--) {
|
|
3630
|
+
const mod = time % 32;
|
|
3631
|
+
str = CROCKFORD_BASE32[mod] + str;
|
|
3632
|
+
time = (time - mod) / 32;
|
|
3633
|
+
}
|
|
3634
|
+
return str;
|
|
3635
|
+
}
|
|
3636
|
+
function encodeUlidRandom(bytes) {
|
|
3637
|
+
let str = "";
|
|
3638
|
+
let bitBuffer = 0;
|
|
3639
|
+
let bitsInBuffer = 0;
|
|
3640
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
3641
|
+
bitBuffer = bitBuffer << 8 | bytes[i];
|
|
3642
|
+
bitsInBuffer += 8;
|
|
3643
|
+
while (bitsInBuffer >= 5) {
|
|
3644
|
+
bitsInBuffer -= 5;
|
|
3645
|
+
const index = bitBuffer >> bitsInBuffer & 31;
|
|
3646
|
+
str += CROCKFORD_BASE32[index];
|
|
3647
|
+
}
|
|
3648
|
+
}
|
|
3649
|
+
return str;
|
|
3650
|
+
}
|
|
3651
|
+
function ulid(seedTime = Date.now()) {
|
|
3652
|
+
const timePart = encodeUlidTime(seedTime);
|
|
3653
|
+
const randPart = encodeUlidRandom((0, import_node_crypto.randomBytes)(10));
|
|
3654
|
+
return timePart + randPart;
|
|
3655
|
+
}
|
|
3656
|
+
function uuid() {
|
|
3657
|
+
return (0, import_node_crypto.randomUUID)();
|
|
3658
|
+
}
|
|
3659
|
+
function resolvePrefix(slug, explicitPrefix) {
|
|
3660
|
+
if (explicitPrefix && typeof explicitPrefix === "string" && explicitPrefix.trim().length > 0) {
|
|
3661
|
+
const cleaned = explicitPrefix.trim().toLowerCase().replace(/[^a-z0-9_]/g, "");
|
|
3662
|
+
if (cleaned.length > 0) return cleaned;
|
|
3663
|
+
}
|
|
3664
|
+
if (!slug || typeof slug !== "string") return "col";
|
|
3665
|
+
const s = slug.trim().toLowerCase();
|
|
3666
|
+
if (COMMON_SLUG_PREFIXES[s]) return COMMON_SLUG_PREFIXES[s];
|
|
3667
|
+
const pieces = s.split(/[-_]/).filter(Boolean);
|
|
3668
|
+
if (pieces.length > 1 && pieces[0].length >= 2) {
|
|
3669
|
+
const first2 = pieces[0].replace(/[^a-z0-9]/g, "");
|
|
3670
|
+
if (first2.length >= 2) return first2.slice(0, 4);
|
|
3671
|
+
}
|
|
3672
|
+
const cleanWord = s.replace(/[^a-z0-9]/g, "");
|
|
3673
|
+
if (cleanWord.length <= 4) return cleanWord || "col";
|
|
3674
|
+
return cleanWord.slice(0, 3) || "col";
|
|
3675
|
+
}
|
|
3676
|
+
function prefixedId(prefix = "col", size = 16) {
|
|
3677
|
+
const cleanPrefix = (prefix || "col").toLowerCase().replace(/[^a-z0-9_]/g, "") || "col";
|
|
3678
|
+
return `${cleanPrefix}_${nanoid(size, BASE62_ALPHABET)}`;
|
|
3679
|
+
}
|
|
3680
|
+
function generateId(options) {
|
|
3681
|
+
if (typeof options === "string") {
|
|
3682
|
+
return prefixedId(resolvePrefix(options));
|
|
3683
|
+
}
|
|
3684
|
+
const opts = options || {};
|
|
3685
|
+
const type = opts.type || "prefixed-nanoid";
|
|
3686
|
+
switch (type) {
|
|
3687
|
+
case "uuid":
|
|
3688
|
+
return uuid();
|
|
3689
|
+
case "ulid":
|
|
3690
|
+
return ulid();
|
|
3691
|
+
case "nanoid":
|
|
3692
|
+
return nanoid(opts.size || 21);
|
|
3693
|
+
case "prefixed-nanoid":
|
|
3694
|
+
default:
|
|
3695
|
+
return prefixedId(opts.prefix || "col", opts.size || 16);
|
|
3696
|
+
}
|
|
3697
|
+
}
|
|
3698
|
+
function generateDocumentId(collectionOrSlug) {
|
|
3699
|
+
if (!collectionOrSlug) {
|
|
3700
|
+
return prefixedId("col");
|
|
3701
|
+
}
|
|
3702
|
+
if (typeof collectionOrSlug === "string") {
|
|
3703
|
+
const prefix2 = resolvePrefix(collectionOrSlug);
|
|
3704
|
+
return prefixedId(prefix2);
|
|
3705
|
+
}
|
|
3706
|
+
if (typeof collectionOrSlug.idGenerator === "function") {
|
|
3707
|
+
return collectionOrSlug.idGenerator(collectionOrSlug.slug);
|
|
3708
|
+
}
|
|
3709
|
+
const type = collectionOrSlug.idType || "prefixed-nanoid";
|
|
3710
|
+
const prefix = resolvePrefix(collectionOrSlug.slug, collectionOrSlug.idPrefix);
|
|
3711
|
+
return generateId({ prefix, type });
|
|
3712
|
+
}
|
|
3713
|
+
|
|
3552
3714
|
// src/utils/config.ts
|
|
3553
3715
|
var AUDIT_COLLECTION_SLUG = "__audit";
|
|
3554
3716
|
var SYSTEM_FIELDS = [
|
|
@@ -3779,7 +3941,33 @@ function normalizeConfig(config) {
|
|
|
3779
3941
|
}
|
|
3780
3942
|
];
|
|
3781
3943
|
}
|
|
3944
|
+
if (!existingFieldNames.has("__preferences")) {
|
|
3945
|
+
fields = [
|
|
3946
|
+
...fields,
|
|
3947
|
+
{
|
|
3948
|
+
name: "__preferences",
|
|
3949
|
+
type: "json",
|
|
3950
|
+
label: "Preferences",
|
|
3951
|
+
promoted: true,
|
|
3952
|
+
admin: {
|
|
3953
|
+
hidden: true,
|
|
3954
|
+
readOnly: true
|
|
3955
|
+
}
|
|
3956
|
+
}
|
|
3957
|
+
];
|
|
3958
|
+
}
|
|
3782
3959
|
fields = fields.map((field) => {
|
|
3960
|
+
if (field.name === "__preferences") {
|
|
3961
|
+
return {
|
|
3962
|
+
...field,
|
|
3963
|
+
promoted: true,
|
|
3964
|
+
admin: {
|
|
3965
|
+
...field.admin || {},
|
|
3966
|
+
hidden: true,
|
|
3967
|
+
readOnly: true
|
|
3968
|
+
}
|
|
3969
|
+
};
|
|
3970
|
+
}
|
|
3783
3971
|
if (field.name === "email") {
|
|
3784
3972
|
return {
|
|
3785
3973
|
...field,
|
|
@@ -3870,11 +4058,31 @@ function normalizeConfig(config) {
|
|
|
3870
4058
|
}
|
|
3871
4059
|
const updatedFieldNames = new Set(fields.map((f) => f.name));
|
|
3872
4060
|
const fieldsToInject = SYSTEM_FIELDS.filter((f) => !updatedFieldNames.has(f.name));
|
|
4061
|
+
const indexedFieldNames = /* @__PURE__ */ new Set();
|
|
4062
|
+
if (col.indexes) {
|
|
4063
|
+
for (const idx of col.indexes) {
|
|
4064
|
+
if (Array.isArray(idx.fields)) {
|
|
4065
|
+
for (const f of idx.fields) {
|
|
4066
|
+
indexedFieldNames.add(f);
|
|
4067
|
+
}
|
|
4068
|
+
}
|
|
4069
|
+
}
|
|
4070
|
+
}
|
|
4071
|
+
const allFields = [...fields, ...fieldsToInject].map((field) => {
|
|
4072
|
+
if (field.unique || field.name && indexedFieldNames.has(field.name)) {
|
|
4073
|
+
return { ...field, promoted: true };
|
|
4074
|
+
}
|
|
4075
|
+
return field;
|
|
4076
|
+
});
|
|
3873
4077
|
const workflow = col.workflow || (col.drafts ? simplePublishingWorkflow() : void 0);
|
|
4078
|
+
const idPrefix = col.idPrefix || resolvePrefix(col.slug);
|
|
4079
|
+
const idType = col.idType || "prefixed-nanoid";
|
|
3874
4080
|
return {
|
|
3875
4081
|
...col,
|
|
4082
|
+
idPrefix,
|
|
4083
|
+
idType,
|
|
3876
4084
|
workflow,
|
|
3877
|
-
fields:
|
|
4085
|
+
fields: allFields
|
|
3878
4086
|
};
|
|
3879
4087
|
});
|
|
3880
4088
|
const hasAuditCollection = normalizedCollections.some((col) => col.slug === AUDIT_COLLECTION_SLUG);
|
|
@@ -3934,6 +4142,17 @@ var ConflictError = class _ConflictError extends DyrectedError {
|
|
|
3934
4142
|
Object.setPrototypeOf(this, _ConflictError.prototype);
|
|
3935
4143
|
}
|
|
3936
4144
|
};
|
|
4145
|
+
var DuplicateKeyError = class _DuplicateKeyError extends ConflictError {
|
|
4146
|
+
field;
|
|
4147
|
+
value;
|
|
4148
|
+
constructor(message, options) {
|
|
4149
|
+
super(message);
|
|
4150
|
+
this.name = "DuplicateKeyError";
|
|
4151
|
+
this.field = options?.field;
|
|
4152
|
+
this.value = options?.value;
|
|
4153
|
+
Object.setPrototypeOf(this, _DuplicateKeyError.prototype);
|
|
4154
|
+
}
|
|
4155
|
+
};
|
|
3937
4156
|
|
|
3938
4157
|
// src/utils/parse-where.ts
|
|
3939
4158
|
function assertNever(op, context) {
|
|
@@ -6555,6 +6774,525 @@ function sanitizeDocForAI(options) {
|
|
|
6555
6774
|
return result;
|
|
6556
6775
|
}
|
|
6557
6776
|
|
|
6777
|
+
// src/utils/navigation-reconciler.ts
|
|
6778
|
+
var normalizeKey = (val) => (val || "").toLowerCase().replace(/[^a-z0-9]/g, "-");
|
|
6779
|
+
function reconcileNavigation(baseTree, prefs, schemas, options) {
|
|
6780
|
+
if (!baseTree) {
|
|
6781
|
+
return {
|
|
6782
|
+
groups: [],
|
|
6783
|
+
ungrouped: [],
|
|
6784
|
+
pinnedItems: []
|
|
6785
|
+
};
|
|
6786
|
+
}
|
|
6787
|
+
const includeHidden = options?.includeHidden ?? false;
|
|
6788
|
+
const effectivePrefs = prefs || DEFAULT_USER_NAV_PREFERENCES;
|
|
6789
|
+
const hiddenSet = new Set(effectivePrefs.hidden || []);
|
|
6790
|
+
const knownCollectionSlugs = new Set((schemas?.collections || []).map((c) => c.slug));
|
|
6791
|
+
const knownGlobalSlugs = new Set((schemas?.globals || []).map((g) => g.slug));
|
|
6792
|
+
const groupsList = [];
|
|
6793
|
+
const findGroup = (query) => {
|
|
6794
|
+
const qNorm = normalizeKey(query);
|
|
6795
|
+
return groupsList.find(
|
|
6796
|
+
(g) => g.id === query || g.slug === query || g.name === query || normalizeKey(g.id) === qNorm || normalizeKey(g.slug) === qNorm || normalizeKey(g.name) === qNorm
|
|
6797
|
+
);
|
|
6798
|
+
};
|
|
6799
|
+
for (const g of baseTree.groups || []) {
|
|
6800
|
+
groupsList.push({
|
|
6801
|
+
...g,
|
|
6802
|
+
items: (g.items || []).map((item) => ({ ...item }))
|
|
6803
|
+
});
|
|
6804
|
+
}
|
|
6805
|
+
for (const ug of effectivePrefs.groups || []) {
|
|
6806
|
+
const existing = findGroup(ug.slug || ug.name);
|
|
6807
|
+
if (!existing) {
|
|
6808
|
+
groupsList.push({
|
|
6809
|
+
id: ug.slug ? `group_${ug.slug}` : `group_${normalizeKey(ug.name)}`,
|
|
6810
|
+
name: ug.name,
|
|
6811
|
+
slug: ug.slug || normalizeKey(ug.name),
|
|
6812
|
+
icon: ug.icon || "Folder",
|
|
6813
|
+
defaultExpanded: ug.defaultExpanded ?? true,
|
|
6814
|
+
order: ug.order ?? 100,
|
|
6815
|
+
items: []
|
|
6816
|
+
});
|
|
6817
|
+
}
|
|
6818
|
+
}
|
|
6819
|
+
for (const itemOpt of effectivePrefs.items || []) {
|
|
6820
|
+
const targetGroup = typeof itemOpt.group === "object" ? itemOpt.group?.name : itemOpt.group;
|
|
6821
|
+
const groupKey = targetGroup || "Custom";
|
|
6822
|
+
let group = findGroup(groupKey);
|
|
6823
|
+
if (!group) {
|
|
6824
|
+
group = {
|
|
6825
|
+
id: `group_${normalizeKey(groupKey)}`,
|
|
6826
|
+
name: groupKey,
|
|
6827
|
+
slug: normalizeKey(groupKey),
|
|
6828
|
+
icon: "Folder",
|
|
6829
|
+
defaultExpanded: true,
|
|
6830
|
+
order: 99,
|
|
6831
|
+
items: []
|
|
6832
|
+
};
|
|
6833
|
+
groupsList.push(group);
|
|
6834
|
+
}
|
|
6835
|
+
const itemId = itemOpt.slug ? `workspace_${itemOpt.slug}` : itemOpt.collection ? `collection_${itemOpt.collection}` : `custom_${Math.random()}`;
|
|
6836
|
+
for (const otherGroup of groupsList) {
|
|
6837
|
+
if (otherGroup !== group) {
|
|
6838
|
+
otherGroup.items = otherGroup.items.filter((i) => i.slug !== itemOpt.slug && i.id !== itemId);
|
|
6839
|
+
}
|
|
6840
|
+
}
|
|
6841
|
+
const existingIndex = group.items.findIndex((i) => i.id === itemId || i.slug === itemOpt.slug);
|
|
6842
|
+
const existingItem = existingIndex >= 0 ? group.items[existingIndex] : void 0;
|
|
6843
|
+
const col = schemas?.collections?.find((c) => c.slug === itemOpt.collection);
|
|
6844
|
+
const colViews = col?.views || [];
|
|
6845
|
+
const baseViews = existingItem?.views || [];
|
|
6846
|
+
const userViews = itemOpt.views || [];
|
|
6847
|
+
const userViewSlugs = new Set(userViews.map((v) => v.slug));
|
|
6848
|
+
let mergedViews = [
|
|
6849
|
+
...baseViews.filter((v) => !userViewSlugs.has(v.slug)),
|
|
6850
|
+
...userViews
|
|
6851
|
+
];
|
|
6852
|
+
if (mergedViews.length === 0 && itemOpt.collection) {
|
|
6853
|
+
if (colViews.length > 0) {
|
|
6854
|
+
mergedViews = [...colViews];
|
|
6855
|
+
} else {
|
|
6856
|
+
mergedViews = [
|
|
6857
|
+
{
|
|
6858
|
+
slug: "default",
|
|
6859
|
+
label: col?.label || col?.labels?.plural || itemOpt.label || "All Records",
|
|
6860
|
+
layout: "table",
|
|
6861
|
+
collection: itemOpt.collection
|
|
6862
|
+
}
|
|
6863
|
+
];
|
|
6864
|
+
}
|
|
6865
|
+
}
|
|
6866
|
+
mergedViews = mergedViews.map((v) => ({
|
|
6867
|
+
...v,
|
|
6868
|
+
collection: v.collection || itemOpt.collection || existingItem?.collection
|
|
6869
|
+
}));
|
|
6870
|
+
const compiledItem = {
|
|
6871
|
+
id: itemId,
|
|
6872
|
+
type: itemOpt.slug ? "workspace" : itemOpt.collection ? "collection" : itemOpt.global ? "global" : "workspace",
|
|
6873
|
+
slug: itemOpt.slug || itemOpt.collection || itemOpt.global || "item",
|
|
6874
|
+
label: itemOpt.label || itemOpt.slug || "Item",
|
|
6875
|
+
icon: itemOpt.icon || existingItem?.icon || col?.admin?.icon || "Briefcase",
|
|
6876
|
+
group: group.name,
|
|
6877
|
+
order: itemOpt.order ?? existingItem?.order ?? 100,
|
|
6878
|
+
views: mergedViews,
|
|
6879
|
+
collection: itemOpt.collection || existingItem?.collection,
|
|
6880
|
+
global: itemOpt.global || existingItem?.global,
|
|
6881
|
+
badge: itemOpt.badge || existingItem?.badge,
|
|
6882
|
+
access: itemOpt.access || existingItem?.access
|
|
6883
|
+
};
|
|
6884
|
+
if (existingIndex >= 0) {
|
|
6885
|
+
group.items[existingIndex] = compiledItem;
|
|
6886
|
+
} else {
|
|
6887
|
+
group.items.push(compiledItem);
|
|
6888
|
+
}
|
|
6889
|
+
}
|
|
6890
|
+
const allAvailableItems = [];
|
|
6891
|
+
const reconciledGroups = [];
|
|
6892
|
+
for (const group of groupsList) {
|
|
6893
|
+
const isGroupHidden = hiddenSet.has(group.id) || !!group.slug && hiddenSet.has(group.slug) || hiddenSet.has(group.name);
|
|
6894
|
+
if (!includeHidden && isGroupHidden) {
|
|
6895
|
+
continue;
|
|
6896
|
+
}
|
|
6897
|
+
const visibleItems = [];
|
|
6898
|
+
for (const item of group.items) {
|
|
6899
|
+
const isItemHidden = hiddenSet.has(item.id) || !!item.slug && hiddenSet.has(item.slug);
|
|
6900
|
+
if (!includeHidden && isItemHidden) {
|
|
6901
|
+
continue;
|
|
6902
|
+
}
|
|
6903
|
+
const allViews = item.views || [];
|
|
6904
|
+
const visibleViews = includeHidden ? allViews : allViews.filter((v) => {
|
|
6905
|
+
const compoundKey = `${item.slug}_${v.slug}`;
|
|
6906
|
+
return !hiddenSet.has(compoundKey) && !hiddenSet.has(v.slug);
|
|
6907
|
+
});
|
|
6908
|
+
let isTombstone = false;
|
|
6909
|
+
if (schemas && schemas.collections && schemas.collections.length > 0) {
|
|
6910
|
+
if (item.collection && !knownCollectionSlugs.has(item.collection)) {
|
|
6911
|
+
isTombstone = true;
|
|
6912
|
+
}
|
|
6913
|
+
}
|
|
6914
|
+
if (schemas && schemas.globals && schemas.globals.length > 0) {
|
|
6915
|
+
if (item.global && !knownGlobalSlugs.has(item.global)) {
|
|
6916
|
+
isTombstone = true;
|
|
6917
|
+
}
|
|
6918
|
+
}
|
|
6919
|
+
const processedItem = {
|
|
6920
|
+
...item,
|
|
6921
|
+
views: visibleViews,
|
|
6922
|
+
...isTombstone ? { isTombstone: true } : {}
|
|
6923
|
+
};
|
|
6924
|
+
visibleItems.push(processedItem);
|
|
6925
|
+
allAvailableItems.push(processedItem);
|
|
6926
|
+
}
|
|
6927
|
+
const groupKey = group.slug || group.name;
|
|
6928
|
+
const itemOrderList = effectivePrefs.itemOrder?.[group.id] || effectivePrefs.itemOrder?.[groupKey];
|
|
6929
|
+
if (itemOrderList && itemOrderList.length > 0) {
|
|
6930
|
+
visibleItems.sort((a, b) => {
|
|
6931
|
+
const aIdx = itemOrderList.indexOf(a.id) >= 0 ? itemOrderList.indexOf(a.id) : a.slug ? itemOrderList.indexOf(a.slug) : -1;
|
|
6932
|
+
const bIdx = itemOrderList.indexOf(b.id) >= 0 ? itemOrderList.indexOf(b.id) : b.slug ? itemOrderList.indexOf(b.slug) : -1;
|
|
6933
|
+
if (aIdx >= 0 && bIdx >= 0) return aIdx - bIdx;
|
|
6934
|
+
if (aIdx >= 0) return -1;
|
|
6935
|
+
if (bIdx >= 0) return 1;
|
|
6936
|
+
return (a.order ?? 100) - (b.order ?? 100);
|
|
6937
|
+
});
|
|
6938
|
+
} else {
|
|
6939
|
+
visibleItems.sort((a, b) => (a.order ?? 100) - (b.order ?? 100));
|
|
6940
|
+
}
|
|
6941
|
+
reconciledGroups.push({
|
|
6942
|
+
...group,
|
|
6943
|
+
items: visibleItems
|
|
6944
|
+
});
|
|
6945
|
+
}
|
|
6946
|
+
if (effectivePrefs.groupOrder && effectivePrefs.groupOrder.length > 0) {
|
|
6947
|
+
reconciledGroups.sort((a, b) => {
|
|
6948
|
+
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);
|
|
6949
|
+
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);
|
|
6950
|
+
if (aIdx >= 0 && bIdx >= 0) return aIdx - bIdx;
|
|
6951
|
+
if (aIdx >= 0) return -1;
|
|
6952
|
+
if (bIdx >= 0) return 1;
|
|
6953
|
+
return (a.order ?? 100) - (b.order ?? 100);
|
|
6954
|
+
});
|
|
6955
|
+
} else {
|
|
6956
|
+
reconciledGroups.sort((a, b) => (a.order ?? 100) - (b.order ?? 100));
|
|
6957
|
+
}
|
|
6958
|
+
const reconciledUngrouped = (baseTree.ungrouped || []).filter((item) => {
|
|
6959
|
+
const isItemHidden = hiddenSet.has(item.id) || !!item.slug && hiddenSet.has(item.slug);
|
|
6960
|
+
return includeHidden || !isItemHidden;
|
|
6961
|
+
}).map((item) => {
|
|
6962
|
+
const allViews = item.views || [];
|
|
6963
|
+
const visibleViews = includeHidden ? allViews : allViews.filter((v) => {
|
|
6964
|
+
const compoundKey = `${item.slug}_${v.slug}`;
|
|
6965
|
+
return !hiddenSet.has(compoundKey) && !hiddenSet.has(v.slug);
|
|
6966
|
+
});
|
|
6967
|
+
const processed = { ...item, views: visibleViews };
|
|
6968
|
+
allAvailableItems.push(processed);
|
|
6969
|
+
return processed;
|
|
6970
|
+
});
|
|
6971
|
+
const pinnedItems = [];
|
|
6972
|
+
for (const pin of effectivePrefs.pinned || []) {
|
|
6973
|
+
const match = allAvailableItems.find((i) => i.slug === pin.slug || i.id === pin.slug);
|
|
6974
|
+
if (match) {
|
|
6975
|
+
pinnedItems.push({
|
|
6976
|
+
...match,
|
|
6977
|
+
id: `pin_${match.id}`,
|
|
6978
|
+
label: pin.label || match.label,
|
|
6979
|
+
icon: pin.icon || match.icon
|
|
6980
|
+
});
|
|
6981
|
+
} else {
|
|
6982
|
+
pinnedItems.push({
|
|
6983
|
+
id: `pin_${pin.slug}`,
|
|
6984
|
+
type: pin.type,
|
|
6985
|
+
slug: pin.slug,
|
|
6986
|
+
label: pin.label || pin.slug,
|
|
6987
|
+
icon: pin.icon || "Star",
|
|
6988
|
+
order: 0,
|
|
6989
|
+
views: []
|
|
6990
|
+
});
|
|
6991
|
+
}
|
|
6992
|
+
}
|
|
6993
|
+
return {
|
|
6994
|
+
groups: reconciledGroups,
|
|
6995
|
+
ungrouped: reconciledUngrouped,
|
|
6996
|
+
pinnedItems
|
|
6997
|
+
};
|
|
6998
|
+
}
|
|
6999
|
+
|
|
7000
|
+
// src/utils/navigation.ts
|
|
7001
|
+
var RESERVED_NAVIGATION_SLUGS = /* @__PURE__ */ new Set([
|
|
7002
|
+
"collections",
|
|
7003
|
+
"globals",
|
|
7004
|
+
"setup",
|
|
7005
|
+
"api",
|
|
7006
|
+
"login",
|
|
7007
|
+
"logout",
|
|
7008
|
+
"settings",
|
|
7009
|
+
"admin",
|
|
7010
|
+
"preferences",
|
|
7011
|
+
"auth"
|
|
7012
|
+
]);
|
|
7013
|
+
function assertValidNavigationSlugs(navigation) {
|
|
7014
|
+
for (const item of navigation) {
|
|
7015
|
+
if (item.slug) {
|
|
7016
|
+
const normalizedSlug = item.slug.toLowerCase().trim().replace(/^\//, "");
|
|
7017
|
+
if (RESERVED_NAVIGATION_SLUGS.has(normalizedSlug)) {
|
|
7018
|
+
throw new Error(
|
|
7019
|
+
`[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.`
|
|
7020
|
+
);
|
|
7021
|
+
}
|
|
7022
|
+
}
|
|
7023
|
+
}
|
|
7024
|
+
}
|
|
7025
|
+
function resolveGroupMeta(groupProp, defaultGroupName = "Collections") {
|
|
7026
|
+
if (!groupProp) {
|
|
7027
|
+
return { name: defaultGroupName };
|
|
7028
|
+
}
|
|
7029
|
+
if (typeof groupProp === "string") {
|
|
7030
|
+
return { name: groupProp };
|
|
7031
|
+
}
|
|
7032
|
+
return { name: groupProp.name, meta: groupProp };
|
|
7033
|
+
}
|
|
7034
|
+
function compileNavigation(config) {
|
|
7035
|
+
const collections = config.collections || [];
|
|
7036
|
+
const globals = config.globals || [];
|
|
7037
|
+
const explicitNav = config.admin?.navigation || [];
|
|
7038
|
+
assertValidNavigationSlugs(explicitNav);
|
|
7039
|
+
const collectionsBySlug = /* @__PURE__ */ new Map();
|
|
7040
|
+
for (const col of collections) {
|
|
7041
|
+
collectionsBySlug.set(col.slug, col);
|
|
7042
|
+
}
|
|
7043
|
+
const globalsBySlug = /* @__PURE__ */ new Map();
|
|
7044
|
+
for (const gl of globals) {
|
|
7045
|
+
globalsBySlug.set(gl.slug, gl);
|
|
7046
|
+
}
|
|
7047
|
+
const mentionedCollections = /* @__PURE__ */ new Set();
|
|
7048
|
+
const mentionedGlobals = /* @__PURE__ */ new Set();
|
|
7049
|
+
const injectedViewsByCollection = /* @__PURE__ */ new Map();
|
|
7050
|
+
for (const item of explicitNav) {
|
|
7051
|
+
if (item.addToCollection) {
|
|
7052
|
+
const existing = injectedViewsByCollection.get(item.addToCollection) || [];
|
|
7053
|
+
if (item.views && item.views.length > 0) {
|
|
7054
|
+
injectedViewsByCollection.set(item.addToCollection, [...existing, ...item.views]);
|
|
7055
|
+
}
|
|
7056
|
+
}
|
|
7057
|
+
if (item.collection) mentionedCollections.add(item.collection);
|
|
7058
|
+
if (item.global) mentionedGlobals.add(item.global);
|
|
7059
|
+
}
|
|
7060
|
+
const groupMetadataMap = /* @__PURE__ */ new Map();
|
|
7061
|
+
const itemsByGroup = /* @__PURE__ */ new Map();
|
|
7062
|
+
const ungroupedItems = [];
|
|
7063
|
+
const registerItem = (groupName, item) => {
|
|
7064
|
+
if (!groupName) {
|
|
7065
|
+
ungroupedItems.push(item);
|
|
7066
|
+
} else {
|
|
7067
|
+
const list = itemsByGroup.get(groupName) || [];
|
|
7068
|
+
list.push(item);
|
|
7069
|
+
itemsByGroup.set(groupName, list);
|
|
7070
|
+
}
|
|
7071
|
+
};
|
|
7072
|
+
for (const item of explicitNav) {
|
|
7073
|
+
if (item.addToCollection && !item.slug && !item.collection && !item.global && !item.dashboard && !item.href) {
|
|
7074
|
+
continue;
|
|
7075
|
+
}
|
|
7076
|
+
const { name: groupName, meta: groupMeta } = resolveGroupMeta(item.group, void 0);
|
|
7077
|
+
if (groupName && groupMeta) {
|
|
7078
|
+
groupMetadataMap.set(groupName, { ...groupMetadataMap.get(groupName) || {}, ...groupMeta });
|
|
7079
|
+
}
|
|
7080
|
+
if (item.dashboard) {
|
|
7081
|
+
registerItem(groupName, {
|
|
7082
|
+
id: "dashboard",
|
|
7083
|
+
type: "dashboard",
|
|
7084
|
+
slug: "dashboard",
|
|
7085
|
+
label: item.label || "Dashboard",
|
|
7086
|
+
icon: item.icon || "LayoutDashboard",
|
|
7087
|
+
group: groupName,
|
|
7088
|
+
order: item.order ?? 0,
|
|
7089
|
+
views: [],
|
|
7090
|
+
access: item.access
|
|
7091
|
+
});
|
|
7092
|
+
continue;
|
|
7093
|
+
}
|
|
7094
|
+
if (item.collection) {
|
|
7095
|
+
const col = collectionsBySlug.get(item.collection);
|
|
7096
|
+
const combinedViews = [
|
|
7097
|
+
...col?.views || [],
|
|
7098
|
+
...injectedViewsByCollection.get(item.collection) || [],
|
|
7099
|
+
...item.views || []
|
|
7100
|
+
];
|
|
7101
|
+
registerItem(groupName, {
|
|
7102
|
+
id: item.slug || `collection_${item.collection}`,
|
|
7103
|
+
type: item.slug ? "workspace" : "collection",
|
|
7104
|
+
slug: item.slug || item.collection,
|
|
7105
|
+
collection: item.collection,
|
|
7106
|
+
label: item.label || col?.labels?.plural || item.collection,
|
|
7107
|
+
icon: item.icon || col?.admin?.icon || "Folder",
|
|
7108
|
+
group: groupName,
|
|
7109
|
+
order: item.order ?? col?.admin?.order ?? 100,
|
|
7110
|
+
views: combinedViews,
|
|
7111
|
+
badge: item.badge,
|
|
7112
|
+
access: item.access || col?.access?.read
|
|
7113
|
+
});
|
|
7114
|
+
continue;
|
|
7115
|
+
}
|
|
7116
|
+
if (item.global) {
|
|
7117
|
+
const gl = globalsBySlug.get(item.global);
|
|
7118
|
+
registerItem(groupName, {
|
|
7119
|
+
id: item.slug || `global_${item.global}`,
|
|
7120
|
+
type: "global",
|
|
7121
|
+
slug: item.slug || item.global,
|
|
7122
|
+
global: item.global,
|
|
7123
|
+
label: item.label || gl?.label || item.global,
|
|
7124
|
+
icon: item.icon || "Settings",
|
|
7125
|
+
group: groupName,
|
|
7126
|
+
order: item.order ?? 100,
|
|
7127
|
+
views: [],
|
|
7128
|
+
badge: item.badge,
|
|
7129
|
+
access: item.access
|
|
7130
|
+
});
|
|
7131
|
+
continue;
|
|
7132
|
+
}
|
|
7133
|
+
if (item.href) {
|
|
7134
|
+
registerItem(groupName, {
|
|
7135
|
+
id: `link_${item.slug || item.href}`,
|
|
7136
|
+
type: "link",
|
|
7137
|
+
slug: item.slug || "link",
|
|
7138
|
+
label: item.label || "Link",
|
|
7139
|
+
href: item.href,
|
|
7140
|
+
icon: item.icon || "ExternalLink",
|
|
7141
|
+
group: groupName,
|
|
7142
|
+
order: item.order ?? 100,
|
|
7143
|
+
views: [],
|
|
7144
|
+
badge: item.badge,
|
|
7145
|
+
access: item.access
|
|
7146
|
+
});
|
|
7147
|
+
continue;
|
|
7148
|
+
}
|
|
7149
|
+
const workspaceSlug = item.slug || "workspace";
|
|
7150
|
+
registerItem(groupName, {
|
|
7151
|
+
id: `workspace_${workspaceSlug}`,
|
|
7152
|
+
type: "workspace",
|
|
7153
|
+
slug: workspaceSlug,
|
|
7154
|
+
label: item.label || workspaceSlug,
|
|
7155
|
+
icon: item.icon || "Briefcase",
|
|
7156
|
+
group: groupName,
|
|
7157
|
+
order: item.order ?? 100,
|
|
7158
|
+
views: item.views || [],
|
|
7159
|
+
badge: item.badge,
|
|
7160
|
+
access: item.access
|
|
7161
|
+
});
|
|
7162
|
+
}
|
|
7163
|
+
for (const col of collections) {
|
|
7164
|
+
if (mentionedCollections.has(col.slug)) continue;
|
|
7165
|
+
if (col.admin?.hidden) continue;
|
|
7166
|
+
const groupProp = col.admin?.group;
|
|
7167
|
+
const { name: groupName, meta: groupMeta } = resolveGroupMeta(groupProp, "Collections");
|
|
7168
|
+
if (groupMeta) {
|
|
7169
|
+
groupMetadataMap.set(groupName, { ...groupMetadataMap.get(groupName) || {}, ...groupMeta });
|
|
7170
|
+
}
|
|
7171
|
+
const combinedViews = [
|
|
7172
|
+
...col.views || [],
|
|
7173
|
+
...injectedViewsByCollection.get(col.slug) || []
|
|
7174
|
+
];
|
|
7175
|
+
registerItem(groupName, {
|
|
7176
|
+
id: `collection_${col.slug}`,
|
|
7177
|
+
type: "collection",
|
|
7178
|
+
slug: col.slug,
|
|
7179
|
+
collection: col.slug,
|
|
7180
|
+
label: col.labels?.plural || col.slug,
|
|
7181
|
+
icon: col.admin?.icon || "Folder",
|
|
7182
|
+
group: groupName,
|
|
7183
|
+
order: col?.admin?.order ?? 100,
|
|
7184
|
+
views: combinedViews,
|
|
7185
|
+
access: col.access?.read
|
|
7186
|
+
});
|
|
7187
|
+
}
|
|
7188
|
+
for (const gl of globals) {
|
|
7189
|
+
if (mentionedGlobals.has(gl.slug)) continue;
|
|
7190
|
+
const groupName = "Configuration";
|
|
7191
|
+
registerItem(groupName, {
|
|
7192
|
+
id: `global_${gl.slug}`,
|
|
7193
|
+
type: "global",
|
|
7194
|
+
slug: gl.slug,
|
|
7195
|
+
global: gl.slug,
|
|
7196
|
+
label: gl.label || gl.slug,
|
|
7197
|
+
icon: "Settings",
|
|
7198
|
+
group: groupName,
|
|
7199
|
+
order: 100,
|
|
7200
|
+
views: []
|
|
7201
|
+
});
|
|
7202
|
+
}
|
|
7203
|
+
const sortAndSpliceItems = (items) => {
|
|
7204
|
+
const sorted = [...items].sort((a, b) => a.order - b.order);
|
|
7205
|
+
const explicitMap = /* @__PURE__ */ new Map();
|
|
7206
|
+
for (const opt of explicitNav) {
|
|
7207
|
+
if (opt.slug) explicitMap.set(opt.slug, opt);
|
|
7208
|
+
if (opt.collection) explicitMap.set(opt.collection, opt);
|
|
7209
|
+
if (opt.global) explicitMap.set(opt.global, opt);
|
|
7210
|
+
}
|
|
7211
|
+
for (const opt of explicitNav) {
|
|
7212
|
+
const itemKey = opt.slug || opt.collection || opt.global;
|
|
7213
|
+
if (!itemKey) continue;
|
|
7214
|
+
if (opt.after) {
|
|
7215
|
+
const itemIdx = sorted.findIndex((i) => i.slug === itemKey);
|
|
7216
|
+
const targetIdx = sorted.findIndex((i) => i.slug === opt.after);
|
|
7217
|
+
if (itemIdx !== -1 && targetIdx !== -1 && itemIdx !== targetIdx) {
|
|
7218
|
+
const [moved] = sorted.splice(itemIdx, 1);
|
|
7219
|
+
const newTargetIdx = sorted.findIndex((i) => i.slug === opt.after);
|
|
7220
|
+
sorted.splice(newTargetIdx + 1, 0, moved);
|
|
7221
|
+
}
|
|
7222
|
+
} else if (opt.before) {
|
|
7223
|
+
const itemIdx = sorted.findIndex((i) => i.slug === itemKey);
|
|
7224
|
+
const targetIdx = sorted.findIndex((i) => i.slug === opt.before);
|
|
7225
|
+
if (itemIdx !== -1 && targetIdx !== -1 && itemIdx !== targetIdx) {
|
|
7226
|
+
const [moved] = sorted.splice(itemIdx, 1);
|
|
7227
|
+
const newTargetIdx = sorted.findIndex((i) => i.slug === opt.before);
|
|
7228
|
+
sorted.splice(newTargetIdx, 0, moved);
|
|
7229
|
+
}
|
|
7230
|
+
} else if (opt.position === "first") {
|
|
7231
|
+
const itemIdx = sorted.findIndex((i) => i.slug === itemKey);
|
|
7232
|
+
if (itemIdx > 0) {
|
|
7233
|
+
const [moved] = sorted.splice(itemIdx, 1);
|
|
7234
|
+
sorted.unshift(moved);
|
|
7235
|
+
}
|
|
7236
|
+
} else if (opt.position === "last") {
|
|
7237
|
+
const itemIdx = sorted.findIndex((i) => i.slug === itemKey);
|
|
7238
|
+
if (itemIdx !== -1 && itemIdx < sorted.length - 1) {
|
|
7239
|
+
const [moved] = sorted.splice(itemIdx, 1);
|
|
7240
|
+
sorted.push(moved);
|
|
7241
|
+
}
|
|
7242
|
+
}
|
|
7243
|
+
}
|
|
7244
|
+
return sorted;
|
|
7245
|
+
};
|
|
7246
|
+
const compiledGroups = [];
|
|
7247
|
+
for (const [groupName, rawItems] of itemsByGroup.entries()) {
|
|
7248
|
+
const meta = groupMetadataMap.get(groupName);
|
|
7249
|
+
const sortedItems = sortAndSpliceItems(rawItems);
|
|
7250
|
+
compiledGroups.push({
|
|
7251
|
+
id: `group_${groupName.toLowerCase().replace(/\s+/g, "_")}`,
|
|
7252
|
+
name: groupName,
|
|
7253
|
+
slug: meta?.slug || groupName.toLowerCase().replace(/\s+/g, "-"),
|
|
7254
|
+
icon: meta?.icon,
|
|
7255
|
+
defaultExpanded: meta?.defaultExpanded ?? true,
|
|
7256
|
+
order: meta?.order ?? 100,
|
|
7257
|
+
items: sortedItems
|
|
7258
|
+
});
|
|
7259
|
+
}
|
|
7260
|
+
compiledGroups.sort((a, b) => a.order - b.order);
|
|
7261
|
+
return {
|
|
7262
|
+
groups: compiledGroups,
|
|
7263
|
+
ungrouped: sortAndSpliceItems(ungroupedItems)
|
|
7264
|
+
};
|
|
7265
|
+
}
|
|
7266
|
+
function pruneNavigationForUser(tree, user) {
|
|
7267
|
+
const userRoles = /* @__PURE__ */ new Set();
|
|
7268
|
+
if (user?.role) userRoles.add(user.role);
|
|
7269
|
+
if (Array.isArray(user?.roles)) {
|
|
7270
|
+
for (const r of user.roles) userRoles.add(r);
|
|
7271
|
+
}
|
|
7272
|
+
const isAllowed = (item) => {
|
|
7273
|
+
if (!item.access) return true;
|
|
7274
|
+
if (Array.isArray(item.access)) {
|
|
7275
|
+
if (item.access.length === 0) return true;
|
|
7276
|
+
return item.access.some((role) => userRoles.has(role));
|
|
7277
|
+
}
|
|
7278
|
+
return true;
|
|
7279
|
+
};
|
|
7280
|
+
const prunedGroups = [];
|
|
7281
|
+
for (const group of tree.groups) {
|
|
7282
|
+
const visibleItems = group.items.filter(isAllowed);
|
|
7283
|
+
if (visibleItems.length > 0) {
|
|
7284
|
+
prunedGroups.push({
|
|
7285
|
+
...group,
|
|
7286
|
+
items: visibleItems
|
|
7287
|
+
});
|
|
7288
|
+
}
|
|
7289
|
+
}
|
|
7290
|
+
return {
|
|
7291
|
+
groups: prunedGroups,
|
|
7292
|
+
ungrouped: tree.ungrouped.filter(isAllowed)
|
|
7293
|
+
};
|
|
7294
|
+
}
|
|
7295
|
+
|
|
6558
7296
|
// src/index.ts
|
|
6559
7297
|
var import_zod = require("zod");
|
|
6560
7298
|
function defineCollection(config) {
|
|
@@ -6619,9 +7357,14 @@ function defineTab(args) {
|
|
|
6619
7357
|
AI_CHUNKS_COLLECTION,
|
|
6620
7358
|
AI_MESSAGES_COLLECTION,
|
|
6621
7359
|
AI_THREADS_COLLECTION,
|
|
7360
|
+
BASE62_ALPHABET,
|
|
6622
7361
|
BUILTIN_JEXL_HELPERS,
|
|
7362
|
+
CROCKFORD_BASE32,
|
|
7363
|
+
CURRENT_NAV_PREFERENCES_VERSION,
|
|
6623
7364
|
ConfigValidationError,
|
|
6624
7365
|
ConflictError,
|
|
7366
|
+
DEFAULT_USER_NAV_PREFERENCES,
|
|
7367
|
+
DuplicateKeyError,
|
|
6625
7368
|
DyrectedAIError,
|
|
6626
7369
|
DyrectedError,
|
|
6627
7370
|
FieldConditionBuilder,
|
|
@@ -6629,9 +7372,11 @@ function defineTab(args) {
|
|
|
6629
7372
|
LIFECYCLE_EVENTS_COLLECTION,
|
|
6630
7373
|
LIFECYCLE_EVENT_NAMES,
|
|
6631
7374
|
MatchBuilder,
|
|
7375
|
+
NANOID_ALPHABET,
|
|
6632
7376
|
NON_NEGOTIABLE_CREDENTIAL_FIELDS,
|
|
6633
7377
|
NotFoundError,
|
|
6634
7378
|
PII_REGEX_PATTERNS,
|
|
7379
|
+
RESERVED_NAVIGATION_SLUGS,
|
|
6635
7380
|
ValidationError,
|
|
6636
7381
|
WORKFLOW_HISTORY_COLLECTION,
|
|
6637
7382
|
abs,
|
|
@@ -6642,6 +7387,7 @@ function defineTab(args) {
|
|
|
6642
7387
|
assertValidDeclarativeHookExpression,
|
|
6643
7388
|
assertValidDeclarativeHookResult,
|
|
6644
7389
|
assertValidDeclarativeHooksInConfig,
|
|
7390
|
+
assertValidNavigationSlugs,
|
|
6645
7391
|
assertValidPreviewUrlsInConfig,
|
|
6646
7392
|
availableWorkflowTransitions,
|
|
6647
7393
|
buildSqlOrderBy,
|
|
@@ -6656,6 +7402,7 @@ function defineTab(args) {
|
|
|
6656
7402
|
collectDeclarativeHookValidationIssues,
|
|
6657
7403
|
collectPreviewUrlValidationIssues,
|
|
6658
7404
|
compact,
|
|
7405
|
+
compileNavigation,
|
|
6659
7406
|
count,
|
|
6660
7407
|
createLifecycleEvent,
|
|
6661
7408
|
createWorkflowDocument,
|
|
@@ -6696,6 +7443,7 @@ function defineTab(args) {
|
|
|
6696
7443
|
defineTimeField,
|
|
6697
7444
|
defineUrlField,
|
|
6698
7445
|
defineView,
|
|
7446
|
+
defineWorkspace,
|
|
6699
7447
|
diffDays,
|
|
6700
7448
|
dispatchLifecycleEvent,
|
|
6701
7449
|
dispatchPendingLifecycleEvents,
|
|
@@ -6724,6 +7472,8 @@ function defineTab(args) {
|
|
|
6724
7472
|
formatDate,
|
|
6725
7473
|
formatJexlValue,
|
|
6726
7474
|
generateDefaultDetailSchema,
|
|
7475
|
+
generateDocumentId,
|
|
7476
|
+
generateId,
|
|
6727
7477
|
generateOpenApi,
|
|
6728
7478
|
get,
|
|
6729
7479
|
getAdminAuthCollection,
|
|
@@ -6750,6 +7500,7 @@ function defineTab(args) {
|
|
|
6750
7500
|
materializeWorkflowDocument,
|
|
6751
7501
|
max,
|
|
6752
7502
|
min,
|
|
7503
|
+
nanoid,
|
|
6753
7504
|
normalizeConfig,
|
|
6754
7505
|
normalizeDetailItem,
|
|
6755
7506
|
now,
|
|
@@ -6758,13 +7509,17 @@ function defineTab(args) {
|
|
|
6758
7509
|
parseSort,
|
|
6759
7510
|
parseSqlWhere,
|
|
6760
7511
|
pow,
|
|
7512
|
+
prefixedId,
|
|
7513
|
+
pruneNavigationForUser,
|
|
6761
7514
|
publishedStateName,
|
|
6762
7515
|
publishingWorkflow,
|
|
6763
7516
|
readingTime,
|
|
7517
|
+
reconcileNavigation,
|
|
6764
7518
|
registerJexlHelpers,
|
|
6765
7519
|
replace,
|
|
6766
7520
|
resolveAdminAuthCollection,
|
|
6767
7521
|
resolveAuthorizedSiteId,
|
|
7522
|
+
resolvePrefix,
|
|
6768
7523
|
round,
|
|
6769
7524
|
runCollectionHooks,
|
|
6770
7525
|
sanitizeDocForAI,
|
|
@@ -6778,8 +7533,10 @@ function defineTab(args) {
|
|
|
6778
7533
|
transitionWorkflow,
|
|
6779
7534
|
trim,
|
|
6780
7535
|
truncate,
|
|
7536
|
+
ulid,
|
|
6781
7537
|
unique,
|
|
6782
7538
|
upper,
|
|
7539
|
+
uuid,
|
|
6783
7540
|
validateAdminConditionExpression,
|
|
6784
7541
|
validateDeclarativeAccessExpression,
|
|
6785
7542
|
validateDeclarativeHookExpression,
|