Changelog
Release notes and version history for the Dyrected platform.
Release notes and version history across all Dyrected packages.
v2.24.3
-
The "Protecting your own endpoints" section of the Custom Admin Pages guide now has a Nuxt server route next to the Next.js route handler. Both verify the session with
me()and check the user's role, and both build the SDK client per request so one editor's token is never shared with another request. (@dyrected/admin) -
The "Publish as Role Default" dropdown in the navigation editor now lists your project's own roles instead of four fixed names.
What was wrong
The dropdown only offered
admin,editor,operatorandcompliance, so you could not publish a menu for a role likeexternal,financeorfield_opsfrom the admin.What changed
- The roles come from the role field on your auth collection: the field named
rolesorrole, or a select markedadmin.inviteRole. Plain string options and{ label, value }options both work, and the first role is selected by default. - If the role field has no fixed options (for example a free-text or JSON field), the dropdown becomes a text box where you type the role name. Publish stays disabled until you enter one.
- @dyrected/[email protected]
- @dyrected/[email protected] (
@dyrected/admin)
- The roles come from the role field on your auth collection: the field named
-
@dyrected/[email protected]
-
@dyrected/[email protected] (
dyrected,@dyrected/next) -
@dyrected/[email protected] (
@dyrected/next)
v2.24.2
-
The Custom Admin Pages guide now says clearly what a page's
accessrule does and does not protect.accessdecides who sees a page in the sidebar and who can open it by address. It is not a security boundary, because the page's code ships with the admin. If a page calls an endpoint in your own app, that endpoint has to check who is asking. The guide has a new "Protecting your own endpoints" section with a Next.js route handler that verifies the session withme()and checks the user's role. (@dyrected/admin) -
The "Role Default" button in the navigation editor now shows for every user the server will accept, not only users whose role is exactly
admin.What was wrong
The server lets
admin,super_admin,superadmin,ownerand the collection's configured admin role publish a navigation layout for a role. The editor only checked foradmin, so asuper_admincould never see the button, even though saving would have worked.What changed
The editor now uses the same
isUserAdmincheck as the server, so the button and the permission always agree.- @dyrected/[email protected]
- @dyrected/[email protected] (
@dyrected/admin)
-
@dyrected/[email protected]
-
@dyrected/[email protected] (
dyrected,@dyrected/next) -
@dyrected/[email protected] (
@dyrected/next)
v2.24.1
-
The admin no longer shows navigation entries a user can't open. Collections, globals, custom pages, workspaces, views and actions are now hidden when your access rules deny them, and opening one by URL shows a "no access" page instead of the screen.
What was wrong
Navigation was only filtered by role arrays like
access: ['admin']. Rules written as functions, Jexl strings or named policies were ignored, so the sidebar listed collections and globals the user couldn't read. View and action access rules were sent to the admin but never used to hide anything, and a global'saccess.readnever reached the navigation at all.What changed
/api/admin/navigationevaluates every kind of rule with the same resolver the API uses. A rule that throws hides the item. A rule that returns a row-level filter ({ owner: { equals: user.sub } }) keeps it visible, because the user can read some rows./api/schemasleaves out views the user can't read, and/api/admin/navigation/badgesno longer counts items they can't see, including when they've customized their navigation.- Workspaces whose views are all hidden disappear, and so do groups left empty.
- The admin sidebar and routes hide collections, globals and views you can't read, and hide actions you can't run. This uses
access.update, the rule the server already checks when an action runs.
This only affects what people see. Your access rules were already enforced by the API, so no data was exposed before and none is newly protected now.
Docs fix
The
AccessFunctionexample useduser.roles contains 'editor', but Jexl has nocontainsoperator, so that rule always denied. Use'editor' in user.roles. (@dyrected/admin,@dyrected/core) -
Production Nuxt builds no longer return a 500 on
/adminwithERR_MODULE_NOT_FOUNDforreact-router/dist/development/dom-export.mjs.What was wrong
@dyrected/adminlistsreact-router-domas a peer dependency, so a server install decides which copy of it you get. On a server with no lockfile (for example when you deploy only one app out of a monorepo), Nitro could leavereact-routeras an external import and then not copy its files into.output/server/node_modules. The server started, then failed on the first request to any Admin route. Local builds with a lockfile bundled the router and never showed the problem.What changed
@dyrected/nuxtnow tells Nitro to bundlereact-routerandreact-router-dominto the server build, so the result no longer depends on how your server lays outnode_modules. You can remove this workaround fromnuxt.config.tsif you added it:nitro: { externals: { inline: [/^react-router(-dom)?($|\/)/] }, }Rules you already have in
nitro.externals.inlineare kept. (@dyrected/nuxt)
v2.24.0
-
A collection or global can now replace its create and edit screens with your own component, while saving still goes through the normal pipeline: validation, access rules, hooks and drafts.
For app developers
-
Point a collection at a form. Set
createForm,editForm, or aformfallback for both inadmin.components, then register a component under that key incomponents.forms:defineCollection({ slug: "check_ins", admin: { components: { createForm: "check_ins.scanForm", editForm: "check_ins.reviewForm", formShell: "header", // "full" (default) | "header" | "none" }, }, });Globals take
editFormandformthe same way. A key that is not registered falls back to the built-in form, so an editor is never left with an empty screen. -
Choose how much of the page stays.
formShell: "full"keeps the header, status badge and Dyrected's Save bar, so you only re-lay-out the body."header"keeps the header and leaves saving to your form."none"gives your form the whole screen. -
Save with
useDocumentForm(). It returns the saveddocument,permissions, theform(values, errors,setValue) andsubmit().submit({ overrides, redirect, silent })resolves to{ ok: true, doc }or{ ok: false, errors }and never throws. Server validation errors land on the matching field, souseField(path).errorworks with no extra code.redirectdefaults to opening the new record after a create and staying put after an edit. -
Reuse the built-in inputs.
<DyrectedField path="guestName" />,<DyrectedFields names={[...]} />and<DyrectedDefaultForm exclude={[...]} />render the real inputs with their labels, conditions, widths, read-only state andadmin.componentoverrides. -
Relationship drawers use it too. Creating a related record inline opens the target collection's
createFormwithpresentation: "drawer". SetformInDrawer: falseto keep the built-in form there. -
Vue and Nuxt.
useDocumentForm(),DyrectedField,DyrectedFieldsandDyrectedDefaultFormexist in@dyrected/vuewith state as refs, and work inside a registered form with no manualprovide. -
Safe by default. A form that throws shows an error card with Retry and Use default form.
permissionsonly decides what to show; the server enforces access on every save.
For plugin and integration authors
@dyrected/coreexportsFormShell,DocumentFormComponentSlotsandGlobalFormComponentSlots.collectReferencedComponentKeysnow fillsforms, sonpx dyrected generate:typestypesRegister.componentKeys.formsand the unused-registration warning covers forms.- Config diagnostics report an unknown
formShelland non-string form keys (sourceadminComponents). @dyrected/admin/publicexportsDocumentContext,DYRECTED_DOCUMENT_KEYandbuildDocumentFormApifor hosts that embed the document context.
Upgrade notes
AdminFormComponentPropschanged shape: it is now{ collection, mode, documentId?, presentation }. Nothing in Dyrected consumed it before, so this only matters if you typed a placeholder against the old{ id, readOnly }.- The inline "Create" dialog on relationship fields now saves through the same pipeline as the relationship drawer. A failed save shows an error toast instead of only logging to the console, and a successful one shows a success toast.
- The hooks and components are marked experimental. (
@dyrected/admin,@dyrected/core,@dyrected/react,@dyrected/vue)
-
v2.23.0
-
Custom admin components are now easier to write, harder to get wrong, and no longer need provider boilerplate in Vue.
For app developers
- Vue custom components just work.
useDyrectedForm(),useField(),useAdminTheme()and the newuseAdminNavigate(),useAdminNotify()anduseAccess()work inside any custom field or slot component with noprovideDyrectedFormcall. Prop updates patch the component in place, so local state and input focus are kept. - New hooks and composables.
useAdminNavigate()(navigateplusto.collection/document/view/page),useAdminNotify()(success/error/info) anduseAccess().can(operation, collection, doc?)ship in@dyrected/reactand@dyrected/vue. They are marked experimental.useAccessis a UI hint only; the server stays authoritative. - Typed component keys. Run
npx dyrected generate:typesanddefineAdminComponents({ fields: { ... } })checks your keys against what your schema references. Untyped apps are unaffected. - Better failure modes. A component that throws shows an inline error card with a Retry button, and the rest of the admin keeps working. This includes errors thrown inside a Vue component. An unregistered key shows a placeholder in development and a warning (a generic placeholder in production).
- Unused registrations are flagged. In development the admin warns once for each registered component the schema never references. Pass
warnUnusedComponents={false}(or:warn-unused-components="false"in Vue) to silence it. - Lazy components.
React.lazyanddefineAsyncComponentcomponents show a skeleton while they load. - Nuxt auto-registration. Drop a file at
components/dyrected/<registry>/<key>.vue(for examplecomponents/dyrected/fields/check_ins.scanner.vue) and it is registered under that key. Thecomponentsprop still wins on a clash, and nothing changes if you don't use the folder.
For plugin and integration authors
AdminComponentsgainsforms,viewLayouts,pagesandcustomComponents, plus the identity prop typesAdminFormComponentProps,AdminViewLayoutPropsandAdminPageProps. The first three are declared but not rendered yet; they are reserved for the custom forms, view layouts and pages work.@dyrected/sdkexportsRegisteredComponentKeys, andRegisteracceptscomponentKeys.@dyrected/coreexportscollectReferencedComponentKeys(schema), the scan the CLI and the admin both use.@dyrected/admin/publicexportsAdminBridgeProvider,useAdminBridgeContext,AdminComponentErrorBoundary,AdminComponentFallbackand the new hooks.
Upgrade notes
- No breaking changes. Existing registries (
fields,dashboard,collectionList,collectionView) keep their props. - Regenerate types to get
Register.componentKeys. If you hand-maintain a largecomponentsmap inadmin.vue, you can move entries intocomponents/dyrected/<registry>/one at a time.
- Vue custom components just work.
-
Operational views can now render documents with your own component, while Dyrected keeps the header, KPI metrics, search, pagination, selection, bulk actions and action dialogs.
For app developers
-
Add a custom layout. Define a view with
layout: "custom"and acomponentkey, then register a component under that key incomponents.viewLayouts:defineView({ slug: "seating", label: "Seating Chart", layout: "custom", component: "guests.seatingChart", options: { tableField: "tableNumber" }, data: { fetchAll: true }, }); -
Read everything through a hook.
useCollectionView()gives youdocuments,total,isLoading,pagination,sort,search,filters,selection,permissionsandopen().useViewActions()runs the view's actions and shows Dyrected's own confirm dialog and input form.useGroupedDocuments(field)groups documents with select and relationship labels resolved. The same three exist in@dyrected/vueas composables, with state as refs, and work with no manualprovide. -
Save changes from your layout.
updateDocument(id, patch)updates optimistically and rolls back with an error toast if the server rejects the change. Hooks, access rules and validation still run. -
Load everything when you need to. Set
data.fetchAllto load up to 1,000 documents. Past that, the user sees a notice that the list was truncated. -
Safe fallback. If the component key is not registered, the view shows a message with a Show as table button instead of a blank page.
Built-in layouts and custom layouts now share one foundation
- Filters everywhere. Custom layouts get the same filter bar as the table: search, per-field filters and match all/any. Table, kanban, cards and custom layouts now use one implementation, so a filter means the same thing in each.
- Slots see the documents. Components registered in
beforeViewContent,afterViewHeaderand the other view slots now receive the documents the active layout loaded, and can calluseCollectionView().documentswas always an empty list before. - Replace a built-in layout. Register a component under a built-in layout's name, such as
viewLayouts.kanban, and views with that layout render it in Dyrected's shell, with the same hooks as a custom layout. - One place that describes layouts. The navigation customizer, the view header icon and the page's dispatch read a single layout registry.
ganttstill renders as a table.
For plugin and integration authors
ViewLayoutgains"custom", and@dyrected/coreexportsCustomViewConfig,CustomViewDataConfig,defineCustomViewandCUSTOM_VIEW_FETCH_ALL_LIMIT. Views serialized to the admin now carrycomponent,optionsanddata.@dyrected/admin/publicexportsViewControllerContext,createViewControllerandDYRECTED_VIEW_KEYfor hosts that embed the controller. The controller is subscribable, like the form controller.npx dyrected generate:typesnow includes custom layout components inRegister.componentKeys.viewLayouts.
Upgrade notes
- No breaking changes. Existing layouts are untouched.
- The hooks are marked experimental.
- If a slot component checked
documents.length === 0because the list was always empty, it will now see real data. - Built-in layouts no longer take
actions,onRunActionandisRunningActionprops. They read them from the view controller. Only code that renderedTableLayout,KanbanLayout,CardsLayoutorCalendarLayoutdirectly is affected, and none of them are public exports. - A custom view's
componentis required.defineViewthrows at config load if it is missing. (@dyrected/admin,@dyrected/core,@dyrected/react,@dyrected/vue)
-
-
Custom pages, view layouts and fields in React can now read and write documents with the editor's own permissions.
For app developers
- New
useAdminClient()hook, exported from@dyrected/react. It returns the SDK client the admin is already signed in with, so a custom component can callclient.collection("orders").find(...)or.update(...)without handling a token, and only sees what that editor is allowed to see. - It is different from
useDyrected()in@dyrected/react, which gives a public site's client and needs its ownDyrectedProvider. CallinguseDyrected()inside the admin throws, because the admin does not mount that provider. - In Vue,
useDyrectedClient()already returns the admin's client inside custom components, so nothing changes there. - The hook is marked experimental.
For integration authors
useAdminClientis also exported from@dyrected/admin/public. It reads the admin's own context and throws a clear error outside the admin or before sign-in. (@dyrected/admin,@dyrected/react)
- New
-
Your own components inside the admin now keep their styles when your app uses Tailwind v4.
For app developers
- Before this fix, the admin's stylesheet beat Tailwind v4 utility classes on your own components rendered inside it, because Tailwind v4 puts utilities in a CSS layer and unlayered CSS always wins over layered CSS. A custom field, slot, page or view layout lost its
border,bg-*,font-bold,text-2xl,mb-4and evenringorshadowclasses. The admin now puts its element defaults in@layer base, so your classes apply as you wrote them. - You no longer need
!important, inline styles or box-shadow tricks to draw a border inside a custom component. - The admin's own appearance is unchanged. Its
dy-*classes are not layered and still take priority over those defaults. - Apps on Tailwind v3 or plain CSS are unaffected, since unlayered host styles already beat layered ones.
For integration authors
- The scoped reset, the heading, button and field defaults, and the
--tw-*variable initialisers inadmin.cssare now inside@layer base. Layers are supported by all current browsers. - Rules that target admin classes, such as
.dy-admin-ui .dy-text-primary, stay unlayered. (@dyrected/admin)
- Before this fix, the admin's stylesheet beat Tailwind v4 utility classes on your own components rendered inside it, because Tailwind v4 puts utilities in a CSS layer and unlayered CSS always wins over layered CSS. A custom field, slot, page or view layout lost its
-
The development warnings for custom components now actually appear in your app.
For app developers
- A custom component key that is not registered now shows a placeholder card and a console warning in development, as intended. The same applies to a registered component the schema never references, and to a custom view layout whose component key is missing, which now names the missing key in development.
- These were switched on by Vite's
import.meta.env.DEV, which Vite fixes when the admin package is built, so in your app they were always off. They now follow your ownNODE_ENVand are silent in production builds. - The Nuxt
<DyrectedAdmin>now acceptswarn-unused-componentsand passes it through, so:warn-unused-components="false"works in Nuxt too.
For integration authors
- Do not use
import.meta.env.DEVin code that ships in a library bundle and should follow the host's mode. The admin now has an internalisDevelopment()that readsprocess.env.NODE_ENV, which the host's bundler resolves. (@dyrected/admin,@dyrected/nuxt)
-
- Case-insensitive collection search:
containsandstarts_withnow compare lowercased values on MySQL and SQLite, so admin list search no longer depends on letter case (MySQL's binary-collated JSON extraction and SQLite's ASCII-onlyLIKEfolding previously made matching case-sensitive). Postgres (ILIKE) and MongoDB ($options: "i") were already insensitive. - Literal special characters in search:
%and_incontains/starts_withare escaped for SQLLIKE, and regex metacharacters are escaped for MongoDB$regex, so searching for50%or(matches literally instead of acting as a wildcard or throwing. The rawlikeoperator keeps wildcard semantics on SQL. - Searchable fields chosen by type: when
admin.searchableFieldsis omitted, search coversadmin.useAsTitleplus every visibletext,textarea,richText,emailandurlfield (up to eight, including fields nested inrow), regardless of field name. Relationship fields are searched only when listed insearchableFields. (@dyrected/core)
- Case-insensitive collection search:
v2.22.0
-
- Time-Bucket Grouping on Metric Cards & Sub-Metrics (Phase 3):
- Added object-based
groupBysupport for date fields:groupBy: { field: string, bucket: "day" | "week" | "month" | "year", limit?: number, orderBy?: "asc" | "desc" }. - Dynamically slices dates into discrete intervals and expands into formatted bucket cards (e.g.
{{group.label}} Tastings->Oct 10, 2026). - Interactive drill-down: Clicking any time-bucket card applies an
isBetweendate interval filter to the active view layout. - Zero-N+1 performance: All bucket aggregates and filter conditions resolve in a single batched aggregation request.
- Added object-based
- Period-over-Period Trend Deltas (Phase 4):
- Added declarative
trendconfiguration toViewMetricandViewSubMetric:trend: { dateField: string, period: "previous_day" | "previous_week" | "previous_month" | "previous_year", invertColors?: boolean }. - Calculates comparative period boundaries (
previous_day,previous_week,previous_month,previous_year) and computes percentage changes with directional trend badges (+X% ↑/-X% ↓). - Added
invertColors: trueoption for metrics where increases indicate risk (e.g. pending tasks, disputes, error counts), displaying positive deltas in rose/alert and negative deltas in emerald. - Supports trend deltas on both headline card metrics and individual sub-metric rows.
- Fan-out optimization: Base values and comparative period aggregates are evaluated together within the single batched query.
- Added declarative
- Interactive Quick-Filter Distribution Bars & Multi-Layout Compatibility:
- Segmented distribution bars with high-contrast luminance stepped palettes and harmonic tonal shading for dark/light modes.
- Interactive sub-metric chips/tiles allowing click-to-filter drill downs across Table, Kanban, Cards, and Spreadsheet layouts.
- High-cardinality handling: Top-N groups with an
"Other (X)"popover drill-down.
- React State & Search Params Transition Fixes:
- Fixed circular state-searchParams loop on Kanban and Cards layouts preventing "Maximum update depth exceeded" errors when metric cards are toggled as quick-filters. (
@dyrected/admin,@dyrected/core)
- Fixed circular state-searchParams loop on Kanban and Cards layouts preventing "Maximum update depth exceeded" errors when metric cards are toggled as quick-filters. (
- Time-Bucket Grouping on Metric Cards & Sub-Metrics (Phase 3):
v2.21.0
-
- Metric Scoping Architecture (
metricsScope&scope): Added comprehensive filter scoping to operational view metrics and sub-metrics with three evaluation modes: "view"(default): Evaluates against the view's persistent filter (view.filter), serving as a stable reference KPI unaffected by ephemeral table row filters."filtered": Dynamically live-syncs with active table toolbar filters, column filters, and search queries."collection": Evaluates across the entire collection, computing global lifetime totals regardless of view or table filters.- Hierarchical inheritance allows views to set
metricsScope, individual metric cards to specifyscope, and sub-metric rows to optionally override. - Contextual Scope Icons on Metric Cards: Added clean, subtle 12px status icons with tooltips (
Filterfor filtered,Databasefor collection,Layersfor view) next to card headers and sub-metric rows, giving instant visual clarity on data boundaries. - Dynamic Grouped Metrics (
groupBy): Introduced declarativegroupBysupport onViewMetricandViewSubMetric:- Dynamic Metric Cards: Setting
groupBy: "field"on a metric card dynamically expands into one metric card per distinct group (e.g. 10 communities $\rightarrow$ 10 cards) with templated labels ({{group.label}},{{group.value}}) and group-scoped aggregations. - Dynamic Sub-Metrics: Setting
groupBy: "field"on a sub-metric dynamically expands into $N$ breakdown rows in the footer of a single metric card. - Automatic Group Discovery: Automatically resolves group options for relationship fields (fetching related document titles and IDs), select/radio options, boolean fields, and scalar distinct values.
- Single Batched Aggregation: Fans all dynamically expanded operations across cards, sub-metrics, and groups into a single batched database aggregation query (
client.collection(slug).aggregate(input)), completely eliminating N+1 queries.
- Dynamic Metric Cards: Setting
- Navigation Editor & Interactive KPI Builder:
- Full support in the Navigation Customizer (
ViewMetricsBuilder) for configuring default viewmetricsScope("view" | "filtered" | "collection"), cardscope, andgroupBy(supporting relationship, select, radio, boolean, and scalar fields). - Interactive click-to-edit on active KPI chips allowing live reconfiguration of metric labels, operations, target fields, format, colors, scope, and groupBy.
- Added "Revert View" action in the Navigation Customizer to seamlessly discard personal overrides and restore codebase view definitions.
- Enhanced
reconcileNavigationin@dyrected/coreto intelligently inherit newmetricsScope,scope,groupBy, andsubMetricsfrom codebase view definitions when sparse user preferences are present.
- Full support in the Navigation Customizer (
- Native Search Parameter in Operational Views: Operational views (Table, Cards, Spreadsheet, Kanban) now forward toolbar search directly to the backend pagination endpoint via the
searchquery parameter, ensuring performant full-text searches. (@dyrected/admin,@dyrected/core)
- Metric Scoping Architecture (
v2.20.1
-
- Where Operator
not& Aliases (ne,not_equal,notEquals): Added support for"not"and related negation aliases inparseSqlWhereandparseMongoWhere, resolving unhandled operator errors. Supports scalar values (!=,IS NOT NULL), arrays (NOT IN), nested operator expressions (NOT (...)), and top-levelNOT/notblocks (SQLNOT (...), Mongo$nor). - Where Sanitizer
NOTClause Preservation: UpdatedsanitizeWhereClauseandcoerceBooleanWhereto preserve and recursively walkNOT/notblocks for boolean coercion and schema field sanitization. - Admin Filter Builder & Formatter Support: Added label and badge formatting support for
"not"and"ne"in admin filter utilities. (@dyrected/admin,@dyrected/core)
- Where Operator
-
- Relationship Filtering in Operational Views: Added multi-select relationship filtering support to table and operational views via
DataTableRelationshipFilter. Includes infinite scroll pagination for browsing and searching target collection records and a dedicated hydration query ensuring selected items never disappear or appear blank. - Pinned "Selected" Section in Popover: Pinned checked items into a dedicated "Selected" section at the top of the popover, keeping them accessible for unchecking even while searching or paging through other options.
- Descriptive Trigger Badges on Table Toolbar: Updated the filter pill trigger badge to display the actual document titles for 1 or 2 items (e.g.
Author: Acme CorporAuthor: Acme Corp, Beta Corp) and count badges for 3+ items. - Multi-Field Server Search for Relationships: Broadened server-side search across candidate identifier fields (
displayField,name,title,email,slug,username,code) matching withORclauses. - Avatars & Thumbnails in Filter Lists: Added thumbnail and avatar rendering for visual upload collections and documents with media fields.
- Relationship Invert & Negation Operators: Added support for
in("Is any of"),not_in("Is not any of"),isEmpty("Is empty"), andisNotEmpty("Is not empty") operators in relationship filters. - Zero-Flicker Relationship Title Display: Added synchronous document caching and TanStack Query cache seeding to eliminate brief raw ID flashes when selecting relationship filter items.
- Multi-Select Filtering on
select,multiSelect, andrelationship: Enabled multi-selection by default across all faceted filter types (select,multiSelect,relationship), allowing editors to filter by multiple choices simultaneously. - Relationship Picker Selected Value Hydration: Updated
RelationshipPickerin document edit forms to hydrate existing selected IDs with a targeted query, preventing selected values from appearing blank when the referenced document is outside the first page of results. - Date Filtering with Day Bounds & Dual Date Picker for "isBetween": Resolved issues where date filters previously failed to match records due to exact millisecond comparisons. Date filters now query against full-day boundaries (
gte: startOfDay, lte: endOfDay), "isBetween" renders two dedicated date pickers (Start dateandEnd date) and requires both values, and added "Is on or before" (lte) and "Is on or after" (gte) operators. (@dyrected/admin)
- Relationship Filtering in Operational Views: Added multi-select relationship filtering support to table and operational views via
v2.20.0
-
feat(auth): polymorphic email transport, custom templates cascade, headless tokens, and admin template management
- Polymorphic email delivery: support both direct HTML and external template IDs with dynamic variables (Postmark, Seamailer, SendGrid) without serializing payloads into fake HTML.
- Multi-tier template cascade: DB overrides (
__email_templates) -> Collection config (collection.auth.email.templates) -> Global config (config.email.templates) -> Core defaults. - Collection action URLs: configure
auth.urls.inviteandauth.urls.resetPasswordper collection to keep end-users from being routed to/admin. - Token lifecycle & safety: hardened password safety checks for null/empty passwords returning 401
PASSWORD_NOT_SET, protected against double-acceptance, and added token superseding withinvitedAt. - Headless tokens & token verification: support
sendEmail: false,createInviteToken,createPasswordResetToken, andGET /api/collections/:slug/tokens/verify(SDKclient.collection(slug).verifyToken(token, type)). - Admin UI template editor: live CodeMirror HTML editor, desktop/mobile iframe preview, variable chip insertion, external template ID mode, test email dispatch dialog, and revert-to-default capability. (
@dyrected/admin,@dyrected/core,@dyrected/sdk)
v2.19.0
-
Add built-in Trash & Retention system and audit/roles field helpers across core, admin, SDK, and framework integrations:
- Core Trash & Retention: Move deleted documents to internal
__trashcollection with deterministic IDs, freeing unique keys and keeping read paths clean. Configurable retention periods with automaticdyrected:trash-purgetask runner integration. - Audit & Schema Field Helpers: Add
defineCreatedAtField,defineUpdatedAtField,defineCreatedByField,defineUpdatedByField, anddefineRolesField(with customizableadminRoleauthorization). - Admin UI: Add collection-level and global
/trashviews, 8-second undo toast on delete, media library trash support, empty trash confirmation dialog, and conflict drawer for "Restore with changes". - Ecosystem: Add
client.trash()in@dyrected/sdk,useTrashin@dyrected/reactand@dyrected/vue,dyrected doctortrash & retention diagnostics in@dyrected/cli, and secret-protected cron endpoints in@dyrected/next.
- Core Trash & Retention: Move deleted documents to internal
v2.18.1
-
Fix operational workspace view action resolution and optional field null validation.
- Workspace view actions (
@dyrected/core): Support operational view actions defined insideconfig.admin.navigation(such asdefineWorkspaceviews targeting a collection viaview.collection,item.collection, oraddToCollection).runViewActionand action route registration now search bothcollection.viewsand all matching workspace views, preventingAction "<action>" was not found in view "<viewSlug>"errors. - Optional field null validation (
@dyrected/admin): UpdatedbuildSchemaShapeso optional fields acceptnull(.nullable().optional().or(z.literal(""))), resolving spuriousExpected string, received nullvalidation errors when saving existing records with null database values. (@dyrected/admin,@dyrected/core)
- Workspace view actions (
v2.18.0
-
Add transactional write hooks and exact money handling. Collections can define
hooks.beforeCommit, which runs inside the write transaction with a writabletxso secondary writes commit or roll back with the document. Workflow transitions can defineonTransition, run inside the transition transaction and given an optional requestinput. Fields acceptimmutable: true, which rejects any update that changes the value. The newmoneyfield (defineMoneyField) stores integer minor units, validates them on write, maps toBIGINTin SQL adapters, and is edited and displayed in major units in the Admin. -
Add view filter builder to navigation customizer. Enables configuring visual and raw JSON where-clause filters for collection subviews directly from the admin UI with schema field introspection, operator presets, and type coercion. (
@dyrected/admin) -
Fix collection-level
actionsnot appearing in the admin, and fix invite and password-reset links./api/schemasnow includes root-levelcollection.actions, sodisplayActionitems on a detail view resolve instead of showing "Action not found". Invite and reset emails now link to the admin UI instead of the site URL. The base URL comes from the newadmin.adminUrloption, then theDYRECTED_ADMIN_URLenv var, then the page the admin is running on, then/admin, and relative values resolve against the request origin. The invite dialog's "Copy" field now shows the full invite link with its token. (@dyrected/admin,@dyrected/core) -
Fix bugs found by running the adapter contract suite against live databases. Postgres atomic
increment/decrementno longer fails with "multiple assignments to same column data", and conditionalwhereupdates by id no longer collide on parameter numbers. MySQL and Postgres unique and compound indexes on collections with long names are now created (over-long index names are shortened with a stable hash instead of being silently rejected, which leftuniqueunenforced). MongoDB compound indexes no longer fail whensparseis unset. Themoneyfield also gets its numeric list filter in the Admin. -
Close the remaining P0 integrity gaps.
findOnenow accepts awherefilter (withlock: "for-update") in addition to anid. The MongoDB adapter now generates string IDs like the SQL adapters, enforcesuniquefields and collectionindexes, throwsDuplicateKeyErroron duplicate keys, and supports atomicincrement/decrementand conditionalwhereupdates. MySQL promotedselect,radio,relationshipandemailcolumns use boundedVARCHARtypes. The adapter contract suite gains concurrency tests for unique inserts and conditional debits. -
Add a background task runner and Nuxt import aliases.
defineTaskandcreateTaskRunner(exported from@dyrected/core) run cron-scheduled jobs from thetasksconfig, with a per-task database lock so each scheduled run happens once across instances, alockTimeoutthat aborts overrunning runs, andrunDue()for platform crons.@dyrected/nuxtregisters#dyrectedand#dyrected/serveraliases anchored to the project root (fixing~resolving toapp/in Nuxt 4), can start the runner with the newrunTasksoption, and no longer blocks dev server boot while validating the config. (@dyrected/core,@dyrected/nuxt) -
Make boolean filters behave the same on every adapter. The strings
"true"/"false"are now coerced to booleans for fields declared as boolean (coerceBooleanWhere), where they previously matched nothing on SQLite and MongoDB and returned the wrong rows on Postgres for promoted columns. The shorthand{ flag: false }form also works on SQLite now. -
Make
groupByaggregates return the same keys and values on every adapter. Group keys are normalized by field type ("true"/"false"for booleans,"1"for numbers, ISO strings for dates,__unassigned__for null), MySQL treats JSON null as SQL NULL andavgreturns double precision, and Postgres and MySQL return promoted date columns as ISO strings. MySQL now accepts ISO timestamps written to promoted date and datetime columns, which previously failed. -
Fix aggregate bugs found on live databases. MySQL no longer fails on
distinctaggregates (it has noDISTINCTforJSON_ARRAYAGG, so values are de-duplicated in the adapter), groups by numeric columns now use keys like"1"instead of"1.0000", and filters on unpromoted boolean fields now match. MongoDB grouped aggregates now honour each aggregate'swhere. (@dyrected/db-mongodb,@dyrected/db-mysql) -
client.collection(slug).transition(id, name, opts)now accepts an optionalinputobject. It is sent with the transition request and passed to the transition's server-sideonTransitionhandler, for example an amount the handler needs to act on. (@dyrected/sdk)
v2.17.0
-
Operational views and dynamic navigation
- Workspaces: add
defineWorkspaceandDefineWorkspaceOptionsfor standalone operational workspaces, collection placement, groups, ordering (order,position,before,after),addToCollection, and role-basedaccess. Reserved route slugs are validated at config load. - Navigation APIs: serve
/api/admin/navigation(compiled tree, pruned per user role) and/api/admin/navigation/badges(batched aggregates, invalidated on mutations). - Badges: support static text badges, aggregate count badges with variants, and per-view badges. Metrics gain
countDistinctand string-based aggregates, with improved Postgres casting. - Admin: add an inline navigation customizer with auto-generated slugs, a Lucide icon picker, and permanent view deletion. Pinned items now sit under the dashboard, and preference events no longer dispatch during render.
- Database adapters: add collection database indexes and the aggregate improvements above to the SQLite, MySQL, and Postgres adapters.
- CLI: add
dyrected nav pullanddyrected nav pushto sync UI-configured navigation withdyrected.config.ts, and keep navigation in sync duringsync:schema. - SDK: resolve relative base URLs server-side.
- Knowledge: add KYC review, order fulfillment, and support desk workspace recipes.
- Docs: add the "Workspaces and navigation" guide and remove legacy
list-view-v1content.
- Workspaces: add
v2.16.0
-
Align drawer saves with edit-page mutation pipeline and parent query invalidation:
- Unify drawer mutations across
JoinFieldandDetailRepeatComponentvia a shareddrawerSavePipeline. - Support password changes (
oldPassword,newPassword,confirmPassword) from drawers usingclient.changePassword(...). - Immediately seed React Query document detail caches upon mutation for zero-flicker UI updates.
- Optimistically update parent join lists and caches (
["join", target, onField, parentDocId]). - Thoroughly invalidate parent document queries (
detailandentry), parent collection list queries, and relation join queries so parent pages update immediately without manual page reload. - Trigger parent query invalidations when executing custom actions in drawer views via
onActionSuccess. - Provide standardized success and error notifications matching edit-page conventions. (
@dyrected/admin)
- Unify drawer mutations across
-
Schema Integrity, Physical Indexes & Atomic Concurrency
- add duplicate key error handling, auto-migration for index creation, and expanded column lengths.
- add production concurrency and fintech readiness specification with database adapter and documentation updates.
v2.15.0
-
Detail View drawers, workflow actions, and list config improvements:
- Join field rows (on the edit page) and detail-repeat rows (on the read-only Detail View) now open into a side drawer showing that row's own collection's Detail View config when it has one (falling back to the edit form otherwise), with a view/edit toggle and prev/next navigation between the already-loaded rows.
- Auto-generated Detail View schemas now render join fields as a table instead of badge pills, and table-layout repeat fields no longer duplicate field labels already shown in the column header.
- New
collection.actions(defineAction/displayAction) let a collection define workflow actions that run against a single document independent of any view, rendered in the Detail View's header toolbar and/or inline viadisplayAction(name)— backed by a new view-lessPOST /api/collections/:slug/actions/:actionroute and aclient.collection(slug).runCollectionAction()SDK method. - New
collection.admin.filter/sort/metrics/groupByapply directly to a collection's default list view, without needing to define a separateviewsarray and mark it as the default. - Inline-editable Detail View fields now show their edit affordance by default on mobile instead of only on hover. (
@dyrected/admin,@dyrected/core,@dyrected/sdk)
-
- Respect
error.statusCodefrom throwingdefineActionhandlers in the collection action runner instead of always returning HTTP 500, matching the workflow-transition error path. Single-row failures now return the thrown status (e.g. 400 for validation failures) with an{ error: true, message }body, and bulk runs report the per-row status. - Surface the server's error message in
DyrectedErrorfor string and bare{ error }response bodies, so admin action toasts show the actual validation message instead of a bare status code. (@dyrected/core,@dyrected/sdk)
- Respect
v2.14.0
-
Auth: configurable session token lifetime and reusable server auth helpers
Session JWTs are no longer fixed at 7 days. Set
auth.tokenExpirationon any auth collection usingjosesetExpirationTimevalues:auth: { tokenExpiration: "12h", }The configured lifetime applies to login, first-user registration, invite acceptance, token refresh, and external-provider admin SSO. Password-reset (
1h) and invite (7d) purpose tokens stay fixed.Reusable auth helpers from
@dyrected/core/serverThe same token, session, password, and email helpers Dyrected uses internally are now exported for custom endpoints and hooks:
- Tokens:
signCollectionToken,verifyCollectionToken,decodeCollectionToken,resolveSessionTokenExpiry - Sessions:
issueAuthSessionToken,getAuthSession,revokeAuthSession,revokeAllAuthSessions - Passwords:
hashPassword,verifyPassword - Email:
sendEmail,buildResetPasswordEmail,buildInviteEmail,buildWelcomeEmail,buildPasswordChangedEmail
Admin: resizable navigation sidebar
The desktop admin menu can now be resized by dragging its right edge, mirroring the AI assistant panel. Double-click resets to the default width. The width persists to the
layout:admin:sidebar-widthglobal preference with localStorage as the instant cache and offline fallback. (@dyrected/admin,@dyrected/core) - Tokens:
v2.13.6
-
Type Safety: Enforce Required Field Properties
Added compile-time type safety for field configuration to catch configuration errors at build time instead of runtime:
Field Type Improvements:
- JoinField:
collectionandonare now required - RelationshipField:
relationTois now required - ImageField:
relationTois now required - ObjectField:
fieldsis now required - ArrayField:
fieldsis now required - BlocksField: Requires either
blocksorblockReferences
Action & Workflow Improvements:
- ActionConfig: Now enforces that either
mutationorhandler(or both) is provided via union type - ViewLayout Types: Layout-specific types enforce required fields:
- Kanban views require
groupBy - Calendar views require
dateField - Gantt views require
startDateFieldandendDateField
- Kanban views require
DefaultValue Type Safety:
defaultValuenow matches the field's value type (e.g., multiSelect requiresstring[], notstring)
Collection Slug Inference (NEW):
- Added
ExtractCollectionSlugs<T>helper type to extract valid collection slugs from config - Added
defineTypedRelationshipField<ValidSlugs>()- type-safe relationship fields - Added
defineTypedImageField<ValidSlugs>()- type-safe image fields - Added
defineTypedJoinField<ValidSlugs>()- type-safe join fields - These builders validate
relationToandcollectionagainst available slugs at compile time
type ValidSlugs = ExtractCollectionSlugs<typeof collections>; // ✅ Valid - 'posts' exists in collections defineTypedRelationshipField<ValidSlugs>({ name: "author", relationTo: "users", // Type-checked! }); // ❌ Invalid - 'potss' doesn't exist defineTypedRelationshipField<ValidSlugs>({ name: "author", relationTo: "potss", // TypeScript error! });Documentation:
- Added guidance that workflow transition
from/tofields should reference defined state names - Clarified that select/multiSelect/radio fields should include options configuration
Bug Fixes:
- Fixed
r.map is not a functionruntime error in admin collections by enforcing multiSelect defaultValue types - Fixed
adminsandinvestorscollections to use correct array-typed defaultValues
These changes improve developer experience by surfacing configuration issues at compile time through TypeScript's type system, reducing debugging time and preventing production issues. (
@dyrected/admin,@dyrected/core) - JoinField:
v2.13.5
-
- Normalize
roleandrolesfields across core auth middleware and admin auth to allow interchangeable use. - Return collection slug in
GET /meresponse to ensure user context collection is always populated. - Fix route access guard in
EditEntryPageto checkcanCreateon creation routes instead of incorrectly checkingcanRead. - Synchronize token authentication with the client on startup and invalidate schemas cache on login/logout so permission rules refresh immediately.
- Fix TypeScript type-narrowing on uploaded file preview in
EditEntryPage. (@dyrected/admin,@dyrected/core)
- Normalize
v2.13.4
- Resolve Rolldown CommonJS interop error in lazy-loaded
RichTextEditorchunk by shimminguse-sync-external-storeto native React 18/19 hooks, and inject a browserwindow.requirefallback forreactandreact-domin@dyrected/adminand@dyrected/vue. (@dyrected/admin,@dyrected/core,@dyrected/vue)
v2.13.3
-
- Bundle all admin UI implementation dependencies into pre-compiled ESM to eliminate Vite runtime dependency discovery and page reloads.
- Lazy-load AI SDK dependencies and add
@vercel/oidcbrowser shim to eliminate Vite CommonJS export errors. - Hide AI lip trigger when no AI config is specified.
- Fix relative ESM import extension for
loadConfigand addjitidependency to@dyrected/nuxt. (@dyrected/admin,@dyrected/core,@dyrected/nuxt)
v2.13.1
-
-
MySQL Adapter Feature Parity & Resilience (
@dyrected/db-mysql): -
Concurrent Schema Migration Safety: Added in-memory
tableLocksmutex and lifecycle table cache to prevent concurrent requests from firing duplicateALTER TABLEqueries during initialization. -
Duplicate Field Tolerance: Caught
ER_DUP_FIELDNAME(errno1060) and duplicate column errors silently during concurrent column promotion. -
AI Chat Storage Provisioning: Auto-created
_dyrected_ai_threadsand_dyrected_ai_messagesinternal tables with indexes and cascading foreign keys on boot, bringing MySQL to parity with Postgres. -
Promoted Field Types & Backfilling: Added
DATETIME(3)column type support fordate/datetimepromoted fields and added automatic backfill from JSONdatainto newly promoted SQL columns. -
Connection Resilience & Retries: Added default keep-alive (
enableKeepAlive: true,10000ms), connection timeout (20000ms), exponential backoff retries on pool initialization, and exposedpoolOptionsinMysqlAdapterConfig. -
Global Pool Caching: Cached MySQL connection pool on
globalThis(getSharedMysqlClientCache) and exportedcloseAllMysqlClients()to prevent connection exhaustion during Next.js/Nuxt HMR. -
Column Inspection Caching: Replaced repetitive
SHOW COLUMNSqueries on every CRUD/aggregate call with an in-memorytableColumnsCache. -
Configurable Superuser Role (
@dyrected/core,@dyrected/admin):- Added
adminRole?: stringtoAuthConfiginterface. - Added
getAdminRoleForCollectionandisUserAdminhelper utilities in@dyrected/core. - Updated
/first-usersetup endpoint to inspect the collection's configuredadminRoleandrolesfield options, automatically selecting the appropriate superuser role instead of hardcoding'admin'. - Decoupled hardcoded
'admin'checks across routes, controllers, and Admin UI to recognize configured admin roles alongside'super_admin'and'admin'.
- Added
-
Nuxt Config Loading via
jiti(@dyrected/nuxt):- Replaced the static top-level ESM
importin the generated Nitro plugin with dynamicloadDyrectedConfig(viajitiwithesmResolve: true), natively supporting extensionless TypeScript imports and path aliases at initial boot.
- Replaced the static top-level ESM
-
Safe Package Publishing & Workspace Protocol Protection (
dyrected,scripts/publish-packages.mjs):- Replaced native
npm publishwithpnpm publish --no-git-checksso internalworkspace:^dependencies are automatically resolved into concrete published semver versions. - Added an automated pre-publish assertion (
assertNoRawWorkspaceDeps) that verifies package tarballs before upload and immediately aborts if any raw"workspace:"string is present in the distribution manifest.
- Replaced native
-
v2.13.0
-
-
Core Client/Server Clean Decoupling & Schema Serialization:
-
Decoupled server-only AI services (
ai.service,ai-tools,rag.service,embedding.service,ai-rate-limit,observability) strictly into@dyrected/core/server. -
Cleaned the
@dyrected/coreroot entry point to be 100% browser-safe, eliminatingpinologger and Node.js built-ins (os,fs,stream) from client bundles and Next.js Turbopack applications. -
Hardened
/api/schemasserialization to forwardshared,siteId, and collection-levelaiconfiguration, plus field constraints (unique,min,max,step,minLength,maxLength,pattern,allowedTypes,maxSize,virtual,promoted,ai). -
Added public AI readiness flags on the schema payload (
ai: { enabled: boolean, provider?: string, model?: string }). -
First-Class Typed SDK AI Module (
@dyrected/sdk):- Implemented typed
client.ainamespace onDyrectedClient:client.ai.createThread(input?): Create a persistent conversation thread.client.ai.listThreads(): Retrieve all conversation threads.client.ai.getThread(id): Retrieve a single thread by ID.client.ai.deleteThread(id): Delete a thread and cascade its messages.client.ai.postMessage(threadId, input): Post a prompt and receive assistant response.client.ai.listMessages(threadId): Fetch full history for a thread.client.ai.getAction(actionId): Fetch details of a pending human-in-the-loop action proposal.client.ai.executeAction(actionId): Approve and execute a sensitive action proposal.client.ai.rejectAction(actionId, input?): Reject a pending action proposal with feedback.client.ai.searchRAG(input): Semantic vector search across indexed collections.client.ai.reindexRAG(input?): Trigger manual document vector indexing.client.ai.chat(messages, options?): Stream raw chat responses from/api/ai/chat.
- Replaced ad-hoc
qsstringification with pure JSON payload transmission for delete-many and folder actions.
- Implemented typed
-
Admin Sidebar Restructuring, Workspace Switcher & Dashboard AI (
@dyrected/admin):- Moved the sidebar collapse toggle to the top-right of the logo row (
[Logo] Dyrected ... [collapse button]). - Added a compact
WorkspaceSwitcher(h-8, ~32px) directly underneath the logo row, with support for user-restricted site lists and dynamic switching. - Added
setSiteIdtoDyrectedContextandDyrectedProviderwith immediate TanStack Query cache invalidation and localStorage persistence. - Added an interactive AI Assistant Spotlight Card and Ask AI Assistant quick action button on the Dashboard.
- Added an AI Assistant navigation item (
Sparklesicon with⌘Jshortcut badge) in the sidebar. - Positioned Setup on the bottom-left and the ThemeSelector on the bottom-right of the sidebar footer.
- Moved the sidebar collapse toggle to the top-right of the logo row (
-
CLI Recursive Layout Flattening (
@dyrected/cli):- Updated
packages/cli/src/utils/type-generator.tsto recursively flattenrowlayout containers into generated TypeScript interfaces so child fields are never omitted.
- Updated
-
Documentation Updates (
apps/docs):- Documented OpenRouter and custom OpenAI-compatible provider configuration in
ai.mdx. - Added multi-tenant architecture docs: overview, header-scoped tenanting, row-level tenanting, and dynamic schemas.
- Added AI privacy and field-level PII scrubber documentation in
ai-privacy.mdx. (@dyrected/admin,dyrected,@dyrected/core,@dyrected/sdk)
- Documented OpenRouter and custom OpenAI-compatible provider configuration in
-
-
-
OpenAPI & Swagger AI Surface:
-
Integrated all
/api/ai/*endpoints into the live OpenAPI 3.0 specification generator (/api/openapi.json) and Swagger UI documentation (/api/docs). -
Added full request/response schemas for
/api/ai/chat,/api/ai/threads,/api/ai/threads/{threadId},/api/ai/threads/{threadId}/messages,/api/ai/actions/{actionId},/api/ai/actions/{actionId}/execute,/api/ai/actions/{actionId}/reject,/api/ai/rag/reindex, and/api/ai/rag/search. -
Added unit test coverage for AI OpenAPI route definitions in
packages/core/src/__tests__/openapi.test.ts. -
AI Core Prompt Architecture & Safety:
- Streamlined
buildDyrectedSystemPromptwith dual-mode communication (editorial partner by default, developer mode opt-in). - Enforced proactive mutation proposals (
proposeCreateDocument,proposeUpdateDocument,proposeUpdateGlobal) without asking passive permission for content rewrites. - Added automatic provider auto-detection across
OPENAI_API_KEY,GEMINI_API_KEY,OPENROUTER_API_KEY, andAGENTROUTER_API_KEY.
- Streamlined
-
Admin Assistant UI & Streaming Enhancements:
- Added live animated streaming carets and streaming status banners with instant abort (
stop()) support. - Upgraded
TypingDotswith contextual status states ("Thinking...", "Synthesizing data...", "Drafting response..."). - Deduplicated tool execution parts and action proposal keys to eliminate React duplicate key warnings.
- Added live animated streaming carets and streaming status banners with instant abort (
-
Comprehensive Documentation Suite (
apps/docs):- Added
model-content/configuration/ai.mdx: Complete guide to configuring AI, setting brand voice directives, and collection prompts. - Added
editor-experience/ai-assistant.mdx: Guide to the embedded Lip Trigger assistant drawer, live diff viewers, and human-in-the-loop proposals. - Added
deliver-content/ai-agent-api.mdx: ProgrammaticAIAgentguide for Server-Sent Events (SSE) streaming and Telegram/WhatsApp webhooks. - Added
deliver-content/rest-api/ai-endpoints.mdx: Complete REST API reference for all AI endpoints. - Added
examples-and-recipes/library/chat-to-order-proposal.mdx: Recipe for parsing unstructured customer chat logs into structured database orders. - Added
examples-and-recipes/library/custom-ai-tools.mdx: Recipe for extending Dyrected AI with custom server-side functions and Zod schemas. (@dyrected/admin,@dyrected/core)
- Added
-
v2.12.0
-
- Digital Asset Management (DAM): Added folder hierarchy tree with desktop sticky sidebar and mobile pill carousel, Move to Folder modal, in-place asset replacement, MIME type filter chips, and full-width
MediaLibraryDialog. - Focal Point & Smart Cropping: Integrated focal point picker in Media Inspector with automatic CSS
object-positioncalculations in<DyrectedMedia>and dynamic CDN crop parameters in Cloudinary/API transformations. - Spreadsheet Grid Cell Editors: Added full in-cell editing for select, multi-select, link, date/datetime, media/image, and relationship pickers.
- Action Dialog & Form Engine Parity: Added async hook support,
setValue(fieldName, value)sibling mutation support, functionaldefaultValue: ({ doc, docs, user }) => ...serialization/client-evaluation, and unified document context across action dialog modals and collection forms. - Sticky Table Headers & Mobile Scroll Container: Consolidated table view scrolling into a single unified scroll container with pinned sticky header rows and sticky selection checkbox columns for smooth vertical and horizontal navigation on desktop and mobile. (
@dyrected/admin,@dyrected/core,@dyrected/sdk,@dyrected/storage-cloudinary)
- Digital Asset Management (DAM): Added folder hierarchy tree with desktop sticky sidebar and mobile pill carousel, Move to Folder modal, in-place asset replacement, MIME type filter chips, and full-width
-
Add
exprexpression builder withexpr.ifElse, concise shorthands (expr.empty,expr.notEmpty,expr.equals), and fluent transforms (.slugify(),.lower(),.upper(),.trim()). Improvedyrected upgradeCLI command with sanitized environment execution and streamlined manifest updates. (dyrected,@dyrected/core)
v2.11.0
-
Support dynamic and JEXL
defaultValueevaluation,admin.hooks.onChangelive reactivity,admin.hooks.optionscascading dropdowns, andadmin.conditionvisibility insideActionFormDialogandFormEngine. (@dyrected/admin,@dyrected/core) -
- Fix Admin UI session staleness and authentication desynchronization:
- Add proactive background token refresh timer scheduled 5 minutes before JWT expiration.
- Refresh token on browser tab
focusandvisibilitychangewhen returning to an open dashboard. - Dispatch
dyrected:auth-unauthorizedand supportonAuthErrorcallback in@dyrected/sdkon 401 responses. - Automatically attempt token refresh on 401s in Admin UI, falling back to instant login gate transition if session is expired or revoked.
- Fix user state leak bug in
DyrectedProviderthat prevented logout and login page rendering. - Call backend
POST /api/collections/:slug/logoutto revoke server session in__auth_sessionsduring logout. - Allow operational view component slots (
afterViewHeader,beforeViewHeader,beforeViewContent,afterViewContent) to resolve components registered under eithercomponents.collectionVieworcomponents.collectionList. - Enhance action and confirmation dialogs for mobile and tall content:
- Render as a mobile bottom-sheet (
max-sm:bottom-0, slide from bottom, top grab handle) on small viewports. - Constrain all fields and custom modal components within the device viewport width (
w-full min-w-0 overflow-x-hidden). - Enable independent vertical scrolling (
overflow-y-auto) with fixed, docked headers and action footer buttons.
- Render as a mobile bottom-sheet (
- Add operational view Refresh button in ViewHeader and mobile action menu:
- Refetches both collection/view data and summary metrics in the background.
- Keeps current datasets and stats on screen while displaying spinning and pulsing refetch indicators.
- Update back button navigation on document edit and global editor pages to use browser history when available, preserving active operational view filters, sorting, and pagination. (
@dyrected/admin,dyrected,@dyrected/sdk)
v2.10.1
-
- Support
submitLabelon operational view actions to customize the modal submit/run button text. - Automatically prefill action modal forms with the target document's current field values when executing row actions.
- Normalize logical operators (
AND/and,OR/or) case-insensitively inwhere-sanitizer. - Apply schema default values on
create()before persisting to the database. - Strictly type operational view filters as
WhereClause | string. - Add thorough JSDoc documentation across all operational view types and interfaces.
- Add architecture specs for
npx dyrected doctordiagnostics and multi-adapter automatic field promotion. (@dyrected/admin,dyrected,@dyrected/core)
- Support
-
- Added type-safe
whendeclarative condition and expression builder to@dyrected/sdkand@dyrected/core. - Added framework parity for
useDyPath()anduseDyPathHelper()in@dyrected/vueand auto-imported in@dyrected/nuxt. - Enhanced CLI
upgradecommand to automatically refresh.dyrected/ai-rules.mdwith the latest canonical rules when upgrading packages. - Added Marketing Site Page Builder Architecture, Array Field Object Shape Contract, and Type Synchronization Workflow to
@dyrected/knowledgeprompt templates and AI rules. - Added
/docs/[...slug]legacy catch-all redirect route in documentation.
- Added type-safe
v2.10.0
-
-
Aggregate Engine Expansion (
countDistinct,distinct,groupBy): -
Added support for
countDistinct({ countDistinct: "fieldName" }) to count unique non-null values in a single database query. -
Added support for
distinct({ distinct: "fieldName" }) to extract unique non-null values without loading full documents. -
Added grouped aggregation support via
groupByparameter (?groupBy=<field>or{ groupBy: "field", aggregates: { ... } }) returning per-group metric breakdowns with automatic"__unassigned__"sentinel handling for missing/null values. -
Implemented cross-adapter parity for all aggregation operations across PostgreSQL, SQLite, MySQL, and MongoDB.
-
Updated live OpenAPI specification (
/api/openapi.json) and Swagger documentation with complete aggregate schemas and response types. -
Grouped Views & Admin UI Performance Optimization:
- Replaced client-side document group extraction with native single-query database aggregations in grouped Table, Kanban, and Spreadsheet views, eliminating $N+1$ query waterfalls and reducing database roundtrips.
- Deduplicated schema queries across
AdminShell,OperationalViewRoute, and dashboard pages by utilizing cached context schemas. - Added
defaultViewcollection configuration support with automated route redirection and clean sidebar submenu rendering.
-
-
- Filter Join Operator: Support
AND/ORtoggle in toolbar and URL parameters (joinOperator=and|or) for inter-column filter combinations in operational views. - Action Dialog Document Context: Pass target document/row context (
doc,docs,record,row,data,formData) into action form dialogs,FieldRenderer, and custom field components. - View Features & Action Ordering: Properly serialize and respect
view.features(edit,delete,duplicate) and customactionOrderin operational view action menus and table columns. (@dyrected/admin,@dyrected/core)
- Filter Join Operator: Support
v2.9.0
-
Promote operational table to canonical list view:
- Default view synthesis in
getSchemas:resolveSchemas(DyrectedProvider) now synthesizes alistview (layout: table, columns fromadmin.defaultColumnsor first 5 display fields) for collections without explicitviews, so every collection has a table workspace andCollectionRoutecan render without redirect. - Standardized preference keys: Column, view-mode, and toolbar keys now use
layout:collections:${slug}:listfor the default view andlayout:collections:${slug}:view:${viewSlug}[:variant|:mode|:toolbar]for named views (variant suffix forcards/kanban). Reads fall back to legacy keys (view-pref:,view-mode:,view-columns:,view-toolbar:) and migrate on next save. - CollectionRoute (Option B):
/collections/:slugnow rendersOperationalViewPagedirectly with the first (synthesized) view instead ofCollectionListPage(list-view-v1).list-view-v1.tsxis deprecated (kept for reference). Media collections still renderMediaPage. - URL compat shim: Legacy
?where=<json>(FilterBuilder) and?search=<term>params are merged into the view'sfilter(mergeFilters/containson first searchable field) so old shared links keep working. - Slot aliasing:
admin.components.beforeList→beforeViewHeader,beforeListTable→beforeViewContent,afterListTable/afterList→afterViewContentare now rendered viaAdminComponentSlotwith a stubbedCollectionListSlotPropsso existingcollectionListslot consumers continue to mount inside operational views.collectionViewslots remain primary.
list-view-v1.tsxis marked@deprecatedand will be removed in a future minor. (@dyrected/admin) - Default view synthesis in
-
Operational Views:
defineView/defineActionconfiguration helpers, view-aware admin sidebar and routing, table, kanban, calendar, cards (with multi-image carousels and edge-to-edge covers), and spreadsheet layouts, summary metric stat cards backed by the aggregation engine, an actions runner that resolves declarative mutations (now(),input.*,doc.*) or self-hosted handlers through the lifecycle-hook pipeline, and 4 new recipes in@dyrected/knowledge. (@dyrected/admin,@dyrected/core,@dyrected/sdk) -
- Where Operator Aliases (
greater_than,less_than, etc.): Added support for verbose operator names inparseSqlWhereandparseMongoWhere(greater_than,less_than,greater_than_equal,greater_than_or_equal,less_than_equal,less_than_or_equal,like), resolving HTTP 500 errors on Detail View adjacent record navigation queries (Previous / Next document buttons). - Core Jexl Pre-bundling: Pre-bundled
jexlinto@dyrected/coreto prevent Vite and browser runtime CJS default export errors across consumer applications. - Public/Default Preferences Read: Allowed
GET /api/preferences/:keyto useoptionalAuth, enabling unauthenticated clients (e.g. login screen, theme initialization) to retrieve global preferences and default fallback values without throwing 401 Unauthorized errors. Mutations (PUT,DELETE) remain protected. - Media Library Clipboard Paste & Progress Indication: Added global clipboard paste support (
⌘V/Ctrl+V) toMediaLibraryDialogwith auto-switch to the Upload tab, live upload progress display, toast feedback notifications, and discoverability shortcut badges. (@dyrected/admin,@dyrected/core)
- Where Operator Aliases (
v2.8.3
-
- Lazy Database Connections: Removed eager initialization in constructors for
@dyrected/db-postgres,@dyrected/db-mysql, and@dyrected/db-mongodb. Network sockets, connection pools, and database creation queries are now deferred until the first actual query or explicit lifecycle call, preventing hanging sockets and timers when loadingdyrected.config.tsduring static builds (nuxt build,next build, type-generation, or CI pipelines). - Graceful Disconnect & Teardown: Added
disconnect(): Promise<void>toDatabaseAdapterinterface across all database adapters (@dyrected/db-postgres,@dyrected/db-mysql,@dyrected/db-mongodb,@dyrected/db-sqlite) and exportedcloseAllPostgresClients()from@dyrected/db-postgres. - Nuxt Lifecycle Teardown: Added a
closehook in@dyrected/nuxtto automatically calldisconnect()on active database adapters and flush cached client connection pools when Nuxt finishes building or shuts down.
- Lazy Database Connections: Removed eager initialization in constructors for
v2.8.2
-
Enhance Detail Views with inline editing, custom component resolution, and dynamic presentation options:
- Custom Component Resolution: Resolve custom Detail View components directly from runtime
DyrectedContextand<DyrectedAdmin :components="..." />in Vue/Nuxt and React/Next.js. - Inline Field Editing: Support
editable: trueondisplayField()with interactive inputs, immediate SDK mutations, and save/cancel micro-interactions. - Dynamic Badge Presentation: Support
badgeColorswith named palettes, hex codes, Tailwind classes, and wildcards ondisplayFieldanddisplaySection. - Media Previews: Render uploads and media relationships seamlessly in Detail Views using
DyrectedMediawith aspect ratio, alignment, and object-fit constraints. - Adjacent Record Stepper: Add header and footer stepper controls to navigate smoothly between previous and next records in the active collection.
- JEXL Visibility Context: Pass full document properties to visibility evaluation context for robust conditional rendering. (
@dyrected/admin,@dyrected/core,@dyrected/nuxt,@dyrected/vue)
- Custom Component Resolution: Resolve custom Detail View components directly from runtime
v2.8.1
-
- Detail View Inline Editing (
editable: true): Added interactive inline editing directly within the Detail View screen. Editors can toggle simple fields (such as internal notes, tags, status choices, quantities, and dates) into editable form inputs with single-click save and cancel controls, updating records immediately via the client SDK without navigating away from the detail screen. - Dynamic Badge & Tag Color Palettes (
badgeColors): Introduced thebadgeColorsresolution engine in Admin Detail Views. Supports 20+ named color palettes (emerald,amber,rose,sky,indigo,purple,violet,zinc, etc.), custom hex codes with automated background tints, raw Tailwind classes, and wildcard (*) fallback mappings. - Section Badges and Palette Styling: Added
badgeandbadgeColorconfiguration options todisplaySection(), allowing section headers to display contextual status or count badges. - Human-Readable Option Resolution: Enhanced select and radio field presentation in Detail Views to resolve raw value identifiers to their human-readable schema option labels.
- Rich Media & Thumbnail Previews: Upload fields and media relationship documents in Detail Views now render responsive image cards, video players, and file download links instead of raw relationship identifiers.
- Star Rating & Color Swatch Displays: Added visual star rating scales and interactive color swatch previews with hex copy utilities to Detail Views.
- Auth Bootstrap & External Token Resolution: Fixed an issue where incoming redirect tokens (
dyrectedExternalToken) caused the admin loading splash to hang indefinitely when external auth was not explicitly configured in the schema. Added cookie session support (__dyrected_token/dyrected_token) and optimistic JWT payload decoding so authenticated dashboards mount instantly without redundant roundtrips. - Detail View Adjacent Record Navigation: Added subtle Previous and Next record traversal in the Detail View. Includes a top-header stepper (
</>), a responsive bottom footer bar with previous/next document titles and directional arrows, and keyboard shortcuts (Jfor next,Kfor previous). - Direct Media URL Resolution & Unified
DyrectedMedia: Standardized media URL handling across@dyrected/adminso that media objects with a populatedurlproperty use the target URL directly rather than reconstructing fallback paths. Centralized avatar, image, HTML5 video, YouTube/Vimeo embed, audio, and file download renderers into a universal<DyrectedMedia />component. - Upload & Image Field Relationship Population (
depth >= 1): FixedPopulationServicein@dyrected/coreto populateuploadandimagefield types (defaulting to the target upload collection ormedia) when queries specifydepth >= 1. Added automatic bare-ID media resolution fallback to<DyrectedMedia />in@dyrected/adminso that media assets display immediately even if received as unpopulated IDs. - Interactive Relationship Badge Links (
DetailRelationshipLink): Relationship and author fields in Detail Views now render interactive linked badges featuring avatar images or initial icons, document titles, and direct navigation links to the target record. If received as an unpopulated ID string, the component automatically resolves the record title and avatar asynchronously. - Tag and Array Badge Rendering: Array fields, multiSelect lists, and JSON string arrays (such as
Tags: ["insights", "operations"]) now automatically parse and render individual badge pills with support forbadgeColorspalettes, avoiding raw JSON string outputs. - Comprehensive Detail Reference & Type Definitions: Added complete JSDoc annotations and automated contract generation in
@dyrected/knowledgefor all 9 Detail View helper functions (displayField,displaySection,displayTabs,displayTab,displayGrid,displayRepeat,displayComputed,displayText,displayDivider,displayCustom) and their configuration options. (@dyrected/admin,@dyrected/core)
- Detail View Inline Editing (
v2.8.0
-
Detail View System:
- Added read-only Detail View pages and configurable layout renderers for collections (
/collections/:slug/:id) and globals (/globals/:slug). - Added layout configuration helpers in
@dyrected/core:defineDetailView,defineSection,defineFieldCard,defineRepeatCard,defineTab,defineTabs,defineComputedCard,defineDivider,defineInfoText, anddefineFieldGrid. - Added support for dynamic conditional visibility on detail cards, sections, and tabs using boolean values or JEXL expressions evaluated against
{ doc, user }. - Added type-aware formatters and display variants including currency, percentages, progress bars, star ratings, tags, avatars, color swatches, and relations.
- Added custom component slot support for detail views in both React and Vue runtimes.
- Added read-only Detail View pages and configurable layout renderers for collections (
-
Collection Aggregations System:
- Added
POST /api/collections/:slug/aggregateendpoint to@dyrected/coreand integrated it into the OpenAPI specification generator. - Added collection
aggregate()method to@dyrected/sdk. - Implemented database aggregation queries across all adapters:
@dyrected/db-postgres,@dyrected/db-mysql(withIF()conditional aggregation),@dyrected/db-mongodb, and@dyrected/db-sqlite. - Added comprehensive security checks and access control gates for collection aggregations.
- Added
-
Knowledge & Documentation Runtime:
- Added runtime-aware documentation manifest generator in
@dyrected/knowledge. - Synchronized OpenAPI endpoints, recipes, and LLM reference indexes.
- Added runtime-aware documentation manifest generator in
v2.7.1
-
- Scoped split-pane edit page width calculation exclusively to desktop screen breakpoints, preventing form compression on mobile viewports
- Replaced zero-based index array warnings with human-readable collection and field slug names in CLI
sync:schemaoutputs - Added direct documentation links to CLI schema sync warning messages and core config validation outputs
- Added comprehensive built-in Jexl helper utility functions (
slugify,lower,upper,trim,capitalize,truncate,readingTime,wordCount,replace,startsWith,endsWith,now,today,formatDate,addDays,diffDays,isPast,isFuture,includes,join,first,last,compact,unique,length,round,clamp,default,coalesce,isEmpty,get) across@dyrected/core,@dyrected/admin, and CLI declarative validation (@dyrected/admin,dyrected,@dyrected/core)
-
- Isolated server observability and logger runtime dependencies under
@dyrected/core/serverto prevent Node core modules (fs,worker_threads,stream) and Pino from leaking into frontend client bundles. - Added browser fallback module configurations for Next.js (
withDyrected) and Nuxt module Vite build hooks to ensure clean client component compilation across Turbopack and Vite. (@dyrected/core,@dyrected/next,@dyrected/nuxt)
- Isolated server observability and logger runtime dependencies under
v2.7.0
-
Add controlled admin theme support so host apps can drive the admin theme and receive theme changes back through the public admin API. This also fixes the admin theme provider initialization so it does not access refs during render. (
@dyrected/admin) -
- Added dark mode SVG logo asset and theme-aware fallback rendering in
admin-shell - Migrated Nuxt example component config access to
useRuntimeConfig - Transitioned default live preview mode to
postMessageacross prompt templates, skills, documentation, and recipes - Updated Dyrected configuration, environment integration, and content modeling rules for rich text and tabbed admin layouts
- Modularized and consolidated prompt generation logic, AI rules, and shared rule templates (
@dyrected/admin,dyrected)
- Added dark mode SVG logo asset and theme-aware fallback rendering in
-
@dyrected/[email protected]
-
@dyrected/[email protected] (
@dyrected/next) -
@dyrected/[email protected] (
@dyrected/next)
v2.6.4
-
Improve admin safety and auth onboarding across admin, core, and SDK.
- add a professional invite dialog in admin with copyable invite URLs and role selection for new invites
- support invite acceptance directly from admin invite links
- pre-create pending invited users in auth collections so they appear in admin lists before acceptance
- let invite and reset emails use clickable URLs with stronger email-client-safe HTML and visible link fallbacks
- expand dashboard "Needs attention" checks with backend health and invite-related signals
- replace browser delete alerts with admin dialogs, including typed confirmation before deleting auth users (
@dyrected/admin,@dyrected/core,@dyrected/sdk)
-
Add Cloud-safe declarative hooks, broader declarative-expression validation, and clearer config diagnostics across core, admin, Nuxt, SDK, and CLI.
- add declarative string hook support for collection/global
beforeRead,afterRead, andbeforeChange, fieldbeforeChange, and fieldadmin.hooks.onChange - preserve supported declarative hook strings during
sync:schema, strip function hooks from Cloud payloads intentionally, and warn with exact schema paths - validate declarative access rules, string access policies, declarative hooks,
admin.condition, andadmin.previewUrlearly with exact config paths and cleaner diagnostics - expose config diagnostics from
/api/schemasso admin surfaces can consume them, and improve admin dashboard attention signals around config issues - improve Nuxt startup and reload reporting for invalid declarative config with formatted diagnostics instead of noisy raw errors
- document the Cloud-safe access and hooks model more clearly, including synced string policies,
createdByCurrentUservsisOwner, declarative hook contexts, and short notes about early validation for access, hooks, preview, andadmin.condition
- add declarative string hook support for collection/global
v2.6.3
-
Polish the admin editing experience with better loading and layout behavior.
- replace branded and text-only loading states with skeleton loaders across bootstrap, collections, globals, dashboard, and media views
- add professional not-found states for missing collections, globals, routes, and missing edit entries after loading resolves
- keep the desktop sidebar pinned to the viewport while the main content scrolls independently
- remove the nested media-page scroll container so the page uses a single parent scroll area
- debounce admin list and media search while keeping existing results mounted so only the results region refreshes during server-side search
- add a draggable desktop split view for resizing the live preview and form editor on collection edit pages
- make rich text editor prose respect dark mode typography tokens
- use configured global
admin.iconvalues in the global edit header - @dyrected/[email protected]
- @dyrected/[email protected] (
@dyrected/admin)
-
@dyrected/[email protected]
-
@dyrected/[email protected] (
dyrected,@dyrected/next) -
@dyrected/[email protected] (
@dyrected/next)
> For earlier release notes (v0.x), see the full CHANGELOG.md on GitHub.