@dyrected/core 2.22.0 → 2.24.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/index.cjs CHANGED
@@ -1793,6 +1793,7 @@ __export(index_exports, {
1793
1793
  BUILTIN_JEXL_HELPERS: () => BUILTIN_JEXL_HELPERS,
1794
1794
  CROCKFORD_BASE32: () => CROCKFORD_BASE32,
1795
1795
  CURRENT_NAV_PREFERENCES_VERSION: () => CURRENT_NAV_PREFERENCES_VERSION,
1796
+ CUSTOM_VIEW_FETCH_ALL_LIMIT: () => CUSTOM_VIEW_FETCH_ALL_LIMIT,
1796
1797
  ConfigValidationError: () => ConfigValidationError,
1797
1798
  ConflictError: () => ConflictError,
1798
1799
  DEFAULT_USER_NAV_PREFERENCES: () => DEFAULT_USER_NAV_PREFERENCES,
@@ -1801,6 +1802,7 @@ __export(index_exports, {
1801
1802
  DyrectedError: () => DyrectedError,
1802
1803
  EMAIL_TEMPLATES_COLLECTION_CONFIG: () => EMAIL_TEMPLATES_COLLECTION_CONFIG,
1803
1804
  EMAIL_TEMPLATES_COLLECTION_SLUG: () => EMAIL_TEMPLATES_COLLECTION_SLUG,
1805
+ FORM_SHELLS: () => FORM_SHELLS,
1804
1806
  FieldConditionBuilder: () => FieldConditionBuilder,
1805
1807
  ForbiddenError: () => ForbiddenError,
1806
1808
  INTERNAL_SYSTEM_COLLECTIONS: () => INTERNAL_SYSTEM_COLLECTIONS,
@@ -1839,11 +1841,13 @@ __export(index_exports, {
1839
1841
  clamp: () => clamp,
1840
1842
  coalesce: () => coalesce,
1841
1843
  coerceBooleanWhere: () => coerceBooleanWhere,
1844
+ collectAdminComponentsValidationIssues: () => collectAdminComponentsValidationIssues,
1842
1845
  collectAdminConditionValidationIssues: () => collectAdminConditionValidationIssues,
1843
1846
  collectConfigDiagnostics: () => collectConfigDiagnostics,
1844
1847
  collectDeclarativeAccessValidationIssues: () => collectDeclarativeAccessValidationIssues,
1845
1848
  collectDeclarativeHookValidationIssues: () => collectDeclarativeHookValidationIssues,
1846
1849
  collectPreviewUrlValidationIssues: () => collectPreviewUrlValidationIssues,
1850
+ collectReferencedComponentKeys: () => collectReferencedComponentKeys,
1847
1851
  compact: () => compact,
1848
1852
  compileNavigation: () => compileNavigation,
1849
1853
  count: () => count,
@@ -1864,6 +1868,7 @@ __export(index_exports, {
1864
1868
  defineConfig: () => defineConfig,
1865
1869
  defineCreatedAtField: () => defineCreatedAtField,
1866
1870
  defineCreatedByField: () => defineCreatedByField,
1871
+ defineCustomView: () => defineCustomView,
1867
1872
  defineDateField: () => defineDateField,
1868
1873
  defineDateTimeField: () => defineDateTimeField,
1869
1874
  defineEmailField: () => defineEmailField,
@@ -1879,6 +1884,7 @@ __export(index_exports, {
1879
1884
  defineMultiSelectField: () => defineMultiSelectField,
1880
1885
  defineNumberField: () => defineNumberField,
1881
1886
  defineObjectField: () => defineObjectField,
1887
+ definePage: () => definePage,
1882
1888
  definePublishingWorkflow: () => definePublishingWorkflow,
1883
1889
  defineRadioField: () => defineRadioField,
1884
1890
  defineRelationshipField: () => defineRelationshipField,
@@ -2032,6 +2038,9 @@ function asCollection(config) {
2032
2038
  return config;
2033
2039
  }
2034
2040
 
2041
+ // src/types/admin.ts
2042
+ var FORM_SHELLS = ["full", "header", "none"];
2043
+
2035
2044
  // src/types/workflows.ts
2036
2045
  var LIFECYCLE_EVENT_NAMES = [
2037
2046
  "revision.created",
@@ -2041,9 +2050,19 @@ var LIFECYCLE_EVENT_NAMES = [
2041
2050
  ];
2042
2051
 
2043
2052
  // src/types/views.ts
2053
+ var CUSTOM_VIEW_FETCH_ALL_LIMIT = 1e3;
2044
2054
  function defineView(config) {
2055
+ assertCustomViewComponent(config);
2045
2056
  return config;
2046
2057
  }
2058
+ function assertCustomViewComponent(config) {
2059
+ if (config.layout !== "custom") return;
2060
+ if (typeof config.component !== "string" || config.component.trim() === "") {
2061
+ throw new Error(
2062
+ `View "${config.slug ?? "(unnamed)"}" uses layout: "custom" but has no \`component\`. Set \`component\` to a key registered in AdminComponents.viewLayouts.`
2063
+ );
2064
+ }
2065
+ }
2047
2066
  function defineTableView(config) {
2048
2067
  return config;
2049
2068
  }
@@ -2056,6 +2075,10 @@ function defineCalendarView(config) {
2056
2075
  function defineGanttView(config) {
2057
2076
  return config;
2058
2077
  }
2078
+ function defineCustomView(config) {
2079
+ assertCustomViewComponent(config);
2080
+ return config;
2081
+ }
2059
2082
  function defineCardsView(config) {
2060
2083
  return config;
2061
2084
  }
@@ -2112,6 +2135,23 @@ var DEFAULT_USER_NAV_PREFERENCES = {
2112
2135
  items: []
2113
2136
  };
2114
2137
 
2138
+ // src/types/pages.ts
2139
+ function definePage(config) {
2140
+ return {
2141
+ slug: config.slug,
2142
+ label: config.label,
2143
+ icon: config.icon,
2144
+ group: config.group,
2145
+ order: config.order,
2146
+ after: config.after,
2147
+ before: config.before,
2148
+ position: config.position,
2149
+ badge: config.badge,
2150
+ access: config.access && typeof config.access === "object" && "read" in config.access ? config.access.read : config.access,
2151
+ page: config
2152
+ };
2153
+ }
2154
+
2115
2155
  // src/auth/token.ts
2116
2156
  var import_jose = require("jose");
2117
2157
 
@@ -2951,6 +2991,54 @@ function collectPreviewUrlValidationIssues(config) {
2951
2991
  });
2952
2992
  return issues;
2953
2993
  }
2994
+ var FORM_COMPONENT_KEYS = ["createForm", "editForm", "form"];
2995
+ var GLOBAL_FORM_COMPONENT_KEYS = ["editForm", "form"];
2996
+ function collectFormComponentIssues(components, path, surface, keys, issues) {
2997
+ if (!isPlainObject(components)) return;
2998
+ for (const key of keys) {
2999
+ const value = components[key];
3000
+ if (value === void 0) continue;
3001
+ if (typeof value !== "string" || value.length === 0) {
3002
+ issues.push({
3003
+ path: `${path}.admin.components.${key}`,
3004
+ surface,
3005
+ message: `\`${key}\` must be the registry key of a component, such as "check_ins.scanForm".`,
3006
+ expression: String(value)
3007
+ });
3008
+ }
3009
+ }
3010
+ const shell = components.formShell;
3011
+ if (shell !== void 0 && !FORM_SHELLS.includes(shell)) {
3012
+ issues.push({
3013
+ path: `${path}.admin.components.formShell`,
3014
+ surface,
3015
+ message: `Unknown formShell "${String(shell)}". Use ${FORM_SHELLS.map((value) => `"${value}"`).join(", ")}.`,
3016
+ expression: String(shell)
3017
+ });
3018
+ }
3019
+ }
3020
+ function collectAdminComponentsValidationIssues(config) {
3021
+ const issues = [];
3022
+ config.collections.forEach((collection, index) => {
3023
+ collectFormComponentIssues(
3024
+ collection.admin?.components,
3025
+ collectionSegment(collection, index),
3026
+ "collection.admin.components",
3027
+ FORM_COMPONENT_KEYS,
3028
+ issues
3029
+ );
3030
+ });
3031
+ config.globals?.forEach((global, index) => {
3032
+ collectFormComponentIssues(
3033
+ global.admin?.components,
3034
+ globalSegment(global, index),
3035
+ "global.admin.components",
3036
+ GLOBAL_FORM_COMPONENT_KEYS,
3037
+ issues
3038
+ );
3039
+ });
3040
+ return issues;
3041
+ }
2954
3042
  function assertValidAdminConditionsInConfig(config, source = "config") {
2955
3043
  const diagnostics = collectAdminConditionValidationIssues(config).map((issue) => ({
2956
3044
  severity: "error",
@@ -3008,7 +3096,15 @@ function collectConfigDiagnostics(config) {
3008
3096
  message: issue.message,
3009
3097
  expression: issue.expression
3010
3098
  }));
3011
- return [...hookIssues, ...accessIssues, ...adminConditionIssues, ...previewUrlIssues];
3099
+ const adminComponentIssues = collectAdminComponentsValidationIssues(config).map((issue) => ({
3100
+ severity: "error",
3101
+ source: "adminComponents",
3102
+ path: issue.path,
3103
+ surface: issue.surface,
3104
+ message: issue.message,
3105
+ expression: issue.expression
3106
+ }));
3107
+ return [...hookIssues, ...accessIssues, ...adminConditionIssues, ...previewUrlIssues, ...adminComponentIssues];
3012
3108
  }
3013
3109
  function formatConfigDiagnostics(source, diagnostics, options = {}) {
3014
3110
  const color = options.color ?? false;
@@ -5441,6 +5537,12 @@ var DuplicateKeyError = class _DuplicateKeyError extends ConflictError {
5441
5537
  function assertNever(op, context) {
5442
5538
  throw new Error(`[dyrected/core] Unhandled where operator "${op}" in ${context}`);
5443
5539
  }
5540
+ function escapeLike(value) {
5541
+ return value.replace(/[!%_]/g, "!$&");
5542
+ }
5543
+ function escapeRegex(value) {
5544
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5545
+ }
5444
5546
  function parseSqlWhere(where, getJsonField, placeholder = "?", likeOperator = placeholder === "pg" ? "ILIKE" : "LIKE") {
5445
5547
  const params = [];
5446
5548
  let pgIndex = 1;
@@ -5450,6 +5552,19 @@ function parseSqlWhere(where, getJsonField, placeholder = "?", likeOperator = pl
5450
5552
  function col(field) {
5451
5553
  return field === "id" ? "id" : getJsonField(field);
5452
5554
  }
5555
+ function buildLike(column, pattern, escaped = false) {
5556
+ const esc = escaped ? ` ESCAPE '!'` : "";
5557
+ if (placeholder === "pg") {
5558
+ params.push(pattern);
5559
+ return `(${column})::text ${likeOperator} ${next()}${esc}`;
5560
+ }
5561
+ if (likeOperator === "ILIKE") {
5562
+ params.push(pattern);
5563
+ return `${column} ILIKE ${next()}${esc}`;
5564
+ }
5565
+ params.push(pattern.toLowerCase());
5566
+ return `LOWER(${column}) LIKE ${next()}${esc}`;
5567
+ }
5453
5568
  function buildOperator(field, value) {
5454
5569
  const c = col(field);
5455
5570
  const isJsonExtract = c.startsWith("data->>") || c.startsWith("json_extract(") || c.startsWith("JSON_UNQUOTE(");
@@ -5592,13 +5707,12 @@ function parseSqlWhere(where, getJsonField, placeholder = "?", likeOperator = pl
5592
5707
  case "less_than_or_equal":
5593
5708
  params.push(operand);
5594
5709
  return `${c} <= ${next()}`;
5595
- case "contains":
5596
5710
  case "like":
5597
- params.push(`%${operand}%`);
5598
- return placeholder === "pg" ? `(${c})::text ${likeOperator} ${next()}` : `${c} ${likeOperator} ${next()}`;
5711
+ return buildLike(c, `%${String(operand)}%`);
5712
+ case "contains":
5713
+ return buildLike(c, `%${escapeLike(String(operand))}%`, true);
5599
5714
  case "starts_with":
5600
- params.push(`${operand}%`);
5601
- return placeholder === "pg" ? `(${c})::text ${likeOperator} ${next()}` : `${c} ${likeOperator} ${next()}`;
5715
+ return buildLike(c, `${escapeLike(String(operand))}%`, true);
5602
5716
  case "exists":
5603
5717
  return operand ? `${c} IS NOT NULL` : `${c} IS NULL`;
5604
5718
  default:
@@ -5696,9 +5810,9 @@ function parseMongoWhere(where) {
5696
5810
  return { [field]: { $lte: operand } };
5697
5811
  case "contains":
5698
5812
  case "like":
5699
- return { [field]: { $regex: operand, $options: "i" } };
5813
+ return { [field]: { $regex: escapeRegex(String(operand)), $options: "i" } };
5700
5814
  case "starts_with":
5701
- return { [field]: { $regex: `^${operand}`, $options: "i" } };
5815
+ return { [field]: { $regex: `^${escapeRegex(String(operand))}`, $options: "i" } };
5702
5816
  case "exists":
5703
5817
  return { [field]: { $exists: operand } };
5704
5818
  default:
@@ -5808,6 +5922,99 @@ function buildSqlOrderBy(sort, existingColumns, numericFields, dialect) {
5808
5922
  }).join(", ");
5809
5923
  }
5810
5924
 
5925
+ // src/utils/component-keys.ts
5926
+ var DASHBOARD_SLOTS = ["beforeDashboard", "afterDashboard"];
5927
+ var LIST_SLOTS = ["beforeList", "beforeListTable", "afterListTable", "afterList"];
5928
+ var FORM_SLOTS = ["createForm", "editForm", "form"];
5929
+ var VIEW_SLOTS = ["beforeViewHeader", "afterViewHeader", "beforeViewContent", "afterViewContent"];
5930
+ function addKeys(target, value) {
5931
+ for (const key of Array.isArray(value) ? value : [value]) {
5932
+ if (typeof key === "string" && key) target.add(key);
5933
+ }
5934
+ }
5935
+ function addSlots(target, slots, names) {
5936
+ if (!slots || typeof slots !== "object") return;
5937
+ for (const name of names) addKeys(target, slots[name]);
5938
+ }
5939
+ function scanFields(fields, keys) {
5940
+ if (!Array.isArray(fields)) return;
5941
+ for (const field of fields) {
5942
+ if (!field || typeof field !== "object") continue;
5943
+ addKeys(keys.fields, field.admin?.component);
5944
+ scanFields(field.fields, keys);
5945
+ if (Array.isArray(field.blocks)) {
5946
+ for (const block of field.blocks) scanFields(block?.fields, keys);
5947
+ }
5948
+ if (Array.isArray(field.tabs)) {
5949
+ for (const tab of field.tabs) scanFields(tab?.fields, keys);
5950
+ }
5951
+ }
5952
+ }
5953
+ function scanDetail(items, keys) {
5954
+ if (!Array.isArray(items)) return;
5955
+ for (const item of items) {
5956
+ if (!item || typeof item !== "object") continue;
5957
+ if (item.type === "custom") addKeys(keys.customComponents, item.name);
5958
+ scanDetail(item.items, keys);
5959
+ if (Array.isArray(item.tabs)) {
5960
+ for (const tab of item.tabs) scanDetail(tab?.items, keys);
5961
+ }
5962
+ }
5963
+ }
5964
+ function scanViews(views, keys) {
5965
+ if (!Array.isArray(views)) return;
5966
+ for (const view of views) {
5967
+ addSlots(keys.collectionView, view?.components, VIEW_SLOTS);
5968
+ if (view?.layout === "custom") addKeys(keys.viewLayouts, view.component);
5969
+ }
5970
+ }
5971
+ function collectReferencedComponentKeys(schema) {
5972
+ const keys = {
5973
+ fields: /* @__PURE__ */ new Set(),
5974
+ dashboard: /* @__PURE__ */ new Set(),
5975
+ collectionList: /* @__PURE__ */ new Set(),
5976
+ collectionView: /* @__PURE__ */ new Set(),
5977
+ forms: /* @__PURE__ */ new Set(),
5978
+ viewLayouts: /* @__PURE__ */ new Set(),
5979
+ pages: /* @__PURE__ */ new Set(),
5980
+ customComponents: /* @__PURE__ */ new Set()
5981
+ };
5982
+ const root = schema;
5983
+ if (!root || typeof root !== "object") return keys;
5984
+ addSlots(keys.dashboard, root.admin?.components, DASHBOARD_SLOTS);
5985
+ if (Array.isArray(root.admin?.navigation)) {
5986
+ for (const item of root.admin.navigation) {
5987
+ if (item?.page) {
5988
+ if (typeof item.page === "string") {
5989
+ addKeys(keys.pages, item.page);
5990
+ } else if (item.page?.component) {
5991
+ addKeys(keys.pages, item.page.component);
5992
+ }
5993
+ }
5994
+ }
5995
+ }
5996
+ if (Array.isArray(root.admin?.pages)) {
5997
+ for (const page of root.admin.pages) addKeys(keys.pages, page?.component);
5998
+ }
5999
+ for (const block of root.blocks ?? []) scanFields(block?.fields, keys);
6000
+ for (const collection of root.collections ?? []) {
6001
+ scanFields(collection.fields, keys);
6002
+ scanDetail(collection.detail, keys);
6003
+ scanViews(collection.views, keys);
6004
+ const slots = collection.admin?.components;
6005
+ addSlots(keys.collectionList, slots, LIST_SLOTS);
6006
+ addSlots(keys.collectionView, slots, VIEW_SLOTS);
6007
+ addSlots(keys.collectionView, slots?.collectionView, VIEW_SLOTS);
6008
+ addSlots(keys.forms, slots, FORM_SLOTS);
6009
+ }
6010
+ for (const global of root.globals ?? []) {
6011
+ scanFields(global.fields, keys);
6012
+ scanDetail(global.detail, keys);
6013
+ addSlots(keys.forms, global.admin?.components, FORM_SLOTS);
6014
+ }
6015
+ return keys;
6016
+ }
6017
+
5811
6018
  // src/utils/openapi.ts
5812
6019
  function getCollectionLabels(collection) {
5813
6020
  return collection.labels || { singular: collection.slug, plural: collection.slug };
@@ -8295,11 +8502,32 @@ var RESERVED_NAVIGATION_SLUGS = /* @__PURE__ */ new Set([
8295
8502
  "admin",
8296
8503
  "preferences",
8297
8504
  "auth",
8298
- "trash"
8505
+ "trash",
8506
+ "pages"
8299
8507
  ]);
8300
8508
  function assertValidNavigationSlugs(navigation) {
8509
+ const seenWorkspaceSlugs = /* @__PURE__ */ new Set();
8510
+ const seenPageSlugs = /* @__PURE__ */ new Set();
8301
8511
  for (const item of navigation) {
8302
8512
  if (item.dashboard || item.trash) continue;
8513
+ if (item.page) {
8514
+ const pageSlug = typeof item.page === "string" ? item.slug || item.page : item.slug || item.page.slug;
8515
+ if (pageSlug) {
8516
+ const normalized = pageSlug.toLowerCase().trim().replace(/^\//, "");
8517
+ if (RESERVED_NAVIGATION_SLUGS.has(normalized)) {
8518
+ throw new Error(
8519
+ `[Dyrected Config] The slug '${pageSlug}' in custom page '${item.label || pageSlug}' is a reserved system path and cannot be used as a page slug.`
8520
+ );
8521
+ }
8522
+ if (seenPageSlugs.has(normalized)) {
8523
+ throw new Error(
8524
+ `[Dyrected Config] Duplicate page slug '${pageSlug}' in navigation. Page slugs must be unique.`
8525
+ );
8526
+ }
8527
+ seenPageSlugs.add(normalized);
8528
+ }
8529
+ continue;
8530
+ }
8303
8531
  if (item.slug) {
8304
8532
  const normalizedSlug = item.slug.toLowerCase().trim().replace(/^\//, "");
8305
8533
  if (RESERVED_NAVIGATION_SLUGS.has(normalizedSlug)) {
@@ -8307,6 +8535,12 @@ function assertValidNavigationSlugs(navigation) {
8307
8535
  `[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.`
8308
8536
  );
8309
8537
  }
8538
+ if (seenWorkspaceSlugs.has(normalizedSlug)) {
8539
+ throw new Error(
8540
+ `[Dyrected Config] Duplicate workspace slug '${item.slug}' in navigation. Workspace slugs must be unique.`
8541
+ );
8542
+ }
8543
+ seenWorkspaceSlugs.add(normalizedSlug);
8310
8544
  }
8311
8545
  }
8312
8546
  }
@@ -8449,6 +8683,43 @@ function compileNavigation(config) {
8449
8683
  });
8450
8684
  continue;
8451
8685
  }
8686
+ if (item.page) {
8687
+ const pageConfig = typeof item.page === "string" ? {
8688
+ slug: item.slug || item.page,
8689
+ label: item.label || item.page,
8690
+ icon: item.icon,
8691
+ component: item.page,
8692
+ group: typeof item.group === "string" ? item.group : item.group?.name,
8693
+ order: item.order,
8694
+ badge: item.badge,
8695
+ access: item.access
8696
+ } : {
8697
+ ...item.page,
8698
+ slug: item.slug || item.page.slug || "page",
8699
+ label: item.label || item.page.label || item.slug || "Page",
8700
+ icon: item.icon || item.page.icon,
8701
+ group: item.group ? typeof item.group === "string" ? item.group : item.group?.name : item.page.group,
8702
+ order: item.order ?? item.page.order,
8703
+ badge: item.badge || item.page.badge,
8704
+ access: item.access || (item.page.access && typeof item.page.access === "object" && "read" in item.page.access ? item.page.access.read : item.page.access)
8705
+ };
8706
+ const pageSlug = pageConfig.slug || "page";
8707
+ registerItem(groupName, {
8708
+ id: `page:${pageSlug}`,
8709
+ type: "page",
8710
+ slug: pageSlug,
8711
+ label: pageConfig.label || pageSlug,
8712
+ icon: pageConfig.icon || "FileText",
8713
+ href: `/pages/${pageSlug}`,
8714
+ group: groupName,
8715
+ order: pageConfig.order ?? 100,
8716
+ views: [],
8717
+ badge: pageConfig.badge,
8718
+ access: pageConfig.access && typeof pageConfig.access === "object" && "read" in pageConfig.access ? pageConfig.access.read : pageConfig.access,
8719
+ page: pageConfig
8720
+ });
8721
+ continue;
8722
+ }
8452
8723
  const workspaceSlug = item.slug || "workspace";
8453
8724
  registerItem(groupName, {
8454
8725
  id: `workspace_${workspaceSlug}`,
@@ -8831,6 +9102,7 @@ function defineTab(args) {
8831
9102
  BUILTIN_JEXL_HELPERS,
8832
9103
  CROCKFORD_BASE32,
8833
9104
  CURRENT_NAV_PREFERENCES_VERSION,
9105
+ CUSTOM_VIEW_FETCH_ALL_LIMIT,
8834
9106
  ConfigValidationError,
8835
9107
  ConflictError,
8836
9108
  DEFAULT_USER_NAV_PREFERENCES,
@@ -8839,6 +9111,7 @@ function defineTab(args) {
8839
9111
  DyrectedError,
8840
9112
  EMAIL_TEMPLATES_COLLECTION_CONFIG,
8841
9113
  EMAIL_TEMPLATES_COLLECTION_SLUG,
9114
+ FORM_SHELLS,
8842
9115
  FieldConditionBuilder,
8843
9116
  ForbiddenError,
8844
9117
  INTERNAL_SYSTEM_COLLECTIONS,
@@ -8877,11 +9150,13 @@ function defineTab(args) {
8877
9150
  clamp,
8878
9151
  coalesce,
8879
9152
  coerceBooleanWhere,
9153
+ collectAdminComponentsValidationIssues,
8880
9154
  collectAdminConditionValidationIssues,
8881
9155
  collectConfigDiagnostics,
8882
9156
  collectDeclarativeAccessValidationIssues,
8883
9157
  collectDeclarativeHookValidationIssues,
8884
9158
  collectPreviewUrlValidationIssues,
9159
+ collectReferencedComponentKeys,
8885
9160
  compact,
8886
9161
  compileNavigation,
8887
9162
  count,
@@ -8902,6 +9177,7 @@ function defineTab(args) {
8902
9177
  defineConfig,
8903
9178
  defineCreatedAtField,
8904
9179
  defineCreatedByField,
9180
+ defineCustomView,
8905
9181
  defineDateField,
8906
9182
  defineDateTimeField,
8907
9183
  defineEmailField,
@@ -8917,6 +9193,7 @@ function defineTab(args) {
8917
9193
  defineMultiSelectField,
8918
9194
  defineNumberField,
8919
9195
  defineObjectField,
9196
+ definePage,
8920
9197
  definePublishingWorkflow,
8921
9198
  defineRadioField,
8922
9199
  defineRelationshipField,
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { F as Field, B as Block, C as CollectionConfig, D as DyrectedConfig, A as AdminAuthConfig, P as PublicAdminAuthConfig, G as GlobalConfig, a as DeclarativeHookExpression, W as WorkflowConfig, b as AuthenticatedUser, c as WorkflowTransition, L as LifecycleEventName, d as LifecycleEvent, e as DatabaseAdapter, f as BaseDocument, H as HookRequestContext, T as TaskRunResult, g as TaskConfig, h as DetailActionOptions, i as DetailAction, j as DetailComputedOptions, k as ComputedHandler, l as DetailComputed, m as DetailCustomOptions, n as DetailCustom, o as DetailDividerOptions, p as DetailDivider, q as DisplayFieldOptions, r as DetailField, s as DetailItem, t as DetailGridOptions, u as DetailGrid, v as DetailRepeatOptions, w as DetailRepeat, x as DetailSectionOptions, y as DetailSection, z as DetailTabOptions, E as DetailTab, I as DetailTabsOptions, J as DetailTabs, K as DetailTextOptions, M as DetailText, N as DetailSchema, O as DyrectedContext, Q as AIConfig, R as AIPIIConfig, S as IdStrategy, U as CompiledNavTree, V as CompiledNavItem, X as UserNavigationPreferences, Y as DefineWorkspaceOptions, Z as ViewConfig, _ as DateTimeField, $ as RelationshipField, a0 as SelectField, a1 as ArrayField, a2 as FieldType, a3 as BooleanField, a4 as AuthConfig, a5 as AccessPolicyResolver, a6 as DateField, a7 as TextField, a8 as EmailField, a9 as IconField, aa as ImageField, ab as JoinField, ac as JsonField, ad as MoneyField, ae as MultiSelectField, af as NumberField, ag as ObjectField, ah as RadioField, ai as RichTextField, aj as RowField, ak as TextareaField, al as TimeField, am as UrlField } from './app-BBHBP-6V.cjs';
2
- export { an as AIAction, ao as AIActionStatus, ap as AIActionType, aq as AIAuditActionType, ar as AIAuditRecord, as as AIChunk, at as AIMessage, au as AIPIIPattern, av as AIRateLimitResult, aw as AIRateLimitStore, ax as AIThread, ay as AIToolContext, az as AIToolDefinition, aA as AI_ACTIONS_COLLECTION, aB as AI_AUDIT_COLLECTION, aC as AI_CHUNKS_COLLECTION, aD as AI_MESSAGES_COLLECTION, aE as AI_THREADS_COLLECTION, aF as AccessConfig, aG as AccessFunction, aH as AccessFunctionArgs, aI as AccessResult, aJ as AccessRule, aK as ActionConfig, aL as ActionConfigBase, aM as ActionConfigWithHandler, aN as ActionConfigWithMutation, aO as ActionContext, aP as ActionType, aQ as AdminAuthAccessResolution, aR as AdminAuthClaimMapping, aS as AdminAuthMember, aT as AdminAuthProvider, aU as AdminAuthProviderMembersConfig, aV as AdminAuthProvisioningMode, aW as AdminAuthResolveAccessArgs, aX as AdminAuthResolvedIdentity, aY as AdminConfig, aZ as AdminDashboardComponentSlots, a_ as AdminIconName, a$ as AggregateArgs, b0 as AggregateCastType, b1 as AggregateCollectionResult, b2 as AggregateInput, b3 as AggregateOperation, b4 as AggregateResult, b5 as AppTrashConfig, b6 as BaseAdminAuthProvider, b7 as BaseFieldAdmin, b8 as BlockVariant, b9 as BlocksField, ba as BooleanFieldAdmin, bb as BooleanFormat, bc as CURRENT_NAV_PREFERENCES_VERSION, bd as CalendarViewConfig, be as CardsViewConfig, bf as CharacterLimitFieldAdmin, bg as CharacterLimitFieldConfig, bh as CollectionAfterChangeHook, bi as CollectionAfterDeleteHook, bj as CollectionAfterReadHook, bk as CollectionAfterReadHookEntry, bl as CollectionAfterRestoreHook, bm as CollectionAfterTransitionHook, bn as CollectionAfterTrashHook, bo as CollectionBeforeChangeHook, bp as CollectionBeforeChangeHookEntry, bq as CollectionBeforeCommitHook, br as CollectionBeforeDeleteHook, bs as CollectionBeforeReadHook, bt as CollectionBeforeReadHookEntry, bu as CollectionBeforeRestoreHook, bv as CollectionBeforeTransitionHook, bw as CollectionBeforeTrashHook, bx as CollectionEmailConfig, by as CollectionIndex, bz as CollectionListComponentSlots, bA as CollectionRAGConfig, bB as CollectionSchemaResult, bC as CollectionSummaryResult, bD as CollectionViewComponentSlots, bE as CompiledNavGroup, bF as CountOperation, bG as CustomAdminAuthProvider, bH as DEFAULT_USER_NAV_PREFERENCES, bI as DateFieldAdmin, bJ as DateFormat, bK as DefaultValueContext, bL as DefineActionOptions, bM as DefineCalendarViewOptions, bN as DefineCardsViewOptions, bO as DefineGanttViewOptions, bP as DefineKanbanViewOptions, bQ as DefineTableViewOptions, bR as DefineViewBaseOptions, bS as DefineViewOptions, bT as DetailSpan, bU as DisplayTone, bV as DisplayVariant, bW as DistinctCountOperation, bX as DistinctValuesOperation, bY as DynamicOptionItem, bZ as DynamicOptionsConfig, b_ as DynamicOptionsResolver, b$ as DynamicOptionsResolverArgs, c0 as DyrectedAIContext, c1 as DyrectedLoggerConfig, c2 as DyrectedObservabilityConfig, c3 as EmailFieldAdmin, c4 as EmailTemplateArgs, c5 as EmailTemplateResult, c6 as FieldAdminHooks, c7 as FieldAdminOnChangeHook, c8 as FieldAdminOnChangeHookArgs, c9 as FieldAdminOptionsHook, ca as FieldAdminOptionsHookArgs, cb as FieldAdminOptionsHookResult, cc as FieldAfterReadHook, cd as FieldAfterReadHookArgs, ce as FieldBase, cf as FieldBeforeChangeHook, cg as FieldBeforeChangeHookArgs, ch as FieldHook, ci as FieldHooks, cj as FileData, ck as GanttViewConfig, cl as GetDocumentResult, cm as GlobalAfterChangeHook, cn as GlobalAfterReadHook, co as GlobalAfterReadHookEntry, cp as GlobalBeforeChangeHook, cq as GlobalBeforeChangeHookEntry, cr as GlobalBeforeReadHook, cs as GlobalBeforeReadHookEntry, ct as GlobalRAGConfig, cu as GlobalSchemaResult, cv as GlobalSummaryResult, cw as HeadingLevel, cx as HookFunction, cy as IconFieldAdmin, cz as ImageService, cA as ImageTransformOptions, cB as InferAggregateResult, cC as JoinFieldAdmin, cD as JsonFieldAdmin, cE as JsonFormat, cF as KanbanViewConfig, cG as LIFECYCLE_EVENT_NAMES, cH as LifecycleEventHandler, cI as LinkFormat, cJ as MetricColor, cK as MoneyFieldAdmin, cL as MoneyFieldConfig, cM as MultiSelectFieldAdmin, cN as NamedAccessPolicy, cO as NavBadgeConfig, cP as NavGroup, cQ as NumberFieldAdmin, cR as NumberFormat, cS as NumberLimitFieldAdmin, cT as NumberLimitFieldConfig, cU as NumericOperation, cV as NumericUpdateOperator, cW as OIDCAdminAuthProvider, cX as OptionFormat, cY as OutboundEmail, cZ as PaginatedResult, c_ as PinnedNavItemRef, c$ as PublicAdminAuthProvider, d0 as QueryCollectionResult, d1 as RAGSearchResult, d2 as RadioFieldAdmin, d3 as RateLimitConfig, d4 as ReadonlyDatabaseAdapter, d5 as RichTextFeature, d6 as RichTextFieldConfig, d7 as SelectFieldAdmin, d8 as SqlWhereResult, d9 as StorageAdapter, da as TableViewConfig, db as TaskContext, dc as TaskLogger, dd as TaskRunStatus, de as TextFieldAdmin, df as TextFormat, dg as TextareaFieldAdmin, dh as TrashConfig, di as TrustProxyConfig, dj as TypedField, dk as UploadConfig, dl as UrlFieldAdmin, dm as UrlLinkValue, dn as ViewActionFeatures, dp as ViewComponentSlots, dq as ViewConfigBase, dr as ViewLayout, ds as ViewMetric, dt as ViewMetricGroupBy, du as ViewMetricGroupByConfig, dv as ViewMetricTrendConfig, dw as ViewSubMetric, dx as WhereClause, dy as WhereOperator, dz as WhereOperatorName, dA as WordLimitFieldAdmin, dB as WordLimitFieldConfig, dC as WorkflowMetadata, dD as WorkflowOnTransitionContext, dE as WorkflowOnTransitionHook, dF as WorkflowRole, dG as WorkflowState, dH as WorkflowTransitionContext, dI as coerceBooleanWhere, dJ as defineAction, dK as defineCalendarView, dL as defineCardsView, dM as defineGanttView, dN as defineKanbanView, dO as defineTableView, dP as defineView, dQ as defineWorkspace, dR as isAICollection, dS as parseMongoWhere, dT as parseSqlWhere } from './app-BBHBP-6V.cjs';
1
+ import { F as Field, B as Block, C as CollectionConfig, D as DyrectedConfig, A as AdminAuthConfig, P as PublicAdminAuthConfig, G as GlobalConfig, a as DeclarativeHookExpression, W as WorkflowConfig, b as AuthenticatedUser, c as WorkflowTransition, L as LifecycleEventName, d as LifecycleEvent, e as DatabaseAdapter, f as BaseDocument, H as HookRequestContext, T as TaskRunResult, g as TaskConfig, h as DetailActionOptions, i as DetailAction, j as DetailComputedOptions, k as ComputedHandler, l as DetailComputed, m as DetailCustomOptions, n as DetailCustom, o as DetailDividerOptions, p as DetailDivider, q as DisplayFieldOptions, r as DetailField, s as DetailItem, t as DetailGridOptions, u as DetailGrid, v as DetailRepeatOptions, w as DetailRepeat, x as DetailSectionOptions, y as DetailSection, z as DetailTabOptions, E as DetailTab, I as DetailTabsOptions, J as DetailTabs, K as DetailTextOptions, M as DetailText, N as DetailSchema, O as DyrectedContext, Q as AIConfig, R as AIPIIConfig, S as IdStrategy, U as CompiledNavTree, V as CompiledNavItem, X as UserNavigationPreferences, Y as DefineWorkspaceOptions, Z as ViewConfig, _ as DateTimeField, $ as RelationshipField, a0 as SelectField, a1 as ArrayField, a2 as FieldType, a3 as BooleanField, a4 as AuthConfig, a5 as AccessPolicyResolver, a6 as DateField, a7 as TextField, a8 as EmailField, a9 as IconField, aa as ImageField, ab as JoinField, ac as JsonField, ad as MoneyField, ae as MultiSelectField, af as NumberField, ag as ObjectField, ah as RadioField, ai as RichTextField, aj as RowField, ak as TextareaField, al as TimeField, am as UrlField } from './app-BpQPL2hY.cjs';
2
+ export { an as AIAction, ao as AIActionStatus, ap as AIActionType, aq as AIAuditActionType, ar as AIAuditRecord, as as AIChunk, at as AIMessage, au as AIPIIPattern, av as AIRateLimitResult, aw as AIRateLimitStore, ax as AIThread, ay as AIToolContext, az as AIToolDefinition, aA as AI_ACTIONS_COLLECTION, aB as AI_AUDIT_COLLECTION, aC as AI_CHUNKS_COLLECTION, aD as AI_MESSAGES_COLLECTION, aE as AI_THREADS_COLLECTION, aF as AccessConfig, aG as AccessFunction, aH as AccessFunctionArgs, aI as AccessResult, aJ as AccessRule, aK as ActionConfig, aL as ActionConfigBase, aM as ActionConfigWithHandler, aN as ActionConfigWithMutation, aO as ActionContext, aP as ActionType, aQ as AdminAuthAccessResolution, aR as AdminAuthClaimMapping, aS as AdminAuthMember, aT as AdminAuthProvider, aU as AdminAuthProviderMembersConfig, aV as AdminAuthProvisioningMode, aW as AdminAuthResolveAccessArgs, aX as AdminAuthResolvedIdentity, aY as AdminConfig, aZ as AdminDashboardComponentSlots, a_ as AdminIconName, a$ as AggregateArgs, b0 as AggregateCastType, b1 as AggregateCollectionResult, b2 as AggregateInput, b3 as AggregateOperation, b4 as AggregateResult, b5 as AppTrashConfig, b6 as BaseAdminAuthProvider, b7 as BaseFieldAdmin, b8 as BlockVariant, b9 as BlocksField, ba as BooleanFieldAdmin, bb as BooleanFormat, bc as CURRENT_NAV_PREFERENCES_VERSION, bd as CUSTOM_VIEW_FETCH_ALL_LIMIT, be as CalendarViewConfig, bf as CardsViewConfig, bg as CharacterLimitFieldAdmin, bh as CharacterLimitFieldConfig, bi as CollectionAfterChangeHook, bj as CollectionAfterDeleteHook, bk as CollectionAfterReadHook, bl as CollectionAfterReadHookEntry, bm as CollectionAfterRestoreHook, bn as CollectionAfterTransitionHook, bo as CollectionAfterTrashHook, bp as CollectionBeforeChangeHook, bq as CollectionBeforeChangeHookEntry, br as CollectionBeforeCommitHook, bs as CollectionBeforeDeleteHook, bt as CollectionBeforeReadHook, bu as CollectionBeforeReadHookEntry, bv as CollectionBeforeRestoreHook, bw as CollectionBeforeTransitionHook, bx as CollectionBeforeTrashHook, by as CollectionEmailConfig, bz as CollectionIndex, bA as CollectionListComponentSlots, bB as CollectionRAGConfig, bC as CollectionSchemaResult, bD as CollectionSummaryResult, bE as CollectionViewComponentSlots, bF as CompiledNavGroup, bG as CountOperation, bH as CustomAdminAuthProvider, bI as CustomViewConfig, bJ as CustomViewDataConfig, bK as DEFAULT_USER_NAV_PREFERENCES, bL as DateFieldAdmin, bM as DateFormat, bN as DefaultValueContext, bO as DefineActionOptions, bP as DefineCalendarViewOptions, bQ as DefineCardsViewOptions, bR as DefineCustomViewOptions, bS as DefineGanttViewOptions, bT as DefineKanbanViewOptions, bU as DefinePageInput, bV as DefineTableViewOptions, bW as DefineViewBaseOptions, bX as DefineViewOptions, bY as DetailSpan, bZ as DisplayTone, b_ as DisplayVariant, b$ as DistinctCountOperation, c0 as DistinctValuesOperation, c1 as DocumentFormComponentSlots, c2 as DynamicOptionItem, c3 as DynamicOptionsConfig, c4 as DynamicOptionsResolver, c5 as DynamicOptionsResolverArgs, c6 as DyrectedAIContext, c7 as DyrectedLoggerConfig, c8 as DyrectedObservabilityConfig, c9 as EmailFieldAdmin, ca as EmailTemplateArgs, cb as EmailTemplateResult, cc as FORM_SHELLS, cd as FieldAdminHooks, ce as FieldAdminOnChangeHook, cf as FieldAdminOnChangeHookArgs, cg as FieldAdminOptionsHook, ch as FieldAdminOptionsHookArgs, ci as FieldAdminOptionsHookResult, cj as FieldAfterReadHook, ck as FieldAfterReadHookArgs, cl as FieldBase, cm as FieldBeforeChangeHook, cn as FieldBeforeChangeHookArgs, co as FieldHook, cp as FieldHooks, cq as FileData, cr as FormShell, cs as GanttViewConfig, ct as GetDocumentResult, cu as GlobalAfterChangeHook, cv as GlobalAfterReadHook, cw as GlobalAfterReadHookEntry, cx as GlobalBeforeChangeHook, cy as GlobalBeforeChangeHookEntry, cz as GlobalBeforeReadHook, cA as GlobalBeforeReadHookEntry, cB as GlobalFormComponentSlots, cC as GlobalRAGConfig, cD as GlobalSchemaResult, cE as GlobalSummaryResult, cF as HeadingLevel, cG as HookFunction, cH as IconFieldAdmin, cI as ImageService, cJ as ImageTransformOptions, cK as InferAggregateResult, cL as JoinFieldAdmin, cM as JsonFieldAdmin, cN as JsonFormat, cO as KanbanViewConfig, cP as LIFECYCLE_EVENT_NAMES, cQ as LifecycleEventHandler, cR as LinkFormat, cS as MetricColor, cT as MoneyFieldAdmin, cU as MoneyFieldConfig, cV as MultiSelectFieldAdmin, cW as NamedAccessPolicy, cX as NavBadgeConfig, cY as NavGroup, cZ as NumberFieldAdmin, c_ as NumberFormat, c$ as NumberLimitFieldAdmin, d0 as NumberLimitFieldConfig, d1 as NumericOperation, d2 as NumericUpdateOperator, d3 as OIDCAdminAuthProvider, d4 as OptionFormat, d5 as OutboundEmail, d6 as PageAction, d7 as PageBreadcrumbItem, d8 as PageConfig, d9 as PaginatedResult, da as PinnedNavItemRef, db as PublicAdminAuthProvider, dc as QueryCollectionResult, dd as RAGSearchResult, de as RadioFieldAdmin, df as RateLimitConfig, dg as ReadonlyDatabaseAdapter, dh as RichTextFeature, di as RichTextFieldConfig, dj as SelectFieldAdmin, dk as SqlWhereResult, dl as StorageAdapter, dm as TableViewConfig, dn as TaskContext, dp as TaskLogger, dq as TaskRunStatus, dr as TextFieldAdmin, ds as TextFormat, dt as TextareaFieldAdmin, du as TrashConfig, dv as TrustProxyConfig, dw as TypedField, dx as UploadConfig, dy as UrlFieldAdmin, dz as UrlLinkValue, dA as ViewActionFeatures, dB as ViewComponentSlots, dC as ViewConfigBase, dD as ViewLayout, dE as ViewMetric, dF as ViewMetricGroupBy, dG as ViewMetricGroupByConfig, dH as ViewMetricTrendConfig, dI as ViewSubMetric, dJ as WhereClause, dK as WhereOperator, dL as WhereOperatorName, dM as WordLimitFieldAdmin, dN as WordLimitFieldConfig, dO as WorkflowMetadata, dP as WorkflowOnTransitionContext, dQ as WorkflowOnTransitionHook, dR as WorkflowRole, dS as WorkflowState, dT as WorkflowTransitionContext, dU as coerceBooleanWhere, dV as defineAction, dW as defineCalendarView, dX as defineCardsView, dY as defineCustomView, dZ as defineGanttView, d_ as defineKanbanView, d$ as definePage, e0 as defineTableView, e1 as defineView, e2 as defineWorkspace, e3 as isAICollection, e4 as parseMongoWhere, e5 as parseSqlWhere } from './app-BpQPL2hY.cjs';
3
3
  import jexl from 'jexl';
4
4
  import { Context } from 'hono';
5
5
  export { z } from 'zod';
@@ -280,7 +280,7 @@ interface DeclarativePreviewValidationIssue {
280
280
  }
281
281
  interface ConfigDiagnostic {
282
282
  severity: "error" | "warning";
283
- source: "declarativeHook" | "declarativeAccess" | "adminCondition" | "previewUrl";
283
+ source: "declarativeHook" | "declarativeAccess" | "adminCondition" | "previewUrl" | "adminComponents";
284
284
  path: string;
285
285
  surface: string;
286
286
  message: string;
@@ -292,7 +292,7 @@ type DiagnosticFormatOptions = {
292
292
  type DeclarativeValidationConfig = {
293
293
  blocks?: Array<Pick<Block, "fields"> & Partial<Pick<Block, "slug">>>;
294
294
  collections: Array<Pick<CollectionConfig, "fields" | "hooks" | "access" | "admin"> & Partial<Pick<CollectionConfig, "slug">>>;
295
- globals?: Array<Pick<GlobalConfig, "fields" | "hooks" | "access"> & Partial<Pick<GlobalConfig, "slug">>>;
295
+ globals?: Array<Pick<GlobalConfig, "fields" | "hooks" | "access" | "admin"> & Partial<Pick<GlobalConfig, "slug">>>;
296
296
  accessPolicies?: Record<string, unknown>;
297
297
  };
298
298
  declare function validateDeclarativeHookExpression(expression: string, surface: DeclarativeHookSurface, path: string): DeclarativeHookValidationIssue[];
@@ -305,6 +305,14 @@ declare function collectDeclarativeHookValidationIssues(config: DeclarativeValid
305
305
  declare function collectDeclarativeAccessValidationIssues(config: DeclarativeValidationConfig): DeclarativeAccessValidationIssue[];
306
306
  declare function collectAdminConditionValidationIssues(config: DeclarativeValidationConfig): DeclarativeAdminValidationIssue[];
307
307
  declare function collectPreviewUrlValidationIssues(config: DeclarativeValidationConfig): DeclarativePreviewValidationIssue[];
308
+ interface AdminComponentsValidationIssue {
309
+ path: string;
310
+ surface: "collection.admin.components" | "global.admin.components";
311
+ message: string;
312
+ expression: string;
313
+ }
314
+ /** Flags malformed `createForm`, `editForm`, `form` and `formShell` settings. */
315
+ declare function collectAdminComponentsValidationIssues(config: DeclarativeValidationConfig): AdminComponentsValidationIssue[];
308
316
  declare function assertValidAdminConditionsInConfig(config: DeclarativeValidationConfig, source?: string): void;
309
317
  declare function assertValidPreviewUrlsInConfig(config: DeclarativeValidationConfig, source?: string): void;
310
318
  declare function collectConfigDiagnostics(config: DeclarativeValidationConfig): ConfigDiagnostic[];
@@ -318,6 +326,38 @@ declare function isConfigValidationError(error: unknown): error is ConfigValidat
318
326
  declare function assertValidDeclarativeHooksInConfig(config: DeclarativeValidationConfig, source?: string): void;
319
327
  declare function assertValidDeclarativeAccessInConfig(config: DeclarativeValidationConfig, source?: string): void;
320
328
 
329
+ /**
330
+ * Component keys a schema references, grouped by the `AdminComponents`
331
+ * registry that must supply them.
332
+ *
333
+ * Registration happens in the host app's admin bundle, so this scan is the
334
+ * single source of truth for both type generation (CLI) and the admin's
335
+ * unused-registration warning.
336
+ */
337
+ interface ReferencedComponentKeys {
338
+ /** `field.admin.component` keys, resolved against `components.fields`. */
339
+ fields: Set<string>;
340
+ /** `admin.components.before/afterDashboard` keys. */
341
+ dashboard: Set<string>;
342
+ /** `collection.admin.components` list slots. */
343
+ collectionList: Set<string>;
344
+ /** Operational view slots (`collectionView` and per-view `components`). */
345
+ collectionView: Set<string>;
346
+ /** `createForm`, `editForm` and `form` keys on collections, and `editForm`/`form` on globals. */
347
+ forms: Set<string>;
348
+ /** `component` of views with `layout: "custom"`. */
349
+ viewLayouts: Set<string>;
350
+ /** `admin.pages[].component` keys. */
351
+ pages: Set<string>;
352
+ /** `displayCustom(name)` keys used in Detail View layouts. */
353
+ customComponents: Set<string>;
354
+ }
355
+ /**
356
+ * Collects every component key a schema (or a `DyrectedConfig`) references.
357
+ * Tolerant of partial or unknown shapes: anything unrecognised is skipped.
358
+ */
359
+ declare function collectReferencedComponentKeys(schema: unknown): ReferencedComponentKeys;
360
+
321
361
  /**
322
362
  * Transforms a string into a clean, URL-safe slug.
323
363
  * Strips accents, lowercases, removes non-alphanumeric characters, and hyphens whitespace.
@@ -1522,7 +1562,7 @@ declare function reconcileNavigation(baseTree: CompiledNavTree | null | undefine
1522
1562
  */
1523
1563
  declare const RESERVED_NAVIGATION_SLUGS: Set<string>;
1524
1564
  /**
1525
- * Validates that no navigation item uses a reserved system route slug.
1565
+ * Validates that no navigation item uses a reserved system route slug or duplicate slug.
1526
1566
  */
1527
1567
  declare function assertValidNavigationSlugs(navigation: DefineWorkspaceOptions[]): void;
1528
1568
  /**
@@ -2340,4 +2380,4 @@ declare function defineTab<const T extends readonly Field[]>(args: {
2340
2380
  fields: T;
2341
2381
  }): T;
2342
2382
 
2343
- export { AIConfig, type AIErrorCode, AIPIIConfig, type AccessConditions, AccessPolicyResolver, AdminAuthConfig, ArrayField, AuthConfig, type AuthDocFields, AuthenticatedUser, BASE62_ALPHABET, BUILTIN_JEXL_HELPERS, BaseDocument, Block, BooleanField, CROCKFORD_BASE32, CollectionConfig, CompiledNavItem, CompiledNavTree, ComputedHandler, type ConfigDiagnostic, ConfigValidationError, ConflictError, type CreatedAtFieldOptions, type CreatedByFieldOptions, DatabaseAdapter, DateField, DateTimeField, type DeclarativeAccessSurface, type DeclarativeAccessValidationIssue, type DeclarativeAdminSurface, type DeclarativeAdminValidationIssue, DeclarativeHookExpression, type DeclarativeHookSurface, type DeclarativeHookValidationIssue, type DeclarativePreviewSurface, type DeclarativePreviewValidationIssue, DefineWorkspaceOptions, DetailAction, DetailActionOptions, DetailComputed, DetailComputedOptions, DetailCustom, DetailCustomOptions, DetailDivider, DetailDividerOptions, DetailField, DetailGrid, DetailGridOptions, DetailItem, DetailRepeat, DetailRepeatOptions, DetailSchema, DetailSection, DetailSectionOptions, DetailTab, DetailTabOptions, DetailTabs, DetailTabsOptions, DetailText, DetailTextOptions, DisplayFieldOptions, DuplicateKeyError, DyrectedAIError, DyrectedConfig, DyrectedError, EMAIL_TEMPLATES_COLLECTION_CONFIG, EMAIL_TEMPLATES_COLLECTION_SLUG, EmailField, type ExprFunction, type ExtractCollectionSlugs, Field, FieldConditionBuilder, FieldType, ForbiddenError, type GenerateIdOptions, GlobalConfig, HookRequestContext, INTERNAL_SYSTEM_COLLECTIONS, IconField, IdStrategy, ImageField, type InferDocShape, JoinField, JsonField, LIFECYCLE_EVENTS_COLLECTION, type LayoutOptions, LifecycleEvent, LifecycleEventName, MatchBuilder, MoneyField, MultiSelectField, NANOID_ALPHABET, NON_NEGOTIABLE_CREDENTIAL_FIELDS, NotFoundError, NumberField, ObjectField, PII_REGEX_PATTERNS, type Prettify, PublicAdminAuthConfig, type PublishingWorkflowOptions, RESERVED_NAVIGATION_SLUGS, RadioField, type ReconcileNavigationOptions, type ReconciledNavTree, RelationshipField, type ResolvedTrashConfig, type RestoreDocumentOptions, RichTextField, type RoleOption, type RolesFieldOptions, RowField, type SanitizeDocForAIOptions, SelectField, type SoftDeleteOptions, type SortClause, type SortDirection, type SqlSortDialect, type SystemDocFields, TASK_LOCKS_COLLECTION, TASK_LOCKS_COLLECTION_CONFIG, TRASH_COLLECTION, TRASH_COLLECTION_CONFIG, TaskConfig, TaskRunResult, type TaskRunner, type TemplateBlock, TextField, TextareaField, TimeField, UNASSIGNED_GROUP_KEY, type UpdatedAtFieldOptions, type UpdatedByFieldOptions, type UploadDocFields, UrlField, UserNavigationPreferences, ValidationError, ViewConfig, WORKFLOW_HISTORY_COLLECTION, type WhenFunction, WorkflowConfig, WorkflowTransition, abs, addDays, alertBox, asCollection, assertValidAdminConditionsInConfig, assertValidDeclarativeAccessInConfig, assertValidDeclarativeHookExpression, assertValidDeclarativeHookResult, assertValidDeclarativeHooksInConfig, assertValidNavigationSlugs, assertValidPreviewUrlsInConfig, assertValidTrashInConfig, availableWorkflowTransitions, buildSqlOrderBy, canViewWorkflowDraft, capitalize, ceil, clamp, coalesce, collectAdminConditionValidationIssues, collectConfigDiagnostics, collectDeclarativeAccessValidationIssues, collectDeclarativeHookValidationIssues, collectPreviewUrlValidationIssues, compact, compileNavigation, count, createLifecycleEvent, createTaskRunner, createTrashPurgeTask, createWorkflowDocument, ctaButton, defaultValue, defineArrayField, defineBlock, defineBlocksField, defineBooleanField, defineCollection, defineConfig, defineCreatedAtField, defineCreatedByField, defineDateField, defineDateTimeField, defineEmailField, defineField, defineGlobal, defineIconField, defineImageField, defineJoinField, defineJsonField, defineMoneyField, defineMultiSelectField, defineNumberField, defineObjectField, definePublishingWorkflow, defineRadioField, defineRelationshipField, defineRichTextField, defineRoles, defineRolesField, defineRowField, defineSelectField, defineTab, defineTask, defineTextField, defineTextareaField, defineTimeField, defineUpdatedAtField, defineUpdatedByField, defineUrlField, detailBox, diffDays, dispatchLifecycleEvent, dispatchPendingLifecycleEvents, displayAction, displayComputed, displayCustom, displayCustomComponent, displayDivider, displayField, displayGrid, displayRepeat, displaySection, displayTab, displayTabs, displayText, divider, emailTokens, endsWith, escapeHtml, evaluateDetailComputed, evaluateJexl, evaluateJexlSync, eventList, executeFieldAfterRead, executeFieldBeforeChange, expr, first, floor, formatConfigDiagnostics, formatDate, formatJexlValue, generateDefaultDetailSchema, generateDocumentId, generateId, generateOpenApi, get, getAdminAuthCollection, getAdminRoleForCollection, getAllowedSitesForUser, getDefaultEmailTemplate, getPublicAdminAuthConfig, getTrashEntryId, heading, includes, initializeWorkflowDocument, isConfigValidationError, isDetailItemVisible, isEmpty, isFuture, isPast, isSiteAuthorized, isUserAdmin, join, last, layout, length, lower, maskEmail, maskPhone, maskTextPII, materializeWorkflowDocument, max, min, nanoid, nextCronRun, normalizeConfig, normalizeDetailItem, normalizeGroupKey, now, numericFieldNames, paragraph, parseCron, parseSort, pow, prefixedId, pruneNavigationForUser, publishedStateName, publishingWorkflow, readingTime, reconcileNavigation, registerJexlHelpers, replace, resolveAdminAuthCollection, resolveAllCollectionViews, resolveAuthorizedSiteId, resolveBlocks, resolveDocumentTitle, resolveIndexName, resolvePrefix, resolveTrashConfig, restoreDocument, round, row, runCollectionHooks, safeLinkDetailBox, sanitizeDocForAI, saveWorkflowDraft, sectionLabel, simplePublishingWorkflow, slugify, softDeleteDocument, spacer, sqrt, startsWith, sum, table, today, transitionWorkflow, trim, truncate, ulid, unique, upper, uuid, validateAdminConditionExpression, validateDeclarativeAccessExpression, validateDeclarativeHookExpression, validatePreviewUrlExpression, when, wordCount, workflowCapabilities };
2383
+ export { AIConfig, type AIErrorCode, AIPIIConfig, type AccessConditions, AccessPolicyResolver, AdminAuthConfig, type AdminComponentsValidationIssue, ArrayField, AuthConfig, type AuthDocFields, AuthenticatedUser, BASE62_ALPHABET, BUILTIN_JEXL_HELPERS, BaseDocument, Block, BooleanField, CROCKFORD_BASE32, CollectionConfig, CompiledNavItem, CompiledNavTree, ComputedHandler, type ConfigDiagnostic, ConfigValidationError, ConflictError, type CreatedAtFieldOptions, type CreatedByFieldOptions, DatabaseAdapter, DateField, DateTimeField, type DeclarativeAccessSurface, type DeclarativeAccessValidationIssue, type DeclarativeAdminSurface, type DeclarativeAdminValidationIssue, DeclarativeHookExpression, type DeclarativeHookSurface, type DeclarativeHookValidationIssue, type DeclarativePreviewSurface, type DeclarativePreviewValidationIssue, DefineWorkspaceOptions, DetailAction, DetailActionOptions, DetailComputed, DetailComputedOptions, DetailCustom, DetailCustomOptions, DetailDivider, DetailDividerOptions, DetailField, DetailGrid, DetailGridOptions, DetailItem, DetailRepeat, DetailRepeatOptions, DetailSchema, DetailSection, DetailSectionOptions, DetailTab, DetailTabOptions, DetailTabs, DetailTabsOptions, DetailText, DetailTextOptions, DisplayFieldOptions, DuplicateKeyError, DyrectedAIError, DyrectedConfig, DyrectedError, EMAIL_TEMPLATES_COLLECTION_CONFIG, EMAIL_TEMPLATES_COLLECTION_SLUG, EmailField, type ExprFunction, type ExtractCollectionSlugs, Field, FieldConditionBuilder, FieldType, ForbiddenError, type GenerateIdOptions, GlobalConfig, HookRequestContext, INTERNAL_SYSTEM_COLLECTIONS, IconField, IdStrategy, ImageField, type InferDocShape, JoinField, JsonField, LIFECYCLE_EVENTS_COLLECTION, type LayoutOptions, LifecycleEvent, LifecycleEventName, MatchBuilder, MoneyField, MultiSelectField, NANOID_ALPHABET, NON_NEGOTIABLE_CREDENTIAL_FIELDS, NotFoundError, NumberField, ObjectField, PII_REGEX_PATTERNS, type Prettify, PublicAdminAuthConfig, type PublishingWorkflowOptions, RESERVED_NAVIGATION_SLUGS, RadioField, type ReconcileNavigationOptions, type ReconciledNavTree, type ReferencedComponentKeys, RelationshipField, type ResolvedTrashConfig, type RestoreDocumentOptions, RichTextField, type RoleOption, type RolesFieldOptions, RowField, type SanitizeDocForAIOptions, SelectField, type SoftDeleteOptions, type SortClause, type SortDirection, type SqlSortDialect, type SystemDocFields, TASK_LOCKS_COLLECTION, TASK_LOCKS_COLLECTION_CONFIG, TRASH_COLLECTION, TRASH_COLLECTION_CONFIG, TaskConfig, TaskRunResult, type TaskRunner, type TemplateBlock, TextField, TextareaField, TimeField, UNASSIGNED_GROUP_KEY, type UpdatedAtFieldOptions, type UpdatedByFieldOptions, type UploadDocFields, UrlField, UserNavigationPreferences, ValidationError, ViewConfig, WORKFLOW_HISTORY_COLLECTION, type WhenFunction, WorkflowConfig, WorkflowTransition, abs, addDays, alertBox, asCollection, assertValidAdminConditionsInConfig, assertValidDeclarativeAccessInConfig, assertValidDeclarativeHookExpression, assertValidDeclarativeHookResult, assertValidDeclarativeHooksInConfig, assertValidNavigationSlugs, assertValidPreviewUrlsInConfig, assertValidTrashInConfig, availableWorkflowTransitions, buildSqlOrderBy, canViewWorkflowDraft, capitalize, ceil, clamp, coalesce, collectAdminComponentsValidationIssues, collectAdminConditionValidationIssues, collectConfigDiagnostics, collectDeclarativeAccessValidationIssues, collectDeclarativeHookValidationIssues, collectPreviewUrlValidationIssues, collectReferencedComponentKeys, compact, compileNavigation, count, createLifecycleEvent, createTaskRunner, createTrashPurgeTask, createWorkflowDocument, ctaButton, defaultValue, defineArrayField, defineBlock, defineBlocksField, defineBooleanField, defineCollection, defineConfig, defineCreatedAtField, defineCreatedByField, defineDateField, defineDateTimeField, defineEmailField, defineField, defineGlobal, defineIconField, defineImageField, defineJoinField, defineJsonField, defineMoneyField, defineMultiSelectField, defineNumberField, defineObjectField, definePublishingWorkflow, defineRadioField, defineRelationshipField, defineRichTextField, defineRoles, defineRolesField, defineRowField, defineSelectField, defineTab, defineTask, defineTextField, defineTextareaField, defineTimeField, defineUpdatedAtField, defineUpdatedByField, defineUrlField, detailBox, diffDays, dispatchLifecycleEvent, dispatchPendingLifecycleEvents, displayAction, displayComputed, displayCustom, displayCustomComponent, displayDivider, displayField, displayGrid, displayRepeat, displaySection, displayTab, displayTabs, displayText, divider, emailTokens, endsWith, escapeHtml, evaluateDetailComputed, evaluateJexl, evaluateJexlSync, eventList, executeFieldAfterRead, executeFieldBeforeChange, expr, first, floor, formatConfigDiagnostics, formatDate, formatJexlValue, generateDefaultDetailSchema, generateDocumentId, generateId, generateOpenApi, get, getAdminAuthCollection, getAdminRoleForCollection, getAllowedSitesForUser, getDefaultEmailTemplate, getPublicAdminAuthConfig, getTrashEntryId, heading, includes, initializeWorkflowDocument, isConfigValidationError, isDetailItemVisible, isEmpty, isFuture, isPast, isSiteAuthorized, isUserAdmin, join, last, layout, length, lower, maskEmail, maskPhone, maskTextPII, materializeWorkflowDocument, max, min, nanoid, nextCronRun, normalizeConfig, normalizeDetailItem, normalizeGroupKey, now, numericFieldNames, paragraph, parseCron, parseSort, pow, prefixedId, pruneNavigationForUser, publishedStateName, publishingWorkflow, readingTime, reconcileNavigation, registerJexlHelpers, replace, resolveAdminAuthCollection, resolveAllCollectionViews, resolveAuthorizedSiteId, resolveBlocks, resolveDocumentTitle, resolveIndexName, resolvePrefix, resolveTrashConfig, restoreDocument, round, row, runCollectionHooks, safeLinkDetailBox, sanitizeDocForAI, saveWorkflowDraft, sectionLabel, simplePublishingWorkflow, slugify, softDeleteDocument, spacer, sqrt, startsWith, sum, table, today, transitionWorkflow, trim, truncate, ulid, unique, upper, uuid, validateAdminConditionExpression, validateDeclarativeAccessExpression, validateDeclarativeHookExpression, validatePreviewUrlExpression, when, wordCount, workflowCapabilities };