@dyrected/core 2.21.0 → 2.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{app-BNdnl0s-.d.cts → app-DregJnqR.d.cts} +165 -7
- package/dist/{app-BNdnl0s-.d.ts → app-DregJnqR.d.ts} +165 -7
- package/dist/index.cjs +219 -8
- package/dist/index.d.cts +36 -4
- package/dist/index.d.ts +36 -4
- package/dist/index.js +215 -8
- package/dist/server.cjs +89 -20
- package/dist/server.d.cts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +89 -20
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1789,9 +1789,19 @@ var LIFECYCLE_EVENT_NAMES = [
|
|
|
1789
1789
|
];
|
|
1790
1790
|
|
|
1791
1791
|
// src/types/views.ts
|
|
1792
|
+
var CUSTOM_VIEW_FETCH_ALL_LIMIT = 1e3;
|
|
1792
1793
|
function defineView(config) {
|
|
1794
|
+
assertCustomViewComponent(config);
|
|
1793
1795
|
return config;
|
|
1794
1796
|
}
|
|
1797
|
+
function assertCustomViewComponent(config) {
|
|
1798
|
+
if (config.layout !== "custom") return;
|
|
1799
|
+
if (typeof config.component !== "string" || config.component.trim() === "") {
|
|
1800
|
+
throw new Error(
|
|
1801
|
+
`View "${config.slug ?? "(unnamed)"}" uses layout: "custom" but has no \`component\`. Set \`component\` to a key registered in AdminComponents.viewLayouts.`
|
|
1802
|
+
);
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1795
1805
|
function defineTableView(config) {
|
|
1796
1806
|
return config;
|
|
1797
1807
|
}
|
|
@@ -1804,6 +1814,10 @@ function defineCalendarView(config) {
|
|
|
1804
1814
|
function defineGanttView(config) {
|
|
1805
1815
|
return config;
|
|
1806
1816
|
}
|
|
1817
|
+
function defineCustomView(config) {
|
|
1818
|
+
assertCustomViewComponent(config);
|
|
1819
|
+
return config;
|
|
1820
|
+
}
|
|
1807
1821
|
function defineCardsView(config) {
|
|
1808
1822
|
return config;
|
|
1809
1823
|
}
|
|
@@ -1860,6 +1874,23 @@ var DEFAULT_USER_NAV_PREFERENCES = {
|
|
|
1860
1874
|
items: []
|
|
1861
1875
|
};
|
|
1862
1876
|
|
|
1877
|
+
// src/types/pages.ts
|
|
1878
|
+
function definePage(config) {
|
|
1879
|
+
return {
|
|
1880
|
+
slug: config.slug,
|
|
1881
|
+
label: config.label,
|
|
1882
|
+
icon: config.icon,
|
|
1883
|
+
group: config.group,
|
|
1884
|
+
order: config.order,
|
|
1885
|
+
after: config.after,
|
|
1886
|
+
before: config.before,
|
|
1887
|
+
position: config.position,
|
|
1888
|
+
badge: config.badge,
|
|
1889
|
+
access: config.access && typeof config.access === "object" && "read" in config.access ? config.access.read : config.access,
|
|
1890
|
+
page: config
|
|
1891
|
+
};
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1863
1894
|
// src/auth/token.ts
|
|
1864
1895
|
import { SignJWT, jwtVerify, decodeJwt } from "jose";
|
|
1865
1896
|
|
|
@@ -5189,6 +5220,12 @@ var DuplicateKeyError = class _DuplicateKeyError extends ConflictError {
|
|
|
5189
5220
|
function assertNever(op, context) {
|
|
5190
5221
|
throw new Error(`[dyrected/core] Unhandled where operator "${op}" in ${context}`);
|
|
5191
5222
|
}
|
|
5223
|
+
function escapeLike(value) {
|
|
5224
|
+
return value.replace(/[!%_]/g, "!$&");
|
|
5225
|
+
}
|
|
5226
|
+
function escapeRegex(value) {
|
|
5227
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5228
|
+
}
|
|
5192
5229
|
function parseSqlWhere(where, getJsonField, placeholder = "?", likeOperator = placeholder === "pg" ? "ILIKE" : "LIKE") {
|
|
5193
5230
|
const params = [];
|
|
5194
5231
|
let pgIndex = 1;
|
|
@@ -5198,6 +5235,19 @@ function parseSqlWhere(where, getJsonField, placeholder = "?", likeOperator = pl
|
|
|
5198
5235
|
function col(field) {
|
|
5199
5236
|
return field === "id" ? "id" : getJsonField(field);
|
|
5200
5237
|
}
|
|
5238
|
+
function buildLike(column, pattern, escaped = false) {
|
|
5239
|
+
const esc = escaped ? ` ESCAPE '!'` : "";
|
|
5240
|
+
if (placeholder === "pg") {
|
|
5241
|
+
params.push(pattern);
|
|
5242
|
+
return `(${column})::text ${likeOperator} ${next()}${esc}`;
|
|
5243
|
+
}
|
|
5244
|
+
if (likeOperator === "ILIKE") {
|
|
5245
|
+
params.push(pattern);
|
|
5246
|
+
return `${column} ILIKE ${next()}${esc}`;
|
|
5247
|
+
}
|
|
5248
|
+
params.push(pattern.toLowerCase());
|
|
5249
|
+
return `LOWER(${column}) LIKE ${next()}${esc}`;
|
|
5250
|
+
}
|
|
5201
5251
|
function buildOperator(field, value) {
|
|
5202
5252
|
const c = col(field);
|
|
5203
5253
|
const isJsonExtract = c.startsWith("data->>") || c.startsWith("json_extract(") || c.startsWith("JSON_UNQUOTE(");
|
|
@@ -5340,13 +5390,12 @@ function parseSqlWhere(where, getJsonField, placeholder = "?", likeOperator = pl
|
|
|
5340
5390
|
case "less_than_or_equal":
|
|
5341
5391
|
params.push(operand);
|
|
5342
5392
|
return `${c} <= ${next()}`;
|
|
5343
|
-
case "contains":
|
|
5344
5393
|
case "like":
|
|
5345
|
-
|
|
5346
|
-
|
|
5394
|
+
return buildLike(c, `%${String(operand)}%`);
|
|
5395
|
+
case "contains":
|
|
5396
|
+
return buildLike(c, `%${escapeLike(String(operand))}%`, true);
|
|
5347
5397
|
case "starts_with":
|
|
5348
|
-
|
|
5349
|
-
return placeholder === "pg" ? `(${c})::text ${likeOperator} ${next()}` : `${c} ${likeOperator} ${next()}`;
|
|
5398
|
+
return buildLike(c, `${escapeLike(String(operand))}%`, true);
|
|
5350
5399
|
case "exists":
|
|
5351
5400
|
return operand ? `${c} IS NOT NULL` : `${c} IS NULL`;
|
|
5352
5401
|
default:
|
|
@@ -5444,9 +5493,9 @@ function parseMongoWhere(where) {
|
|
|
5444
5493
|
return { [field]: { $lte: operand } };
|
|
5445
5494
|
case "contains":
|
|
5446
5495
|
case "like":
|
|
5447
|
-
return { [field]: { $regex: operand, $options: "i" } };
|
|
5496
|
+
return { [field]: { $regex: escapeRegex(String(operand)), $options: "i" } };
|
|
5448
5497
|
case "starts_with":
|
|
5449
|
-
return { [field]: { $regex: `^${operand}`, $options: "i" } };
|
|
5498
|
+
return { [field]: { $regex: `^${escapeRegex(String(operand))}`, $options: "i" } };
|
|
5450
5499
|
case "exists":
|
|
5451
5500
|
return { [field]: { $exists: operand } };
|
|
5452
5501
|
default:
|
|
@@ -5556,6 +5605,96 @@ function buildSqlOrderBy(sort, existingColumns, numericFields, dialect) {
|
|
|
5556
5605
|
}).join(", ");
|
|
5557
5606
|
}
|
|
5558
5607
|
|
|
5608
|
+
// src/utils/component-keys.ts
|
|
5609
|
+
var DASHBOARD_SLOTS = ["beforeDashboard", "afterDashboard"];
|
|
5610
|
+
var LIST_SLOTS = ["beforeList", "beforeListTable", "afterListTable", "afterList"];
|
|
5611
|
+
var VIEW_SLOTS = ["beforeViewHeader", "afterViewHeader", "beforeViewContent", "afterViewContent"];
|
|
5612
|
+
function addKeys(target, value) {
|
|
5613
|
+
for (const key of Array.isArray(value) ? value : [value]) {
|
|
5614
|
+
if (typeof key === "string" && key) target.add(key);
|
|
5615
|
+
}
|
|
5616
|
+
}
|
|
5617
|
+
function addSlots(target, slots, names) {
|
|
5618
|
+
if (!slots || typeof slots !== "object") return;
|
|
5619
|
+
for (const name of names) addKeys(target, slots[name]);
|
|
5620
|
+
}
|
|
5621
|
+
function scanFields(fields, keys) {
|
|
5622
|
+
if (!Array.isArray(fields)) return;
|
|
5623
|
+
for (const field of fields) {
|
|
5624
|
+
if (!field || typeof field !== "object") continue;
|
|
5625
|
+
addKeys(keys.fields, field.admin?.component);
|
|
5626
|
+
scanFields(field.fields, keys);
|
|
5627
|
+
if (Array.isArray(field.blocks)) {
|
|
5628
|
+
for (const block of field.blocks) scanFields(block?.fields, keys);
|
|
5629
|
+
}
|
|
5630
|
+
if (Array.isArray(field.tabs)) {
|
|
5631
|
+
for (const tab of field.tabs) scanFields(tab?.fields, keys);
|
|
5632
|
+
}
|
|
5633
|
+
}
|
|
5634
|
+
}
|
|
5635
|
+
function scanDetail(items, keys) {
|
|
5636
|
+
if (!Array.isArray(items)) return;
|
|
5637
|
+
for (const item of items) {
|
|
5638
|
+
if (!item || typeof item !== "object") continue;
|
|
5639
|
+
if (item.type === "custom") addKeys(keys.customComponents, item.name);
|
|
5640
|
+
scanDetail(item.items, keys);
|
|
5641
|
+
if (Array.isArray(item.tabs)) {
|
|
5642
|
+
for (const tab of item.tabs) scanDetail(tab?.items, keys);
|
|
5643
|
+
}
|
|
5644
|
+
}
|
|
5645
|
+
}
|
|
5646
|
+
function scanViews(views, keys) {
|
|
5647
|
+
if (!Array.isArray(views)) return;
|
|
5648
|
+
for (const view of views) {
|
|
5649
|
+
addSlots(keys.collectionView, view?.components, VIEW_SLOTS);
|
|
5650
|
+
if (view?.layout === "custom") addKeys(keys.viewLayouts, view.component);
|
|
5651
|
+
}
|
|
5652
|
+
}
|
|
5653
|
+
function collectReferencedComponentKeys(schema) {
|
|
5654
|
+
const keys = {
|
|
5655
|
+
fields: /* @__PURE__ */ new Set(),
|
|
5656
|
+
dashboard: /* @__PURE__ */ new Set(),
|
|
5657
|
+
collectionList: /* @__PURE__ */ new Set(),
|
|
5658
|
+
collectionView: /* @__PURE__ */ new Set(),
|
|
5659
|
+
forms: /* @__PURE__ */ new Set(),
|
|
5660
|
+
viewLayouts: /* @__PURE__ */ new Set(),
|
|
5661
|
+
pages: /* @__PURE__ */ new Set(),
|
|
5662
|
+
customComponents: /* @__PURE__ */ new Set()
|
|
5663
|
+
};
|
|
5664
|
+
const root = schema;
|
|
5665
|
+
if (!root || typeof root !== "object") return keys;
|
|
5666
|
+
addSlots(keys.dashboard, root.admin?.components, DASHBOARD_SLOTS);
|
|
5667
|
+
if (Array.isArray(root.admin?.navigation)) {
|
|
5668
|
+
for (const item of root.admin.navigation) {
|
|
5669
|
+
if (item?.page) {
|
|
5670
|
+
if (typeof item.page === "string") {
|
|
5671
|
+
addKeys(keys.pages, item.page);
|
|
5672
|
+
} else if (item.page?.component) {
|
|
5673
|
+
addKeys(keys.pages, item.page.component);
|
|
5674
|
+
}
|
|
5675
|
+
}
|
|
5676
|
+
}
|
|
5677
|
+
}
|
|
5678
|
+
if (Array.isArray(root.admin?.pages)) {
|
|
5679
|
+
for (const page of root.admin.pages) addKeys(keys.pages, page?.component);
|
|
5680
|
+
}
|
|
5681
|
+
for (const block of root.blocks ?? []) scanFields(block?.fields, keys);
|
|
5682
|
+
for (const collection of root.collections ?? []) {
|
|
5683
|
+
scanFields(collection.fields, keys);
|
|
5684
|
+
scanDetail(collection.detail, keys);
|
|
5685
|
+
scanViews(collection.views, keys);
|
|
5686
|
+
const slots = collection.admin?.components;
|
|
5687
|
+
addSlots(keys.collectionList, slots, LIST_SLOTS);
|
|
5688
|
+
addSlots(keys.collectionView, slots, VIEW_SLOTS);
|
|
5689
|
+
addSlots(keys.collectionView, slots?.collectionView, VIEW_SLOTS);
|
|
5690
|
+
}
|
|
5691
|
+
for (const global of root.globals ?? []) {
|
|
5692
|
+
scanFields(global.fields, keys);
|
|
5693
|
+
scanDetail(global.detail, keys);
|
|
5694
|
+
}
|
|
5695
|
+
return keys;
|
|
5696
|
+
}
|
|
5697
|
+
|
|
5559
5698
|
// src/utils/openapi.ts
|
|
5560
5699
|
function getCollectionLabels(collection) {
|
|
5561
5700
|
return collection.labels || { singular: collection.slug, plural: collection.slug };
|
|
@@ -8043,11 +8182,32 @@ var RESERVED_NAVIGATION_SLUGS = /* @__PURE__ */ new Set([
|
|
|
8043
8182
|
"admin",
|
|
8044
8183
|
"preferences",
|
|
8045
8184
|
"auth",
|
|
8046
|
-
"trash"
|
|
8185
|
+
"trash",
|
|
8186
|
+
"pages"
|
|
8047
8187
|
]);
|
|
8048
8188
|
function assertValidNavigationSlugs(navigation) {
|
|
8189
|
+
const seenWorkspaceSlugs = /* @__PURE__ */ new Set();
|
|
8190
|
+
const seenPageSlugs = /* @__PURE__ */ new Set();
|
|
8049
8191
|
for (const item of navigation) {
|
|
8050
8192
|
if (item.dashboard || item.trash) continue;
|
|
8193
|
+
if (item.page) {
|
|
8194
|
+
const pageSlug = typeof item.page === "string" ? item.slug || item.page : item.slug || item.page.slug;
|
|
8195
|
+
if (pageSlug) {
|
|
8196
|
+
const normalized = pageSlug.toLowerCase().trim().replace(/^\//, "");
|
|
8197
|
+
if (RESERVED_NAVIGATION_SLUGS.has(normalized)) {
|
|
8198
|
+
throw new Error(
|
|
8199
|
+
`[Dyrected Config] The slug '${pageSlug}' in custom page '${item.label || pageSlug}' is a reserved system path and cannot be used as a page slug.`
|
|
8200
|
+
);
|
|
8201
|
+
}
|
|
8202
|
+
if (seenPageSlugs.has(normalized)) {
|
|
8203
|
+
throw new Error(
|
|
8204
|
+
`[Dyrected Config] Duplicate page slug '${pageSlug}' in navigation. Page slugs must be unique.`
|
|
8205
|
+
);
|
|
8206
|
+
}
|
|
8207
|
+
seenPageSlugs.add(normalized);
|
|
8208
|
+
}
|
|
8209
|
+
continue;
|
|
8210
|
+
}
|
|
8051
8211
|
if (item.slug) {
|
|
8052
8212
|
const normalizedSlug = item.slug.toLowerCase().trim().replace(/^\//, "");
|
|
8053
8213
|
if (RESERVED_NAVIGATION_SLUGS.has(normalizedSlug)) {
|
|
@@ -8055,6 +8215,12 @@ function assertValidNavigationSlugs(navigation) {
|
|
|
8055
8215
|
`[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.`
|
|
8056
8216
|
);
|
|
8057
8217
|
}
|
|
8218
|
+
if (seenWorkspaceSlugs.has(normalizedSlug)) {
|
|
8219
|
+
throw new Error(
|
|
8220
|
+
`[Dyrected Config] Duplicate workspace slug '${item.slug}' in navigation. Workspace slugs must be unique.`
|
|
8221
|
+
);
|
|
8222
|
+
}
|
|
8223
|
+
seenWorkspaceSlugs.add(normalizedSlug);
|
|
8058
8224
|
}
|
|
8059
8225
|
}
|
|
8060
8226
|
}
|
|
@@ -8197,6 +8363,43 @@ function compileNavigation(config) {
|
|
|
8197
8363
|
});
|
|
8198
8364
|
continue;
|
|
8199
8365
|
}
|
|
8366
|
+
if (item.page) {
|
|
8367
|
+
const pageConfig = typeof item.page === "string" ? {
|
|
8368
|
+
slug: item.slug || item.page,
|
|
8369
|
+
label: item.label || item.page,
|
|
8370
|
+
icon: item.icon,
|
|
8371
|
+
component: item.page,
|
|
8372
|
+
group: typeof item.group === "string" ? item.group : item.group?.name,
|
|
8373
|
+
order: item.order,
|
|
8374
|
+
badge: item.badge,
|
|
8375
|
+
access: item.access
|
|
8376
|
+
} : {
|
|
8377
|
+
...item.page,
|
|
8378
|
+
slug: item.slug || item.page.slug || "page",
|
|
8379
|
+
label: item.label || item.page.label || item.slug || "Page",
|
|
8380
|
+
icon: item.icon || item.page.icon,
|
|
8381
|
+
group: item.group ? typeof item.group === "string" ? item.group : item.group?.name : item.page.group,
|
|
8382
|
+
order: item.order ?? item.page.order,
|
|
8383
|
+
badge: item.badge || item.page.badge,
|
|
8384
|
+
access: item.access || (item.page.access && typeof item.page.access === "object" && "read" in item.page.access ? item.page.access.read : item.page.access)
|
|
8385
|
+
};
|
|
8386
|
+
const pageSlug = pageConfig.slug || "page";
|
|
8387
|
+
registerItem(groupName, {
|
|
8388
|
+
id: `page:${pageSlug}`,
|
|
8389
|
+
type: "page",
|
|
8390
|
+
slug: pageSlug,
|
|
8391
|
+
label: pageConfig.label || pageSlug,
|
|
8392
|
+
icon: pageConfig.icon || "FileText",
|
|
8393
|
+
href: `/pages/${pageSlug}`,
|
|
8394
|
+
group: groupName,
|
|
8395
|
+
order: pageConfig.order ?? 100,
|
|
8396
|
+
views: [],
|
|
8397
|
+
badge: pageConfig.badge,
|
|
8398
|
+
access: pageConfig.access && typeof pageConfig.access === "object" && "read" in pageConfig.access ? pageConfig.access.read : pageConfig.access,
|
|
8399
|
+
page: pageConfig
|
|
8400
|
+
});
|
|
8401
|
+
continue;
|
|
8402
|
+
}
|
|
8200
8403
|
const workspaceSlug = item.slug || "workspace";
|
|
8201
8404
|
registerItem(groupName, {
|
|
8202
8405
|
id: `workspace_${workspaceSlug}`,
|
|
@@ -8578,6 +8781,7 @@ export {
|
|
|
8578
8781
|
BUILTIN_JEXL_HELPERS,
|
|
8579
8782
|
CROCKFORD_BASE32,
|
|
8580
8783
|
CURRENT_NAV_PREFERENCES_VERSION,
|
|
8784
|
+
CUSTOM_VIEW_FETCH_ALL_LIMIT,
|
|
8581
8785
|
ConfigValidationError,
|
|
8582
8786
|
ConflictError,
|
|
8583
8787
|
DEFAULT_USER_NAV_PREFERENCES,
|
|
@@ -8629,6 +8833,7 @@ export {
|
|
|
8629
8833
|
collectDeclarativeAccessValidationIssues,
|
|
8630
8834
|
collectDeclarativeHookValidationIssues,
|
|
8631
8835
|
collectPreviewUrlValidationIssues,
|
|
8836
|
+
collectReferencedComponentKeys,
|
|
8632
8837
|
compact,
|
|
8633
8838
|
compileNavigation,
|
|
8634
8839
|
count,
|
|
@@ -8649,6 +8854,7 @@ export {
|
|
|
8649
8854
|
defineConfig,
|
|
8650
8855
|
defineCreatedAtField,
|
|
8651
8856
|
defineCreatedByField,
|
|
8857
|
+
defineCustomView,
|
|
8652
8858
|
defineDateField,
|
|
8653
8859
|
defineDateTimeField,
|
|
8654
8860
|
defineEmailField,
|
|
@@ -8664,6 +8870,7 @@ export {
|
|
|
8664
8870
|
defineMultiSelectField,
|
|
8665
8871
|
defineNumberField,
|
|
8666
8872
|
defineObjectField,
|
|
8873
|
+
definePage,
|
|
8667
8874
|
definePublishingWorkflow,
|
|
8668
8875
|
defineRadioField,
|
|
8669
8876
|
defineRelationshipField,
|
package/dist/server.cjs
CHANGED
|
@@ -6713,20 +6713,12 @@ function isUserAdmin(user, collection) {
|
|
|
6713
6713
|
}
|
|
6714
6714
|
|
|
6715
6715
|
// src/utils/collection-search.ts
|
|
6716
|
-
var DEFAULT_SEARCHABLE_NAMES = /* @__PURE__ */ new Set([
|
|
6717
|
-
"title",
|
|
6718
|
-
"name",
|
|
6719
|
-
"label",
|
|
6720
|
-
"slug",
|
|
6721
|
-
"email",
|
|
6722
|
-
"caption",
|
|
6723
|
-
"description"
|
|
6724
|
-
]);
|
|
6725
6716
|
var MAX_RELATION_MATCHES = 50;
|
|
6717
|
+
var MAX_DEFAULT_SEARCH_FIELDS = 8;
|
|
6726
6718
|
var MAX_RELATION_TITLE_DEPTH = 8;
|
|
6727
6719
|
var TITLE_FALLBACK_NAMES = ["title", "name", "label", "heading", "email", "subject"];
|
|
6728
6720
|
function isScalarSearchField(field) {
|
|
6729
|
-
return field.type === "text" || field.type === "textarea" || field.type === "richText" || field.type === "email";
|
|
6721
|
+
return field.type === "text" || field.type === "textarea" || field.type === "richText" || field.type === "email" || field.type === "url";
|
|
6730
6722
|
}
|
|
6731
6723
|
function findFieldByName(collection, fieldName) {
|
|
6732
6724
|
if (!fieldName) return void 0;
|
|
@@ -6741,10 +6733,20 @@ function resolveCollectionTitleField(collection) {
|
|
|
6741
6733
|
}
|
|
6742
6734
|
return collection.fields.find((field) => !!field.name && field.type !== "join" && field.type !== "row");
|
|
6743
6735
|
}
|
|
6736
|
+
function flattenNamedFields(fields) {
|
|
6737
|
+
const result = [];
|
|
6738
|
+
for (const field of fields) {
|
|
6739
|
+
if (field.type === "row" && field.fields) {
|
|
6740
|
+
result.push(...flattenNamedFields(field.fields));
|
|
6741
|
+
continue;
|
|
6742
|
+
}
|
|
6743
|
+
if (field.name) result.push(field);
|
|
6744
|
+
}
|
|
6745
|
+
return result;
|
|
6746
|
+
}
|
|
6744
6747
|
function getCollectionSearchableFields(collection) {
|
|
6745
|
-
const
|
|
6746
|
-
|
|
6747
|
-
);
|
|
6748
|
+
const namedFields = flattenNamedFields(collection.fields);
|
|
6749
|
+
const fieldByName = new Map(namedFields.map((field) => [field.name, field]));
|
|
6748
6750
|
const configured = collection.admin?.searchableFields?.map((fieldName) => fieldByName.get(fieldName)).filter((field) => !!field);
|
|
6749
6751
|
if (configured && configured.length > 0) {
|
|
6750
6752
|
return configured;
|
|
@@ -6755,12 +6757,12 @@ function getCollectionSearchableFields(collection) {
|
|
|
6755
6757
|
if (results.some((item) => item.name === field.name)) return;
|
|
6756
6758
|
results.push(field);
|
|
6757
6759
|
};
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
if (
|
|
6762
|
-
|
|
6763
|
-
|
|
6760
|
+
const titleField = collection.admin?.useAsTitle ? fieldByName.get(collection.admin.useAsTitle) : void 0;
|
|
6761
|
+
pushUnique(titleField);
|
|
6762
|
+
for (const field of namedFields) {
|
|
6763
|
+
if (results.length >= MAX_DEFAULT_SEARCH_FIELDS) break;
|
|
6764
|
+
if (field.admin?.hidden || !isScalarSearchField(field)) continue;
|
|
6765
|
+
pushUnique(field);
|
|
6764
6766
|
}
|
|
6765
6767
|
return results;
|
|
6766
6768
|
}
|
|
@@ -7185,11 +7187,32 @@ var RESERVED_NAVIGATION_SLUGS = /* @__PURE__ */ new Set([
|
|
|
7185
7187
|
"admin",
|
|
7186
7188
|
"preferences",
|
|
7187
7189
|
"auth",
|
|
7188
|
-
"trash"
|
|
7190
|
+
"trash",
|
|
7191
|
+
"pages"
|
|
7189
7192
|
]);
|
|
7190
7193
|
function assertValidNavigationSlugs(navigation) {
|
|
7194
|
+
const seenWorkspaceSlugs = /* @__PURE__ */ new Set();
|
|
7195
|
+
const seenPageSlugs = /* @__PURE__ */ new Set();
|
|
7191
7196
|
for (const item of navigation) {
|
|
7192
7197
|
if (item.dashboard || item.trash) continue;
|
|
7198
|
+
if (item.page) {
|
|
7199
|
+
const pageSlug = typeof item.page === "string" ? item.slug || item.page : item.slug || item.page.slug;
|
|
7200
|
+
if (pageSlug) {
|
|
7201
|
+
const normalized = pageSlug.toLowerCase().trim().replace(/^\//, "");
|
|
7202
|
+
if (RESERVED_NAVIGATION_SLUGS.has(normalized)) {
|
|
7203
|
+
throw new Error(
|
|
7204
|
+
`[Dyrected Config] The slug '${pageSlug}' in custom page '${item.label || pageSlug}' is a reserved system path and cannot be used as a page slug.`
|
|
7205
|
+
);
|
|
7206
|
+
}
|
|
7207
|
+
if (seenPageSlugs.has(normalized)) {
|
|
7208
|
+
throw new Error(
|
|
7209
|
+
`[Dyrected Config] Duplicate page slug '${pageSlug}' in navigation. Page slugs must be unique.`
|
|
7210
|
+
);
|
|
7211
|
+
}
|
|
7212
|
+
seenPageSlugs.add(normalized);
|
|
7213
|
+
}
|
|
7214
|
+
continue;
|
|
7215
|
+
}
|
|
7193
7216
|
if (item.slug) {
|
|
7194
7217
|
const normalizedSlug = item.slug.toLowerCase().trim().replace(/^\//, "");
|
|
7195
7218
|
if (RESERVED_NAVIGATION_SLUGS.has(normalizedSlug)) {
|
|
@@ -7197,6 +7220,12 @@ function assertValidNavigationSlugs(navigation) {
|
|
|
7197
7220
|
`[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.`
|
|
7198
7221
|
);
|
|
7199
7222
|
}
|
|
7223
|
+
if (seenWorkspaceSlugs.has(normalizedSlug)) {
|
|
7224
|
+
throw new Error(
|
|
7225
|
+
`[Dyrected Config] Duplicate workspace slug '${item.slug}' in navigation. Workspace slugs must be unique.`
|
|
7226
|
+
);
|
|
7227
|
+
}
|
|
7228
|
+
seenWorkspaceSlugs.add(normalizedSlug);
|
|
7200
7229
|
}
|
|
7201
7230
|
}
|
|
7202
7231
|
}
|
|
@@ -7339,6 +7368,43 @@ function compileNavigation(config) {
|
|
|
7339
7368
|
});
|
|
7340
7369
|
continue;
|
|
7341
7370
|
}
|
|
7371
|
+
if (item.page) {
|
|
7372
|
+
const pageConfig = typeof item.page === "string" ? {
|
|
7373
|
+
slug: item.slug || item.page,
|
|
7374
|
+
label: item.label || item.page,
|
|
7375
|
+
icon: item.icon,
|
|
7376
|
+
component: item.page,
|
|
7377
|
+
group: typeof item.group === "string" ? item.group : item.group?.name,
|
|
7378
|
+
order: item.order,
|
|
7379
|
+
badge: item.badge,
|
|
7380
|
+
access: item.access
|
|
7381
|
+
} : {
|
|
7382
|
+
...item.page,
|
|
7383
|
+
slug: item.slug || item.page.slug || "page",
|
|
7384
|
+
label: item.label || item.page.label || item.slug || "Page",
|
|
7385
|
+
icon: item.icon || item.page.icon,
|
|
7386
|
+
group: item.group ? typeof item.group === "string" ? item.group : item.group?.name : item.page.group,
|
|
7387
|
+
order: item.order ?? item.page.order,
|
|
7388
|
+
badge: item.badge || item.page.badge,
|
|
7389
|
+
access: item.access || (item.page.access && typeof item.page.access === "object" && "read" in item.page.access ? item.page.access.read : item.page.access)
|
|
7390
|
+
};
|
|
7391
|
+
const pageSlug = pageConfig.slug || "page";
|
|
7392
|
+
registerItem(groupName, {
|
|
7393
|
+
id: `page:${pageSlug}`,
|
|
7394
|
+
type: "page",
|
|
7395
|
+
slug: pageSlug,
|
|
7396
|
+
label: pageConfig.label || pageSlug,
|
|
7397
|
+
icon: pageConfig.icon || "FileText",
|
|
7398
|
+
href: `/pages/${pageSlug}`,
|
|
7399
|
+
group: groupName,
|
|
7400
|
+
order: pageConfig.order ?? 100,
|
|
7401
|
+
views: [],
|
|
7402
|
+
badge: pageConfig.badge,
|
|
7403
|
+
access: pageConfig.access && typeof pageConfig.access === "object" && "read" in pageConfig.access ? pageConfig.access.read : pageConfig.access,
|
|
7404
|
+
page: pageConfig
|
|
7405
|
+
});
|
|
7406
|
+
continue;
|
|
7407
|
+
}
|
|
7342
7408
|
const workspaceSlug = item.slug || "workspace";
|
|
7343
7409
|
registerItem(groupName, {
|
|
7344
7410
|
id: `workspace_${workspaceSlug}`,
|
|
@@ -16841,6 +16907,9 @@ async function serializeViewForApi(view, serializeAccess) {
|
|
|
16841
16907
|
dateField: view.dateField,
|
|
16842
16908
|
startDateField: view.startDateField,
|
|
16843
16909
|
endDateField: view.endDateField,
|
|
16910
|
+
component: view.layout === "custom" ? view.component : void 0,
|
|
16911
|
+
options: view.layout === "custom" ? view.options : void 0,
|
|
16912
|
+
data: view.layout === "custom" ? view.data : void 0,
|
|
16844
16913
|
columns: view.columns,
|
|
16845
16914
|
sort: view.sort,
|
|
16846
16915
|
metrics: view.metrics,
|
package/dist/server.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { O as DyrectedContext, D as DyrectedConfig, C as CollectionConfig, G as GlobalConfig,
|
|
2
|
-
export {
|
|
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';
|
|
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,
|
|
2
|
-
export {
|
|
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';
|
|
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';
|