@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.cjs CHANGED
@@ -1784,6 +1784,243 @@ var require_Jexl = __commonJS({
1784
1784
  }
1785
1785
  });
1786
1786
 
1787
+ // src/types/access.ts
1788
+ var init_access = __esm({
1789
+ "src/types/access.ts"() {
1790
+ "use strict";
1791
+ }
1792
+ });
1793
+
1794
+ // src/types/adapters.ts
1795
+ var init_adapters = __esm({
1796
+ "src/types/adapters.ts"() {
1797
+ "use strict";
1798
+ }
1799
+ });
1800
+
1801
+ // src/types/aggregate.ts
1802
+ var init_aggregate = __esm({
1803
+ "src/types/aggregate.ts"() {
1804
+ "use strict";
1805
+ }
1806
+ });
1807
+
1808
+ // src/types/admin.ts
1809
+ var FORM_SHELLS;
1810
+ var init_admin = __esm({
1811
+ "src/types/admin.ts"() {
1812
+ "use strict";
1813
+ FORM_SHELLS = ["full", "header", "none"];
1814
+ }
1815
+ });
1816
+
1817
+ // src/types/admin-auth.ts
1818
+ var init_admin_auth = __esm({
1819
+ "src/types/admin-auth.ts"() {
1820
+ "use strict";
1821
+ }
1822
+ });
1823
+
1824
+ // src/types/app-config.ts
1825
+ var init_app_config = __esm({
1826
+ "src/types/app-config.ts"() {
1827
+ "use strict";
1828
+ }
1829
+ });
1830
+
1831
+ // src/types/documents.ts
1832
+ var init_documents = __esm({
1833
+ "src/types/documents.ts"() {
1834
+ "use strict";
1835
+ }
1836
+ });
1837
+
1838
+ // src/types/hooks.ts
1839
+ var init_hooks = __esm({
1840
+ "src/types/hooks.ts"() {
1841
+ "use strict";
1842
+ }
1843
+ });
1844
+
1845
+ // src/types/request.ts
1846
+ var init_request = __esm({
1847
+ "src/types/request.ts"() {
1848
+ "use strict";
1849
+ }
1850
+ });
1851
+
1852
+ // src/types/schema-config.ts
1853
+ var init_schema_config = __esm({
1854
+ "src/types/schema-config.ts"() {
1855
+ "use strict";
1856
+ }
1857
+ });
1858
+
1859
+ // src/types/schema-core.ts
1860
+ var init_schema_core = __esm({
1861
+ "src/types/schema-core.ts"() {
1862
+ "use strict";
1863
+ }
1864
+ });
1865
+
1866
+ // src/types/schema-inference.ts
1867
+ var init_schema_inference = __esm({
1868
+ "src/types/schema-inference.ts"() {
1869
+ "use strict";
1870
+ }
1871
+ });
1872
+
1873
+ // src/types/workflows.ts
1874
+ var init_workflows = __esm({
1875
+ "src/types/workflows.ts"() {
1876
+ "use strict";
1877
+ }
1878
+ });
1879
+
1880
+ // src/types/tasks.ts
1881
+ var init_tasks = __esm({
1882
+ "src/types/tasks.ts"() {
1883
+ "use strict";
1884
+ }
1885
+ });
1886
+
1887
+ // src/types/detail.ts
1888
+ var init_detail = __esm({
1889
+ "src/types/detail.ts"() {
1890
+ "use strict";
1891
+ }
1892
+ });
1893
+
1894
+ // src/types/views.ts
1895
+ var init_views = __esm({
1896
+ "src/types/views.ts"() {
1897
+ "use strict";
1898
+ }
1899
+ });
1900
+
1901
+ // src/types/ai.ts
1902
+ var ai_exports = {};
1903
+ __export(ai_exports, {
1904
+ AI_ACTIONS_COLLECTION: () => AI_ACTIONS_COLLECTION,
1905
+ AI_AUDIT_COLLECTION: () => AI_AUDIT_COLLECTION,
1906
+ AI_CHUNKS_COLLECTION: () => AI_CHUNKS_COLLECTION,
1907
+ AI_MESSAGES_COLLECTION: () => AI_MESSAGES_COLLECTION,
1908
+ AI_THREADS_COLLECTION: () => AI_THREADS_COLLECTION,
1909
+ isAICollection: () => isAICollection
1910
+ });
1911
+ function isAICollection(slug) {
1912
+ return slug === AI_THREADS_COLLECTION || slug === AI_MESSAGES_COLLECTION || slug === AI_CHUNKS_COLLECTION || slug === AI_ACTIONS_COLLECTION || slug === AI_AUDIT_COLLECTION;
1913
+ }
1914
+ var AI_THREADS_COLLECTION, AI_MESSAGES_COLLECTION, AI_CHUNKS_COLLECTION, AI_ACTIONS_COLLECTION, AI_AUDIT_COLLECTION;
1915
+ var init_ai = __esm({
1916
+ "src/types/ai.ts"() {
1917
+ "use strict";
1918
+ AI_THREADS_COLLECTION = "_dyrected_ai_threads";
1919
+ AI_MESSAGES_COLLECTION = "_dyrected_ai_messages";
1920
+ AI_CHUNKS_COLLECTION = "_dyrected_ai_chunks";
1921
+ AI_ACTIONS_COLLECTION = "_dyrected_ai_actions";
1922
+ AI_AUDIT_COLLECTION = "_dyrected_ai_audit";
1923
+ }
1924
+ });
1925
+
1926
+ // src/types/ai-errors.ts
1927
+ var DyrectedAIError;
1928
+ var init_ai_errors = __esm({
1929
+ "src/types/ai-errors.ts"() {
1930
+ "use strict";
1931
+ DyrectedAIError = class _DyrectedAIError extends Error {
1932
+ code;
1933
+ status;
1934
+ details;
1935
+ constructor(code, message, status = 500, details) {
1936
+ super(message);
1937
+ this.name = "DyrectedAIError";
1938
+ this.code = code;
1939
+ this.status = status;
1940
+ this.details = details;
1941
+ Object.setPrototypeOf(this, _DyrectedAIError.prototype);
1942
+ }
1943
+ toJSON() {
1944
+ return {
1945
+ error: true,
1946
+ code: this.code,
1947
+ message: this.message,
1948
+ status: this.status,
1949
+ details: this.details
1950
+ };
1951
+ }
1952
+ };
1953
+ }
1954
+ });
1955
+
1956
+ // src/types/readonly-fix.ts
1957
+ var init_readonly_fix = __esm({
1958
+ "src/types/readonly-fix.ts"() {
1959
+ "use strict";
1960
+ }
1961
+ });
1962
+
1963
+ // src/types/navigation.ts
1964
+ var CURRENT_NAV_PREFERENCES_VERSION, DEFAULT_USER_NAV_PREFERENCES;
1965
+ var init_navigation = __esm({
1966
+ "src/types/navigation.ts"() {
1967
+ "use strict";
1968
+ CURRENT_NAV_PREFERENCES_VERSION = 1;
1969
+ DEFAULT_USER_NAV_PREFERENCES = {
1970
+ _version: CURRENT_NAV_PREFERENCES_VERSION,
1971
+ pinned: [],
1972
+ hidden: [],
1973
+ groupOrder: [],
1974
+ itemOrder: {},
1975
+ groups: [],
1976
+ items: []
1977
+ };
1978
+ }
1979
+ });
1980
+
1981
+ // src/types/email.ts
1982
+ var init_email = __esm({
1983
+ "src/types/email.ts"() {
1984
+ "use strict";
1985
+ }
1986
+ });
1987
+
1988
+ // src/types/pages.ts
1989
+ var init_pages = __esm({
1990
+ "src/types/pages.ts"() {
1991
+ "use strict";
1992
+ }
1993
+ });
1994
+
1995
+ // src/types/index.ts
1996
+ var init_types = __esm({
1997
+ "src/types/index.ts"() {
1998
+ "use strict";
1999
+ init_access();
2000
+ init_adapters();
2001
+ init_aggregate();
2002
+ init_admin();
2003
+ init_admin_auth();
2004
+ init_app_config();
2005
+ init_documents();
2006
+ init_hooks();
2007
+ init_request();
2008
+ init_schema_config();
2009
+ init_schema_core();
2010
+ init_schema_inference();
2011
+ init_workflows();
2012
+ init_tasks();
2013
+ init_detail();
2014
+ init_views();
2015
+ init_ai();
2016
+ init_ai_errors();
2017
+ init_readonly_fix();
2018
+ init_navigation();
2019
+ init_email();
2020
+ init_pages();
2021
+ }
2022
+ });
2023
+
1787
2024
  // src/utils/jexl-helpers.ts
1788
2025
  function slugify(val) {
1789
2026
  if (val === void 0 || val === null) return "";
@@ -2587,6 +2824,52 @@ function collectPreviewUrlValidationIssues(config) {
2587
2824
  });
2588
2825
  return issues;
2589
2826
  }
2827
+ function collectFormComponentIssues(components, path, surface, keys, issues) {
2828
+ if (!isPlainObject(components)) return;
2829
+ for (const key of keys) {
2830
+ const value = components[key];
2831
+ if (value === void 0) continue;
2832
+ if (typeof value !== "string" || value.length === 0) {
2833
+ issues.push({
2834
+ path: `${path}.admin.components.${key}`,
2835
+ surface,
2836
+ message: `\`${key}\` must be the registry key of a component, such as "check_ins.scanForm".`,
2837
+ expression: String(value)
2838
+ });
2839
+ }
2840
+ }
2841
+ const shell = components.formShell;
2842
+ if (shell !== void 0 && !FORM_SHELLS.includes(shell)) {
2843
+ issues.push({
2844
+ path: `${path}.admin.components.formShell`,
2845
+ surface,
2846
+ message: `Unknown formShell "${String(shell)}". Use ${FORM_SHELLS.map((value) => `"${value}"`).join(", ")}.`,
2847
+ expression: String(shell)
2848
+ });
2849
+ }
2850
+ }
2851
+ function collectAdminComponentsValidationIssues(config) {
2852
+ const issues = [];
2853
+ config.collections.forEach((collection, index) => {
2854
+ collectFormComponentIssues(
2855
+ collection.admin?.components,
2856
+ collectionSegment(collection, index),
2857
+ "collection.admin.components",
2858
+ FORM_COMPONENT_KEYS,
2859
+ issues
2860
+ );
2861
+ });
2862
+ config.globals?.forEach((global, index) => {
2863
+ collectFormComponentIssues(
2864
+ global.admin?.components,
2865
+ globalSegment(global, index),
2866
+ "global.admin.components",
2867
+ GLOBAL_FORM_COMPONENT_KEYS,
2868
+ issues
2869
+ );
2870
+ });
2871
+ return issues;
2872
+ }
2590
2873
  function assertValidAdminConditionsInConfig(config, source = "config") {
2591
2874
  const diagnostics = collectAdminConditionValidationIssues(config).map((issue) => ({
2592
2875
  severity: "error",
@@ -2644,7 +2927,15 @@ function collectConfigDiagnostics(config) {
2644
2927
  message: issue.message,
2645
2928
  expression: issue.expression
2646
2929
  }));
2647
- return [...hookIssues, ...accessIssues, ...adminConditionIssues, ...previewUrlIssues];
2930
+ const adminComponentIssues = collectAdminComponentsValidationIssues(config).map((issue) => ({
2931
+ severity: "error",
2932
+ source: "adminComponents",
2933
+ path: issue.path,
2934
+ surface: issue.surface,
2935
+ message: issue.message,
2936
+ expression: issue.expression
2937
+ }));
2938
+ return [...hookIssues, ...accessIssues, ...adminConditionIssues, ...previewUrlIssues, ...adminComponentIssues];
2648
2939
  }
2649
2940
  function formatConfigDiagnostics(source, diagnostics, options = {}) {
2650
2941
  const color = options.color ?? false;
@@ -2684,11 +2975,12 @@ function assertValidDeclarativeAccessInConfig(config, source = "config") {
2684
2975
  if (diagnostics.length === 0) return;
2685
2976
  throw new ConfigValidationError(source, diagnostics);
2686
2977
  }
2687
- var import_jexl3, SURFACE_ROOTS, ACCESS_ROOTS, ADMIN_CONDITION_RESERVED_ROOTS, PREVIEW_URL_RESERVED_ROOTS, COMPILE_CACHE, ConfigValidationError;
2978
+ 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;
2688
2979
  var init_declarative_hooks = __esm({
2689
2980
  "src/utils/declarative-hooks.ts"() {
2690
2981
  "use strict";
2691
2982
  import_jexl3 = __toESM(require_Jexl(), 1);
2983
+ init_types();
2692
2984
  init_jexl_helpers();
2693
2985
  registerJexlHelpers(import_jexl3.default);
2694
2986
  SURFACE_ROOTS = {
@@ -2705,6 +2997,8 @@ var init_declarative_hooks = __esm({
2705
2997
  ADMIN_CONDITION_RESERVED_ROOTS = ["data", "siblingData", "user", "id", ...BUILTIN_JEXL_HELPERS];
2706
2998
  PREVIEW_URL_RESERVED_ROOTS = ["siteUrl", "id", ...BUILTIN_JEXL_HELPERS];
2707
2999
  COMPILE_CACHE = /* @__PURE__ */ new Map();
3000
+ FORM_COMPONENT_KEYS = ["createForm", "editForm", "form"];
3001
+ GLOBAL_FORM_COMPONENT_KEYS = ["editForm", "form"];
2708
3002
  ConfigValidationError = class extends Error {
2709
3003
  diagnostics;
2710
3004
  source;
@@ -2917,7 +3211,7 @@ async function executeFieldAfterRead(fields, doc, user, db) {
2917
3211
  return result;
2918
3212
  }
2919
3213
  var import_jexl4;
2920
- var init_hooks = __esm({
3214
+ var init_hooks2 = __esm({
2921
3215
  "src/utils/hooks.ts"() {
2922
3216
  "use strict";
2923
3217
  import_jexl4 = __toESM(require_Jexl(), 1);
@@ -2994,7 +3288,7 @@ async function isAccessAllowed(config, access, args) {
2994
3288
  if (result === void 0) return true;
2995
3289
  return typeof result === "boolean" ? result : !!result;
2996
3290
  }
2997
- var init_access = __esm({
3291
+ var init_access2 = __esm({
2998
3292
  "src/auth/access.ts"() {
2999
3293
  "use strict";
3000
3294
  init_jexl();
@@ -3174,7 +3468,7 @@ var TRASH_COLLECTION, INTERNAL_SYSTEM_COLLECTIONS, TRASH_COLLECTION_CONFIG;
3174
3468
  var init_trash = __esm({
3175
3469
  "src/trash.ts"() {
3176
3470
  "use strict";
3177
- init_hooks();
3471
+ init_hooks2();
3178
3472
  TRASH_COLLECTION = "__trash";
3179
3473
  INTERNAL_SYSTEM_COLLECTIONS = /* @__PURE__ */ new Set([
3180
3474
  "__audit",
@@ -3400,32 +3694,7 @@ function mergeWhereConstraint(where, constraint) {
3400
3694
  var init_access_control = __esm({
3401
3695
  "src/utils/access-control.ts"() {
3402
3696
  "use strict";
3403
- init_access();
3404
- }
3405
- });
3406
-
3407
- // src/types/ai.ts
3408
- var ai_exports = {};
3409
- __export(ai_exports, {
3410
- AI_ACTIONS_COLLECTION: () => AI_ACTIONS_COLLECTION,
3411
- AI_AUDIT_COLLECTION: () => AI_AUDIT_COLLECTION,
3412
- AI_CHUNKS_COLLECTION: () => AI_CHUNKS_COLLECTION,
3413
- AI_MESSAGES_COLLECTION: () => AI_MESSAGES_COLLECTION,
3414
- AI_THREADS_COLLECTION: () => AI_THREADS_COLLECTION,
3415
- isAICollection: () => isAICollection
3416
- });
3417
- function isAICollection(slug) {
3418
- return slug === AI_THREADS_COLLECTION || slug === AI_MESSAGES_COLLECTION || slug === AI_CHUNKS_COLLECTION || slug === AI_ACTIONS_COLLECTION || slug === AI_AUDIT_COLLECTION;
3419
- }
3420
- var AI_THREADS_COLLECTION, AI_MESSAGES_COLLECTION, AI_CHUNKS_COLLECTION, AI_ACTIONS_COLLECTION, AI_AUDIT_COLLECTION;
3421
- var init_ai = __esm({
3422
- "src/types/ai.ts"() {
3423
- "use strict";
3424
- AI_THREADS_COLLECTION = "_dyrected_ai_threads";
3425
- AI_MESSAGES_COLLECTION = "_dyrected_ai_messages";
3426
- AI_CHUNKS_COLLECTION = "_dyrected_ai_chunks";
3427
- AI_ACTIONS_COLLECTION = "_dyrected_ai_actions";
3428
- AI_AUDIT_COLLECTION = "_dyrected_ai_audit";
3697
+ init_access2();
3429
3698
  }
3430
3699
  });
3431
3700
 
@@ -3974,7 +4243,7 @@ var init_rag_service = __esm({
3974
4243
  "src/services/rag/rag.service.ts"() {
3975
4244
  "use strict";
3976
4245
  init_ai();
3977
- init_access();
4246
+ init_access2();
3978
4247
  init_normalizer();
3979
4248
  init_chunker();
3980
4249
  init_embedding_service();
@@ -5412,7 +5681,7 @@ var init_ai_tools = __esm({
5412
5681
  import_ai3 = require("ai");
5413
5682
  import_zod = require("zod");
5414
5683
  init_ai();
5415
- init_access();
5684
+ init_access2();
5416
5685
  init_access_control();
5417
5686
  init_rag_service();
5418
5687
  init_ai_pii();
@@ -6511,7 +6780,7 @@ function createSessionId() {
6511
6780
  }
6512
6781
 
6513
6782
  // src/controllers/collection.controller.ts
6514
- init_hooks();
6783
+ init_hooks2();
6515
6784
 
6516
6785
  // src/utils/readonly-db.ts
6517
6786
  var WRITE_METHODS = ["create", "update", "delete", "updateGlobal", "execute"];
@@ -6639,7 +6908,7 @@ function generateUniqueUploadFilename(filename) {
6639
6908
  }
6640
6909
 
6641
6910
  // src/controllers/collection.controller.ts
6642
- init_access();
6911
+ init_access2();
6643
6912
 
6644
6913
  // src/utils/admin-auth.ts
6645
6914
  function getAdminAuthCollection(config) {
@@ -6902,19 +7171,8 @@ async function buildCollectionSearchWhere(args) {
6902
7171
  // src/utils/navigation.ts
6903
7172
  init_trash();
6904
7173
 
6905
- // src/types/navigation.ts
6906
- var CURRENT_NAV_PREFERENCES_VERSION = 1;
6907
- var DEFAULT_USER_NAV_PREFERENCES = {
6908
- _version: CURRENT_NAV_PREFERENCES_VERSION,
6909
- pinned: [],
6910
- hidden: [],
6911
- groupOrder: [],
6912
- itemOrder: {},
6913
- groups: [],
6914
- items: []
6915
- };
6916
-
6917
7174
  // src/utils/navigation-reconciler.ts
7175
+ init_navigation();
6918
7176
  var normalizeKey = (val) => (val || "").toLowerCase().replace(/[^a-z0-9]/g, "-");
6919
7177
  function reconcileNavigation(baseTree, prefs, schemas, options) {
6920
7178
  if (!baseTree) {
@@ -7348,7 +7606,7 @@ function compileNavigation(config) {
7348
7606
  order: item.order ?? 100,
7349
7607
  views: [],
7350
7608
  badge: item.badge,
7351
- access: item.access
7609
+ access: item.access || gl?.access?.read
7352
7610
  });
7353
7611
  continue;
7354
7612
  }
@@ -7456,7 +7714,8 @@ function compileNavigation(config) {
7456
7714
  icon: "Settings",
7457
7715
  group: groupName,
7458
7716
  order: 100,
7459
- views: []
7717
+ views: [],
7718
+ access: gl.access?.read
7460
7719
  });
7461
7720
  }
7462
7721
  const mentionedTrash = explicitNav.some((i) => i.trash || i.slug === "trash");
@@ -7539,34 +7798,23 @@ function compileNavigation(config) {
7539
7798
  ungrouped: sortAndSpliceItems(ungroupedItems)
7540
7799
  };
7541
7800
  }
7542
- function pruneNavigationForUser(tree, user) {
7543
- const userRoles = /* @__PURE__ */ new Set();
7544
- if (user?.role) userRoles.add(user.role);
7545
- if (Array.isArray(user?.roles)) {
7546
- for (const r of user.roles) userRoles.add(r);
7547
- }
7548
- const isAllowed = (item) => {
7549
- if (!item.access) return true;
7550
- if (Array.isArray(item.access)) {
7551
- if (item.access.length === 0) return true;
7552
- return item.access.some((role) => userRoles.has(role));
7553
- }
7554
- return true;
7801
+ async function pruneNavigationByAccess(tree, canAccess, canAccessView) {
7802
+ const resolveItem = async (item) => {
7803
+ if (!await canAccess(item)) return null;
7804
+ if (!canAccessView || !item.views?.length) return item;
7805
+ const allowed = await Promise.all(item.views.map((view) => canAccessView(view, item)));
7806
+ const views = item.views.filter((_, i) => allowed[i]);
7807
+ if (views.length === item.views.length) return item;
7808
+ if (views.length === 0 && item.type === "workspace") return null;
7809
+ return { ...item, views };
7555
7810
  };
7556
- const prunedGroups = [];
7811
+ const filterItems = async (items) => (await Promise.all(items.map(resolveItem))).filter((item) => item !== null);
7812
+ const groups = [];
7557
7813
  for (const group of tree.groups) {
7558
- const visibleItems = group.items.filter(isAllowed);
7559
- if (visibleItems.length > 0) {
7560
- prunedGroups.push({
7561
- ...group,
7562
- items: visibleItems
7563
- });
7564
- }
7814
+ const items = await filterItems(group.items);
7815
+ if (items.length > 0) groups.push({ ...group, items });
7565
7816
  }
7566
- return {
7567
- groups: prunedGroups,
7568
- ungrouped: tree.ungrouped.filter(isAllowed)
7569
- };
7817
+ return { groups, ungrouped: await filterItems(tree.ungrouped) };
7570
7818
  }
7571
7819
  function resolveAllCollectionViews(collection, config) {
7572
7820
  const views = [...collection.views ?? []];
@@ -10684,7 +10932,7 @@ var CollectionController = class _CollectionController {
10684
10932
  };
10685
10933
 
10686
10934
  // src/controllers/global.controller.ts
10687
- init_hooks();
10935
+ init_hooks2();
10688
10936
  init_access_control();
10689
10937
  var import_http_exception3 = require("hono/http-exception");
10690
10938
  var GlobalController = class {
@@ -14856,7 +15104,7 @@ var AIController = class {
14856
15104
  const dynamicConfig = await activeConfig.onSchemaFetch(projectId);
14857
15105
  activeConfig = mergeDynamicConfig(activeConfig, dynamicConfig);
14858
15106
  }
14859
- const { isAccessAllowed: isAccessAllowed2 } = await Promise.resolve().then(() => (init_access(), access_exports));
15107
+ const { isAccessAllowed: isAccessAllowed2 } = await Promise.resolve().then(() => (init_access2(), access_exports));
14860
15108
  const { validatePayloadAgainstFields: validatePayloadAgainstFields2 } = await Promise.resolve().then(() => (init_ai_tools(), ai_tools_exports));
14861
15109
  if (action.targetCollection) {
14862
15110
  const col = activeConfig.collections?.find((c2) => c2.slug === action.targetCollection);
@@ -15231,31 +15479,8 @@ function optionalAuth(config) {
15231
15479
  };
15232
15480
  }
15233
15481
 
15234
- // src/types/ai-errors.ts
15235
- var DyrectedAIError = class _DyrectedAIError extends Error {
15236
- code;
15237
- status;
15238
- details;
15239
- constructor(code, message, status = 500, details) {
15240
- super(message);
15241
- this.name = "DyrectedAIError";
15242
- this.code = code;
15243
- this.status = status;
15244
- this.details = details;
15245
- Object.setPrototypeOf(this, _DyrectedAIError.prototype);
15246
- }
15247
- toJSON() {
15248
- return {
15249
- error: true,
15250
- code: this.code,
15251
- message: this.message,
15252
- status: this.status,
15253
- details: this.details
15254
- };
15255
- }
15256
- };
15257
-
15258
15482
  // src/middleware/ai-rate-limit.ts
15483
+ init_ai_errors();
15259
15484
  var InMemoryRateLimitStore = class {
15260
15485
  windows = /* @__PURE__ */ new Map();
15261
15486
  constructor() {
@@ -16714,6 +16939,7 @@ function getSwaggerHtml(specUrl) {
16714
16939
  }
16715
16940
 
16716
16941
  // src/router.ts
16942
+ init_access2();
16717
16943
  init_access_control();
16718
16944
  init_trash();
16719
16945
  init_declarative_hooks();
@@ -16943,6 +17169,20 @@ function registerRoutes(app, config) {
16943
17169
  }
16944
17170
  return resolveBooleanAccess(requestConfig, access, accessArgs);
16945
17171
  };
17172
+ const filterReadableViews = async (views) => {
17173
+ const readable = await Promise.all(
17174
+ views.map(async (view) => {
17175
+ if (view?.access?.read === void 0) return true;
17176
+ try {
17177
+ const result = await resolveAccess(requestConfig, view.access.read, accessArgs);
17178
+ return result === void 0 || result !== false;
17179
+ } catch {
17180
+ return false;
17181
+ }
17182
+ })
17183
+ );
17184
+ return views.filter((_, i) => readable[i]);
17185
+ };
16946
17186
  const filteredCollections = await Promise.all(
16947
17187
  collections.filter((col) => !INTERNAL_SYSTEM_COLLECTIONS.has(col.slug) && (!siteId || col.shared || !col.siteId || col.siteId === siteId)).map(async (col) => ({
16948
17188
  slug: col.slug,
@@ -16999,7 +17239,9 @@ function registerRoutes(app, config) {
16999
17239
  audit: !!col.audit,
17000
17240
  drafts: !!col.drafts,
17001
17241
  defaultView: col.defaultView ?? col.admin?.defaultView,
17002
- views: await Promise.all((col.views || []).map((view) => serializeViewForApi(view, serializeAccess))),
17242
+ views: await Promise.all(
17243
+ (await filterReadableViews(col.views || [])).map((view) => serializeViewForApi(view, serializeAccess))
17244
+ ),
17003
17245
  actions: await serializeActionsForApi(col.actions, serializeAccess),
17004
17246
  admin: col.admin,
17005
17247
  detail: serializeDetailForApi(col.detail),
@@ -17467,10 +17709,29 @@ function registerRoutes(app, config) {
17467
17709
  });
17468
17710
  return c.json({ success: true });
17469
17711
  });
17470
- app.get("/api/admin/navigation", optionalAuth(config), async (c) => {
17712
+ const createNavAccessChecker = (c) => {
17471
17713
  const user = c.get("user");
17714
+ const roles = /* @__PURE__ */ new Set([...user?.role ? [user.role] : [], ...Array.isArray(user?.roles) ? user.roles : []]);
17715
+ const args = { user, req: toHookRequestContext(c.req) };
17716
+ const allows = async (rule) => {
17717
+ if (rule === void 0 || rule === null) return true;
17718
+ if (Array.isArray(rule)) return rule.length === 0 || rule.some((r) => roles.has(r));
17719
+ try {
17720
+ const result = await resolveAccess(config, rule, args);
17721
+ return result === void 0 || result !== false;
17722
+ } catch {
17723
+ return false;
17724
+ }
17725
+ };
17726
+ return {
17727
+ canAccess: (item) => allows(item.access),
17728
+ canAccessView: (view) => allows(view.access?.read)
17729
+ };
17730
+ };
17731
+ app.get("/api/admin/navigation", optionalAuth(config), async (c) => {
17472
17732
  const compiled = compileNavigation(config);
17473
- const pruned = pruneNavigationForUser(compiled, user);
17733
+ const { canAccess, canAccessView } = createNavAccessChecker(c);
17734
+ const pruned = await pruneNavigationByAccess(compiled, canAccess, canAccessView);
17474
17735
  return c.json(pruned);
17475
17736
  });
17476
17737
  app.on(["GET", "POST"], "/api/admin/navigation/badges", optionalAuth(config), async (c) => {
@@ -17526,12 +17787,17 @@ function registerRoutes(app, config) {
17526
17787
  ...(reconciled.groups || []).flatMap((g) => g.items || [])
17527
17788
  ];
17528
17789
  } else {
17529
- const pruned = pruneNavigationForUser(compiled, user);
17790
+ const pruned = await pruneNavigationByAccess(compiled, createNavAccessChecker(c).canAccess);
17530
17791
  allItems = [
17531
17792
  ...pruned.ungrouped,
17532
17793
  ...pruned.groups.flatMap((g) => g.items)
17533
17794
  ];
17534
17795
  }
17796
+ if (userNavPrefs) {
17797
+ const { canAccess } = createNavAccessChecker(c);
17798
+ const allowed = await Promise.all(allItems.map((item) => canAccess(item)));
17799
+ allItems = allItems.filter((_, i) => allowed[i]);
17800
+ }
17535
17801
  const badges = {};
17536
17802
  const requestsByCollection = /* @__PURE__ */ new Map();
17537
17803
  let reqCounter = 0;
package/dist/server.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { O as DyrectedContext, D as DyrectedConfig, C as CollectionConfig, G as GlobalConfig, c9 as EmailTemplateArgs, ca as EmailTemplateResult, d1 as OutboundEmail, e as DatabaseAdapter, b as AuthenticatedUser, c5 as DyrectedAIContext, ax as AIThread, at as AIMessage, d9 as RAGSearchResult, aw as AIRateLimitStore, av as AIRateLimitResult } from './app-DregJnqR.cjs';
2
- export { e2 as CollectionTokenPayload, e3 as DEFAULT_INVITE_EXPIRY, e4 as DEFAULT_RESET_PASSWORD_EXPIRY, e5 as DEFAULT_SESSION_EXPIRY, e6 as DyrectedObservabilityRuntime, e7 as RequestBodyCapture, e8 as RequestTraceContext, e9 as ResolvedObservabilityConfig, ea as attachRequestMetrics, eb as bindObservabilityRuntime, ec as buildRequestLogger, ed as captureRequestBody, ee as createDyrectedApp, ef as createObservabilityRuntime, eg as createRequestSpan, eh as decodeCollectionToken, ei as endRequestSpan, ej as getConfigLogger, ek as getObservabilityRuntime, el as getRequestLogger, em as redactBody, en as redactHeaders, eo as renderPrometheusMetrics, ep as resolveInviteTokenExpiry, eq as resolveObservabilityConfig, er as resolveResetPasswordTokenExpiry, es as resolveSessionTokenExpiry, et as shouldSampleRequest, eu as signCollectionToken, ev as verifyCollectionToken } from './app-DregJnqR.cjs';
1
+ import { O as DyrectedContext, D as DyrectedConfig, C as CollectionConfig, G as GlobalConfig, ca as EmailTemplateArgs, cb as EmailTemplateResult, d5 as OutboundEmail, e as DatabaseAdapter, b as AuthenticatedUser, c6 as DyrectedAIContext, ax as AIThread, at as AIMessage, dd as RAGSearchResult, aw as AIRateLimitStore, av as AIRateLimitResult } from './app-Bg34iyUz.cjs';
2
+ export { e6 as CollectionTokenPayload, e7 as DEFAULT_INVITE_EXPIRY, e8 as DEFAULT_RESET_PASSWORD_EXPIRY, e9 as DEFAULT_SESSION_EXPIRY, ea as DyrectedObservabilityRuntime, eb as RequestBodyCapture, ec as RequestTraceContext, ed as ResolvedObservabilityConfig, ee as attachRequestMetrics, ef as bindObservabilityRuntime, eg as buildRequestLogger, eh as captureRequestBody, ei as createDyrectedApp, ej as createObservabilityRuntime, ek as createRequestSpan, el as decodeCollectionToken, em as endRequestSpan, en as getConfigLogger, eo as getObservabilityRuntime, ep as getRequestLogger, eq as redactBody, er as redactHeaders, es as renderPrometheusMetrics, et as resolveInviteTokenExpiry, eu as resolveObservabilityConfig, ev as resolveResetPasswordTokenExpiry, ew as resolveSessionTokenExpiry, ex as shouldSampleRequest, ey as signCollectionToken, ez as verifyCollectionToken } from './app-Bg34iyUz.cjs';
3
3
  import * as hono from 'hono';
4
4
  import { Hono, Context, Next } from 'hono';
5
5
  import * as hono_utils_http_status from 'hono/utils/http-status';
package/dist/server.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { O as DyrectedContext, D as DyrectedConfig, C as CollectionConfig, G as GlobalConfig, c9 as EmailTemplateArgs, ca as EmailTemplateResult, d1 as OutboundEmail, e as DatabaseAdapter, b as AuthenticatedUser, c5 as DyrectedAIContext, ax as AIThread, at as AIMessage, d9 as RAGSearchResult, aw as AIRateLimitStore, av as AIRateLimitResult } from './app-DregJnqR.js';
2
- export { e2 as CollectionTokenPayload, e3 as DEFAULT_INVITE_EXPIRY, e4 as DEFAULT_RESET_PASSWORD_EXPIRY, e5 as DEFAULT_SESSION_EXPIRY, e6 as DyrectedObservabilityRuntime, e7 as RequestBodyCapture, e8 as RequestTraceContext, e9 as ResolvedObservabilityConfig, ea as attachRequestMetrics, eb as bindObservabilityRuntime, ec as buildRequestLogger, ed as captureRequestBody, ee as createDyrectedApp, ef as createObservabilityRuntime, eg as createRequestSpan, eh as decodeCollectionToken, ei as endRequestSpan, ej as getConfigLogger, ek as getObservabilityRuntime, el as getRequestLogger, em as redactBody, en as redactHeaders, eo as renderPrometheusMetrics, ep as resolveInviteTokenExpiry, eq as resolveObservabilityConfig, er as resolveResetPasswordTokenExpiry, es as resolveSessionTokenExpiry, et as shouldSampleRequest, eu as signCollectionToken, ev as verifyCollectionToken } from './app-DregJnqR.js';
1
+ import { O as DyrectedContext, D as DyrectedConfig, C as CollectionConfig, G as GlobalConfig, ca as EmailTemplateArgs, cb as EmailTemplateResult, d5 as OutboundEmail, e as DatabaseAdapter, b as AuthenticatedUser, c6 as DyrectedAIContext, ax as AIThread, at as AIMessage, dd as RAGSearchResult, aw as AIRateLimitStore, av as AIRateLimitResult } from './app-Bg34iyUz.js';
2
+ export { e6 as CollectionTokenPayload, e7 as DEFAULT_INVITE_EXPIRY, e8 as DEFAULT_RESET_PASSWORD_EXPIRY, e9 as DEFAULT_SESSION_EXPIRY, ea as DyrectedObservabilityRuntime, eb as RequestBodyCapture, ec as RequestTraceContext, ed as ResolvedObservabilityConfig, ee as attachRequestMetrics, ef as bindObservabilityRuntime, eg as buildRequestLogger, eh as captureRequestBody, ei as createDyrectedApp, ej as createObservabilityRuntime, ek as createRequestSpan, el as decodeCollectionToken, em as endRequestSpan, en as getConfigLogger, eo as getObservabilityRuntime, ep as getRequestLogger, eq as redactBody, er as redactHeaders, es as renderPrometheusMetrics, et as resolveInviteTokenExpiry, eu as resolveObservabilityConfig, ev as resolveResetPasswordTokenExpiry, ew as resolveSessionTokenExpiry, ex as shouldSampleRequest, ey as signCollectionToken, ez as verifyCollectionToken } from './app-Bg34iyUz.js';
3
3
  import * as hono from 'hono';
4
4
  import { Hono, Context, Next } from 'hono';
5
5
  import * as hono_utils_http_status from 'hono/utils/http-status';