@dyrected/core 2.23.0 → 2.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.js CHANGED
@@ -1782,6 +1782,243 @@ var require_Jexl = __commonJS({
1782
1782
  }
1783
1783
  });
1784
1784
 
1785
+ // src/types/access.ts
1786
+ var init_access = __esm({
1787
+ "src/types/access.ts"() {
1788
+ "use strict";
1789
+ }
1790
+ });
1791
+
1792
+ // src/types/adapters.ts
1793
+ var init_adapters = __esm({
1794
+ "src/types/adapters.ts"() {
1795
+ "use strict";
1796
+ }
1797
+ });
1798
+
1799
+ // src/types/aggregate.ts
1800
+ var init_aggregate = __esm({
1801
+ "src/types/aggregate.ts"() {
1802
+ "use strict";
1803
+ }
1804
+ });
1805
+
1806
+ // src/types/admin.ts
1807
+ var FORM_SHELLS;
1808
+ var init_admin = __esm({
1809
+ "src/types/admin.ts"() {
1810
+ "use strict";
1811
+ FORM_SHELLS = ["full", "header", "none"];
1812
+ }
1813
+ });
1814
+
1815
+ // src/types/admin-auth.ts
1816
+ var init_admin_auth = __esm({
1817
+ "src/types/admin-auth.ts"() {
1818
+ "use strict";
1819
+ }
1820
+ });
1821
+
1822
+ // src/types/app-config.ts
1823
+ var init_app_config = __esm({
1824
+ "src/types/app-config.ts"() {
1825
+ "use strict";
1826
+ }
1827
+ });
1828
+
1829
+ // src/types/documents.ts
1830
+ var init_documents = __esm({
1831
+ "src/types/documents.ts"() {
1832
+ "use strict";
1833
+ }
1834
+ });
1835
+
1836
+ // src/types/hooks.ts
1837
+ var init_hooks = __esm({
1838
+ "src/types/hooks.ts"() {
1839
+ "use strict";
1840
+ }
1841
+ });
1842
+
1843
+ // src/types/request.ts
1844
+ var init_request = __esm({
1845
+ "src/types/request.ts"() {
1846
+ "use strict";
1847
+ }
1848
+ });
1849
+
1850
+ // src/types/schema-config.ts
1851
+ var init_schema_config = __esm({
1852
+ "src/types/schema-config.ts"() {
1853
+ "use strict";
1854
+ }
1855
+ });
1856
+
1857
+ // src/types/schema-core.ts
1858
+ var init_schema_core = __esm({
1859
+ "src/types/schema-core.ts"() {
1860
+ "use strict";
1861
+ }
1862
+ });
1863
+
1864
+ // src/types/schema-inference.ts
1865
+ var init_schema_inference = __esm({
1866
+ "src/types/schema-inference.ts"() {
1867
+ "use strict";
1868
+ }
1869
+ });
1870
+
1871
+ // src/types/workflows.ts
1872
+ var init_workflows = __esm({
1873
+ "src/types/workflows.ts"() {
1874
+ "use strict";
1875
+ }
1876
+ });
1877
+
1878
+ // src/types/tasks.ts
1879
+ var init_tasks = __esm({
1880
+ "src/types/tasks.ts"() {
1881
+ "use strict";
1882
+ }
1883
+ });
1884
+
1885
+ // src/types/detail.ts
1886
+ var init_detail = __esm({
1887
+ "src/types/detail.ts"() {
1888
+ "use strict";
1889
+ }
1890
+ });
1891
+
1892
+ // src/types/views.ts
1893
+ var init_views = __esm({
1894
+ "src/types/views.ts"() {
1895
+ "use strict";
1896
+ }
1897
+ });
1898
+
1899
+ // src/types/ai.ts
1900
+ var ai_exports = {};
1901
+ __export(ai_exports, {
1902
+ AI_ACTIONS_COLLECTION: () => AI_ACTIONS_COLLECTION,
1903
+ AI_AUDIT_COLLECTION: () => AI_AUDIT_COLLECTION,
1904
+ AI_CHUNKS_COLLECTION: () => AI_CHUNKS_COLLECTION,
1905
+ AI_MESSAGES_COLLECTION: () => AI_MESSAGES_COLLECTION,
1906
+ AI_THREADS_COLLECTION: () => AI_THREADS_COLLECTION,
1907
+ isAICollection: () => isAICollection
1908
+ });
1909
+ function isAICollection(slug) {
1910
+ return slug === AI_THREADS_COLLECTION || slug === AI_MESSAGES_COLLECTION || slug === AI_CHUNKS_COLLECTION || slug === AI_ACTIONS_COLLECTION || slug === AI_AUDIT_COLLECTION;
1911
+ }
1912
+ var AI_THREADS_COLLECTION, AI_MESSAGES_COLLECTION, AI_CHUNKS_COLLECTION, AI_ACTIONS_COLLECTION, AI_AUDIT_COLLECTION;
1913
+ var init_ai = __esm({
1914
+ "src/types/ai.ts"() {
1915
+ "use strict";
1916
+ AI_THREADS_COLLECTION = "_dyrected_ai_threads";
1917
+ AI_MESSAGES_COLLECTION = "_dyrected_ai_messages";
1918
+ AI_CHUNKS_COLLECTION = "_dyrected_ai_chunks";
1919
+ AI_ACTIONS_COLLECTION = "_dyrected_ai_actions";
1920
+ AI_AUDIT_COLLECTION = "_dyrected_ai_audit";
1921
+ }
1922
+ });
1923
+
1924
+ // src/types/ai-errors.ts
1925
+ var DyrectedAIError;
1926
+ var init_ai_errors = __esm({
1927
+ "src/types/ai-errors.ts"() {
1928
+ "use strict";
1929
+ DyrectedAIError = class _DyrectedAIError extends Error {
1930
+ code;
1931
+ status;
1932
+ details;
1933
+ constructor(code, message, status = 500, details) {
1934
+ super(message);
1935
+ this.name = "DyrectedAIError";
1936
+ this.code = code;
1937
+ this.status = status;
1938
+ this.details = details;
1939
+ Object.setPrototypeOf(this, _DyrectedAIError.prototype);
1940
+ }
1941
+ toJSON() {
1942
+ return {
1943
+ error: true,
1944
+ code: this.code,
1945
+ message: this.message,
1946
+ status: this.status,
1947
+ details: this.details
1948
+ };
1949
+ }
1950
+ };
1951
+ }
1952
+ });
1953
+
1954
+ // src/types/readonly-fix.ts
1955
+ var init_readonly_fix = __esm({
1956
+ "src/types/readonly-fix.ts"() {
1957
+ "use strict";
1958
+ }
1959
+ });
1960
+
1961
+ // src/types/navigation.ts
1962
+ var CURRENT_NAV_PREFERENCES_VERSION, DEFAULT_USER_NAV_PREFERENCES;
1963
+ var init_navigation = __esm({
1964
+ "src/types/navigation.ts"() {
1965
+ "use strict";
1966
+ CURRENT_NAV_PREFERENCES_VERSION = 1;
1967
+ DEFAULT_USER_NAV_PREFERENCES = {
1968
+ _version: CURRENT_NAV_PREFERENCES_VERSION,
1969
+ pinned: [],
1970
+ hidden: [],
1971
+ groupOrder: [],
1972
+ itemOrder: {},
1973
+ groups: [],
1974
+ items: []
1975
+ };
1976
+ }
1977
+ });
1978
+
1979
+ // src/types/email.ts
1980
+ var init_email = __esm({
1981
+ "src/types/email.ts"() {
1982
+ "use strict";
1983
+ }
1984
+ });
1985
+
1986
+ // src/types/pages.ts
1987
+ var init_pages = __esm({
1988
+ "src/types/pages.ts"() {
1989
+ "use strict";
1990
+ }
1991
+ });
1992
+
1993
+ // src/types/index.ts
1994
+ var init_types = __esm({
1995
+ "src/types/index.ts"() {
1996
+ "use strict";
1997
+ init_access();
1998
+ init_adapters();
1999
+ init_aggregate();
2000
+ init_admin();
2001
+ init_admin_auth();
2002
+ init_app_config();
2003
+ init_documents();
2004
+ init_hooks();
2005
+ init_request();
2006
+ init_schema_config();
2007
+ init_schema_core();
2008
+ init_schema_inference();
2009
+ init_workflows();
2010
+ init_tasks();
2011
+ init_detail();
2012
+ init_views();
2013
+ init_ai();
2014
+ init_ai_errors();
2015
+ init_readonly_fix();
2016
+ init_navigation();
2017
+ init_email();
2018
+ init_pages();
2019
+ }
2020
+ });
2021
+
1785
2022
  // src/utils/jexl-helpers.ts
1786
2023
  function slugify(val) {
1787
2024
  if (val === void 0 || val === null) return "";
@@ -2585,6 +2822,52 @@ function collectPreviewUrlValidationIssues(config) {
2585
2822
  });
2586
2823
  return issues;
2587
2824
  }
2825
+ function collectFormComponentIssues(components, path, surface, keys, issues) {
2826
+ if (!isPlainObject(components)) return;
2827
+ for (const key of keys) {
2828
+ const value = components[key];
2829
+ if (value === void 0) continue;
2830
+ if (typeof value !== "string" || value.length === 0) {
2831
+ issues.push({
2832
+ path: `${path}.admin.components.${key}`,
2833
+ surface,
2834
+ message: `\`${key}\` must be the registry key of a component, such as "check_ins.scanForm".`,
2835
+ expression: String(value)
2836
+ });
2837
+ }
2838
+ }
2839
+ const shell = components.formShell;
2840
+ if (shell !== void 0 && !FORM_SHELLS.includes(shell)) {
2841
+ issues.push({
2842
+ path: `${path}.admin.components.formShell`,
2843
+ surface,
2844
+ message: `Unknown formShell "${String(shell)}". Use ${FORM_SHELLS.map((value) => `"${value}"`).join(", ")}.`,
2845
+ expression: String(shell)
2846
+ });
2847
+ }
2848
+ }
2849
+ function collectAdminComponentsValidationIssues(config) {
2850
+ const issues = [];
2851
+ config.collections.forEach((collection, index) => {
2852
+ collectFormComponentIssues(
2853
+ collection.admin?.components,
2854
+ collectionSegment(collection, index),
2855
+ "collection.admin.components",
2856
+ FORM_COMPONENT_KEYS,
2857
+ issues
2858
+ );
2859
+ });
2860
+ config.globals?.forEach((global, index) => {
2861
+ collectFormComponentIssues(
2862
+ global.admin?.components,
2863
+ globalSegment(global, index),
2864
+ "global.admin.components",
2865
+ GLOBAL_FORM_COMPONENT_KEYS,
2866
+ issues
2867
+ );
2868
+ });
2869
+ return issues;
2870
+ }
2588
2871
  function assertValidAdminConditionsInConfig(config, source = "config") {
2589
2872
  const diagnostics = collectAdminConditionValidationIssues(config).map((issue) => ({
2590
2873
  severity: "error",
@@ -2642,7 +2925,15 @@ function collectConfigDiagnostics(config) {
2642
2925
  message: issue.message,
2643
2926
  expression: issue.expression
2644
2927
  }));
2645
- return [...hookIssues, ...accessIssues, ...adminConditionIssues, ...previewUrlIssues];
2928
+ const adminComponentIssues = collectAdminComponentsValidationIssues(config).map((issue) => ({
2929
+ severity: "error",
2930
+ source: "adminComponents",
2931
+ path: issue.path,
2932
+ surface: issue.surface,
2933
+ message: issue.message,
2934
+ expression: issue.expression
2935
+ }));
2936
+ return [...hookIssues, ...accessIssues, ...adminConditionIssues, ...previewUrlIssues, ...adminComponentIssues];
2646
2937
  }
2647
2938
  function formatConfigDiagnostics(source, diagnostics, options = {}) {
2648
2939
  const color = options.color ?? false;
@@ -2682,11 +2973,12 @@ function assertValidDeclarativeAccessInConfig(config, source = "config") {
2682
2973
  if (diagnostics.length === 0) return;
2683
2974
  throw new ConfigValidationError(source, diagnostics);
2684
2975
  }
2685
- var import_jexl3, SURFACE_ROOTS, ACCESS_ROOTS, ADMIN_CONDITION_RESERVED_ROOTS, PREVIEW_URL_RESERVED_ROOTS, COMPILE_CACHE, ConfigValidationError;
2976
+ var import_jexl3, SURFACE_ROOTS, ACCESS_ROOTS, ADMIN_CONDITION_RESERVED_ROOTS, PREVIEW_URL_RESERVED_ROOTS, COMPILE_CACHE, FORM_COMPONENT_KEYS, GLOBAL_FORM_COMPONENT_KEYS, ConfigValidationError;
2686
2977
  var init_declarative_hooks = __esm({
2687
2978
  "src/utils/declarative-hooks.ts"() {
2688
2979
  "use strict";
2689
2980
  import_jexl3 = __toESM(require_Jexl(), 1);
2981
+ init_types();
2690
2982
  init_jexl_helpers();
2691
2983
  registerJexlHelpers(import_jexl3.default);
2692
2984
  SURFACE_ROOTS = {
@@ -2703,6 +2995,8 @@ var init_declarative_hooks = __esm({
2703
2995
  ADMIN_CONDITION_RESERVED_ROOTS = ["data", "siblingData", "user", "id", ...BUILTIN_JEXL_HELPERS];
2704
2996
  PREVIEW_URL_RESERVED_ROOTS = ["siteUrl", "id", ...BUILTIN_JEXL_HELPERS];
2705
2997
  COMPILE_CACHE = /* @__PURE__ */ new Map();
2998
+ FORM_COMPONENT_KEYS = ["createForm", "editForm", "form"];
2999
+ GLOBAL_FORM_COMPONENT_KEYS = ["editForm", "form"];
2706
3000
  ConfigValidationError = class extends Error {
2707
3001
  diagnostics;
2708
3002
  source;
@@ -2915,7 +3209,7 @@ async function executeFieldAfterRead(fields, doc, user, db) {
2915
3209
  return result;
2916
3210
  }
2917
3211
  var import_jexl4;
2918
- var init_hooks = __esm({
3212
+ var init_hooks2 = __esm({
2919
3213
  "src/utils/hooks.ts"() {
2920
3214
  "use strict";
2921
3215
  import_jexl4 = __toESM(require_Jexl(), 1);
@@ -2992,7 +3286,7 @@ async function isAccessAllowed(config, access, args) {
2992
3286
  if (result === void 0) return true;
2993
3287
  return typeof result === "boolean" ? result : !!result;
2994
3288
  }
2995
- var init_access = __esm({
3289
+ var init_access2 = __esm({
2996
3290
  "src/auth/access.ts"() {
2997
3291
  "use strict";
2998
3292
  init_jexl();
@@ -3172,7 +3466,7 @@ var TRASH_COLLECTION, INTERNAL_SYSTEM_COLLECTIONS, TRASH_COLLECTION_CONFIG;
3172
3466
  var init_trash = __esm({
3173
3467
  "src/trash.ts"() {
3174
3468
  "use strict";
3175
- init_hooks();
3469
+ init_hooks2();
3176
3470
  TRASH_COLLECTION = "__trash";
3177
3471
  INTERNAL_SYSTEM_COLLECTIONS = /* @__PURE__ */ new Set([
3178
3472
  "__audit",
@@ -3398,32 +3692,7 @@ function mergeWhereConstraint(where, constraint) {
3398
3692
  var init_access_control = __esm({
3399
3693
  "src/utils/access-control.ts"() {
3400
3694
  "use strict";
3401
- init_access();
3402
- }
3403
- });
3404
-
3405
- // src/types/ai.ts
3406
- var ai_exports = {};
3407
- __export(ai_exports, {
3408
- AI_ACTIONS_COLLECTION: () => AI_ACTIONS_COLLECTION,
3409
- AI_AUDIT_COLLECTION: () => AI_AUDIT_COLLECTION,
3410
- AI_CHUNKS_COLLECTION: () => AI_CHUNKS_COLLECTION,
3411
- AI_MESSAGES_COLLECTION: () => AI_MESSAGES_COLLECTION,
3412
- AI_THREADS_COLLECTION: () => AI_THREADS_COLLECTION,
3413
- isAICollection: () => isAICollection
3414
- });
3415
- function isAICollection(slug) {
3416
- return slug === AI_THREADS_COLLECTION || slug === AI_MESSAGES_COLLECTION || slug === AI_CHUNKS_COLLECTION || slug === AI_ACTIONS_COLLECTION || slug === AI_AUDIT_COLLECTION;
3417
- }
3418
- var AI_THREADS_COLLECTION, AI_MESSAGES_COLLECTION, AI_CHUNKS_COLLECTION, AI_ACTIONS_COLLECTION, AI_AUDIT_COLLECTION;
3419
- var init_ai = __esm({
3420
- "src/types/ai.ts"() {
3421
- "use strict";
3422
- AI_THREADS_COLLECTION = "_dyrected_ai_threads";
3423
- AI_MESSAGES_COLLECTION = "_dyrected_ai_messages";
3424
- AI_CHUNKS_COLLECTION = "_dyrected_ai_chunks";
3425
- AI_ACTIONS_COLLECTION = "_dyrected_ai_actions";
3426
- AI_AUDIT_COLLECTION = "_dyrected_ai_audit";
3695
+ init_access2();
3427
3696
  }
3428
3697
  });
3429
3698
 
@@ -3972,7 +4241,7 @@ var init_rag_service = __esm({
3972
4241
  "src/services/rag/rag.service.ts"() {
3973
4242
  "use strict";
3974
4243
  init_ai();
3975
- init_access();
4244
+ init_access2();
3976
4245
  init_normalizer();
3977
4246
  init_chunker();
3978
4247
  init_embedding_service();
@@ -5409,7 +5678,7 @@ var init_ai_tools = __esm({
5409
5678
  "src/services/ai-tools.ts"() {
5410
5679
  "use strict";
5411
5680
  init_ai();
5412
- init_access();
5681
+ init_access2();
5413
5682
  init_access_control();
5414
5683
  init_rag_service();
5415
5684
  init_ai_pii();
@@ -6441,7 +6710,7 @@ function createSessionId() {
6441
6710
  }
6442
6711
 
6443
6712
  // src/controllers/collection.controller.ts
6444
- init_hooks();
6713
+ init_hooks2();
6445
6714
 
6446
6715
  // src/utils/readonly-db.ts
6447
6716
  var WRITE_METHODS = ["create", "update", "delete", "updateGlobal", "execute"];
@@ -6569,7 +6838,7 @@ function generateUniqueUploadFilename(filename) {
6569
6838
  }
6570
6839
 
6571
6840
  // src/controllers/collection.controller.ts
6572
- init_access();
6841
+ init_access2();
6573
6842
 
6574
6843
  // src/utils/admin-auth.ts
6575
6844
  function getAdminAuthCollection(config) {
@@ -6832,19 +7101,8 @@ async function buildCollectionSearchWhere(args) {
6832
7101
  // src/utils/navigation.ts
6833
7102
  init_trash();
6834
7103
 
6835
- // src/types/navigation.ts
6836
- var CURRENT_NAV_PREFERENCES_VERSION = 1;
6837
- var DEFAULT_USER_NAV_PREFERENCES = {
6838
- _version: CURRENT_NAV_PREFERENCES_VERSION,
6839
- pinned: [],
6840
- hidden: [],
6841
- groupOrder: [],
6842
- itemOrder: {},
6843
- groups: [],
6844
- items: []
6845
- };
6846
-
6847
7104
  // src/utils/navigation-reconciler.ts
7105
+ init_navigation();
6848
7106
  var normalizeKey = (val) => (val || "").toLowerCase().replace(/[^a-z0-9]/g, "-");
6849
7107
  function reconcileNavigation(baseTree, prefs, schemas, options) {
6850
7108
  if (!baseTree) {
@@ -7278,7 +7536,7 @@ function compileNavigation(config) {
7278
7536
  order: item.order ?? 100,
7279
7537
  views: [],
7280
7538
  badge: item.badge,
7281
- access: item.access
7539
+ access: item.access || gl?.access?.read
7282
7540
  });
7283
7541
  continue;
7284
7542
  }
@@ -7386,7 +7644,8 @@ function compileNavigation(config) {
7386
7644
  icon: "Settings",
7387
7645
  group: groupName,
7388
7646
  order: 100,
7389
- views: []
7647
+ views: [],
7648
+ access: gl.access?.read
7390
7649
  });
7391
7650
  }
7392
7651
  const mentionedTrash = explicitNav.some((i) => i.trash || i.slug === "trash");
@@ -7469,34 +7728,23 @@ function compileNavigation(config) {
7469
7728
  ungrouped: sortAndSpliceItems(ungroupedItems)
7470
7729
  };
7471
7730
  }
7472
- function pruneNavigationForUser(tree, user) {
7473
- const userRoles = /* @__PURE__ */ new Set();
7474
- if (user?.role) userRoles.add(user.role);
7475
- if (Array.isArray(user?.roles)) {
7476
- for (const r of user.roles) userRoles.add(r);
7477
- }
7478
- const isAllowed = (item) => {
7479
- if (!item.access) return true;
7480
- if (Array.isArray(item.access)) {
7481
- if (item.access.length === 0) return true;
7482
- return item.access.some((role) => userRoles.has(role));
7483
- }
7484
- return true;
7731
+ async function pruneNavigationByAccess(tree, canAccess, canAccessView) {
7732
+ const resolveItem = async (item) => {
7733
+ if (!await canAccess(item)) return null;
7734
+ if (!canAccessView || !item.views?.length) return item;
7735
+ const allowed = await Promise.all(item.views.map((view) => canAccessView(view, item)));
7736
+ const views = item.views.filter((_, i) => allowed[i]);
7737
+ if (views.length === item.views.length) return item;
7738
+ if (views.length === 0 && item.type === "workspace") return null;
7739
+ return { ...item, views };
7485
7740
  };
7486
- const prunedGroups = [];
7741
+ const filterItems = async (items) => (await Promise.all(items.map(resolveItem))).filter((item) => item !== null);
7742
+ const groups = [];
7487
7743
  for (const group of tree.groups) {
7488
- const visibleItems = group.items.filter(isAllowed);
7489
- if (visibleItems.length > 0) {
7490
- prunedGroups.push({
7491
- ...group,
7492
- items: visibleItems
7493
- });
7494
- }
7744
+ const items = await filterItems(group.items);
7745
+ if (items.length > 0) groups.push({ ...group, items });
7495
7746
  }
7496
- return {
7497
- groups: prunedGroups,
7498
- ungrouped: tree.ungrouped.filter(isAllowed)
7499
- };
7747
+ return { groups, ungrouped: await filterItems(tree.ungrouped) };
7500
7748
  }
7501
7749
  function resolveAllCollectionViews(collection, config) {
7502
7750
  const views = [...collection.views ?? []];
@@ -10614,7 +10862,7 @@ var CollectionController = class _CollectionController {
10614
10862
  };
10615
10863
 
10616
10864
  // src/controllers/global.controller.ts
10617
- init_hooks();
10865
+ init_hooks2();
10618
10866
  init_access_control();
10619
10867
  import { HTTPException as HTTPException3 } from "hono/http-exception";
10620
10868
  var GlobalController = class {
@@ -14791,7 +15039,7 @@ var AIController = class {
14791
15039
  const dynamicConfig = await activeConfig.onSchemaFetch(projectId);
14792
15040
  activeConfig = mergeDynamicConfig(activeConfig, dynamicConfig);
14793
15041
  }
14794
- const { isAccessAllowed: isAccessAllowed2 } = await Promise.resolve().then(() => (init_access(), access_exports));
15042
+ const { isAccessAllowed: isAccessAllowed2 } = await Promise.resolve().then(() => (init_access2(), access_exports));
14795
15043
  const { validatePayloadAgainstFields: validatePayloadAgainstFields2 } = await Promise.resolve().then(() => (init_ai_tools(), ai_tools_exports));
14796
15044
  if (action.targetCollection) {
14797
15045
  const col = activeConfig.collections?.find((c2) => c2.slug === action.targetCollection);
@@ -15166,31 +15414,8 @@ function optionalAuth(config) {
15166
15414
  };
15167
15415
  }
15168
15416
 
15169
- // src/types/ai-errors.ts
15170
- var DyrectedAIError = class _DyrectedAIError extends Error {
15171
- code;
15172
- status;
15173
- details;
15174
- constructor(code, message, status = 500, details) {
15175
- super(message);
15176
- this.name = "DyrectedAIError";
15177
- this.code = code;
15178
- this.status = status;
15179
- this.details = details;
15180
- Object.setPrototypeOf(this, _DyrectedAIError.prototype);
15181
- }
15182
- toJSON() {
15183
- return {
15184
- error: true,
15185
- code: this.code,
15186
- message: this.message,
15187
- status: this.status,
15188
- details: this.details
15189
- };
15190
- }
15191
- };
15192
-
15193
15417
  // src/middleware/ai-rate-limit.ts
15418
+ init_ai_errors();
15194
15419
  var InMemoryRateLimitStore = class {
15195
15420
  windows = /* @__PURE__ */ new Map();
15196
15421
  constructor() {
@@ -16649,6 +16874,7 @@ function getSwaggerHtml(specUrl) {
16649
16874
  }
16650
16875
 
16651
16876
  // src/router.ts
16877
+ init_access2();
16652
16878
  init_access_control();
16653
16879
  init_trash();
16654
16880
  init_declarative_hooks();
@@ -16878,6 +17104,20 @@ function registerRoutes(app, config) {
16878
17104
  }
16879
17105
  return resolveBooleanAccess(requestConfig, access, accessArgs);
16880
17106
  };
17107
+ const filterReadableViews = async (views) => {
17108
+ const readable = await Promise.all(
17109
+ views.map(async (view) => {
17110
+ if (view?.access?.read === void 0) return true;
17111
+ try {
17112
+ const result = await resolveAccess(requestConfig, view.access.read, accessArgs);
17113
+ return result === void 0 || result !== false;
17114
+ } catch {
17115
+ return false;
17116
+ }
17117
+ })
17118
+ );
17119
+ return views.filter((_, i) => readable[i]);
17120
+ };
16881
17121
  const filteredCollections = await Promise.all(
16882
17122
  collections.filter((col) => !INTERNAL_SYSTEM_COLLECTIONS.has(col.slug) && (!siteId || col.shared || !col.siteId || col.siteId === siteId)).map(async (col) => ({
16883
17123
  slug: col.slug,
@@ -16934,7 +17174,9 @@ function registerRoutes(app, config) {
16934
17174
  audit: !!col.audit,
16935
17175
  drafts: !!col.drafts,
16936
17176
  defaultView: col.defaultView ?? col.admin?.defaultView,
16937
- views: await Promise.all((col.views || []).map((view) => serializeViewForApi(view, serializeAccess))),
17177
+ views: await Promise.all(
17178
+ (await filterReadableViews(col.views || [])).map((view) => serializeViewForApi(view, serializeAccess))
17179
+ ),
16938
17180
  actions: await serializeActionsForApi(col.actions, serializeAccess),
16939
17181
  admin: col.admin,
16940
17182
  detail: serializeDetailForApi(col.detail),
@@ -17402,10 +17644,29 @@ function registerRoutes(app, config) {
17402
17644
  });
17403
17645
  return c.json({ success: true });
17404
17646
  });
17405
- app.get("/api/admin/navigation", optionalAuth(config), async (c) => {
17647
+ const createNavAccessChecker = (c) => {
17406
17648
  const user = c.get("user");
17649
+ const roles = /* @__PURE__ */ new Set([...user?.role ? [user.role] : [], ...Array.isArray(user?.roles) ? user.roles : []]);
17650
+ const args = { user, req: toHookRequestContext(c.req) };
17651
+ const allows = async (rule) => {
17652
+ if (rule === void 0 || rule === null) return true;
17653
+ if (Array.isArray(rule)) return rule.length === 0 || rule.some((r) => roles.has(r));
17654
+ try {
17655
+ const result = await resolveAccess(config, rule, args);
17656
+ return result === void 0 || result !== false;
17657
+ } catch {
17658
+ return false;
17659
+ }
17660
+ };
17661
+ return {
17662
+ canAccess: (item) => allows(item.access),
17663
+ canAccessView: (view) => allows(view.access?.read)
17664
+ };
17665
+ };
17666
+ app.get("/api/admin/navigation", optionalAuth(config), async (c) => {
17407
17667
  const compiled = compileNavigation(config);
17408
- const pruned = pruneNavigationForUser(compiled, user);
17668
+ const { canAccess, canAccessView } = createNavAccessChecker(c);
17669
+ const pruned = await pruneNavigationByAccess(compiled, canAccess, canAccessView);
17409
17670
  return c.json(pruned);
17410
17671
  });
17411
17672
  app.on(["GET", "POST"], "/api/admin/navigation/badges", optionalAuth(config), async (c) => {
@@ -17461,12 +17722,17 @@ function registerRoutes(app, config) {
17461
17722
  ...(reconciled.groups || []).flatMap((g) => g.items || [])
17462
17723
  ];
17463
17724
  } else {
17464
- const pruned = pruneNavigationForUser(compiled, user);
17725
+ const pruned = await pruneNavigationByAccess(compiled, createNavAccessChecker(c).canAccess);
17465
17726
  allItems = [
17466
17727
  ...pruned.ungrouped,
17467
17728
  ...pruned.groups.flatMap((g) => g.items)
17468
17729
  ];
17469
17730
  }
17731
+ if (userNavPrefs) {
17732
+ const { canAccess } = createNavAccessChecker(c);
17733
+ const allowed = await Promise.all(allItems.map((item) => canAccess(item)));
17734
+ allItems = allItems.filter((_, i) => allowed[i]);
17735
+ }
17470
17736
  const badges = {};
17471
17737
  const requestsByCollection = /* @__PURE__ */ new Map();
17472
17738
  let reqCounter = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dyrected/core",
3
- "version": "2.23.0",
3
+ "version": "2.24.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",