The DMS interface
Overview
The DMS ships one public AntelopeJS interface package, @antelopejs/interface-dms. Everything a module needs to declare pages, build components, authenticate a request, send a notification or render an HTML template comes from that single package, through a subpath named after the domain it belongs to. Never reach the surface through the runtime package @antelopejs/dms.
{
"dependencies": {
"@antelopejs/interface-dms": ">=0.0.1 <1.0.0"
}
}
This section is the contract reference: the exact symbol names, options and return types, grouped by domain. The DMS guide covers the same ground task by task, organised around what you are building.
If you are learning the DMS, start with the Quickstart and Pages & components. Return here when you need an import path, a signature, or the exact behavior of an option; you do not need to read every domain before building a page.
| Task | Guide with examples | Contract reference |
|---|---|---|
| Build a page and choose its layout | Pages & components | Pages and modules, Layout |
| Add workspace settings | Settings pages | Page access |
| Protect a route and scope its data | Auth & tenancy | Authentication, Tenancy |
| Extend another module's screen | Page extensions | Extend a page |
Separately published extension interfaces have their own module interface references, including Builder. This page covers @antelopejs/interface-dms itself.
One installed copy
The host and every module must resolve the same installed copy of @antelopejs/interface-dms. The package holds live state, not just types: the page, category and extension registries, the permission tree, the hook registry, the data-type and block registries and the component slot resolvers. A second copy gets its own empty registries: pages register into a tree nobody reads, permissions never reach the roles form, and hooks never fire, without any error. @antelopejs/core checks this before constructing modules and fails with Incompatible interface package resolution when a module resolves another copy.
Depend on the package with a wide range, raising the lower bound to the version you need rather than pinning an upper one, so package managers can deduplicate, and never vendor or bundle it into a module. @antelopejs/dms, which implements the interface, is the exception: it caps its range below the next minor, so a breaking minor never reaches an older DMS.
The runtime also hands a module a per-context view of the values it receives through an interface, so reference equality does not survive the round trip. Compare registrations on a field, never with ===, and compare plain data rather than the views themselves: isDeepStrictEqual and assert.deepStrictEqual refuse two views that hold equal values.
The Domains
| Domain | What it is for | Import prefix |
|---|---|---|
| Core | Pages, modules, components, permissions, tenancy, invites, hooks, realtime, quick actions and layout banners. | @antelopejs/interface-dms and its root-level subpaths |
| Auth | Authentication decorators, token and session handling, and the user and session tables. | @antelopejs/interface-dms/auth |
| Base | The component vocabulary: forms, tables, charts, layout, trees, data types and the shared prop types. | @antelopejs/interface-dms/base |
| Notifications | Declaring notification categories and subjects, and building and sending notifications. | @antelopejs/interface-dms/notifications |
| HTML Render | Registering HTML templates and rendering them server-side. | @antelopejs/interface-dms/html-render |
Start with Core and Base: the first declares pages and the components they carry as serializable data, the second is the concrete set of components you fill those pages with. Auth resolves a request to a user, which the permission and tenant guards build on. The remaining two stand on their own and are used where you need them.
Subpath Map
Each subpath is its own entry point: importing one does not pull the others in, and the modules that register schemas or controllers as they evaluate are deliberately kept off the root barrel. Every domain's introduction carries the detailed map of its own subpaths; this is the whole set at a glance.
| Subpath | Holds | Domain |
|---|---|---|
@antelopejs/interface-dms | The root barrel over the core surface below | Core |
/page | Pages, categories, modules, layouts, page extensions, dynamic menus, frontend modules | Core |
/component | Component, ComponentBuilder, actions, watches | Core |
/component-slots | RegisterComponentSlot, ComponentSlotResolver, SlotOptions | Core |
/attachments | SaveComponentFiles and its request, field and result types | Core |
/permission-gate | Shared PermissionGate fields for permission-filtered UI | Base |
/permissions | The permission registry and the permission computation | Core |
/permissions-resolver | Registering and running permission resolvers | Core |
/guards | AuthUserWithPermission, AuthTenantOwner, AuthTenantMember | Core |
/constants | Schema names and the default tenant | Core |
/db, /db/models, /db/tables | The Tenant, TenantMember, Role and UserInvite tables and models | Core |
/request-tenant | getRequestTenantId | Core |
/tenant-scoped-model | TenantScopedModel | Core |
/tenant-access | Tenant access gates | Core |
/tenant-ownership | Membership and ownership writes | Core |
/tenant-lifecycle | Producer admission and permanent closure before tenant deletion | Core |
/data-controllers | The built-in members and roles data controllers | Core |
/invites | Inviting a user into a tenant | Core |
/invite-extensions | Invite form contributions, validation, delivery and availability | Core |
/invite-resolution | Durable terminal decisions and retryable invite effects | Core |
/hooks | The Hook enum, handlers and dispatch | Core |
/tenant-export | The tenant export archive, contribution and manifest types | Core |
/realtime | Page topics, publishing and backend subscription | Core |
/quick-actions | Command-palette entries | Core |
/layout-banners | Global banners under the dashboard header | Core |
/uploads | Signed upload tokens for the file and image fields of a serialized component | Core |
/types | MaybePromise, the one shared type alias | Core |
/api-base-url, /client-base-url | GetApiBaseUrl, GetClientBaseUrl: the public origins of the API and the dashboard | Core |
/client-ip | getClientIp, ResolveClientIp: a request's client address behind the trusted proxies | Core |
/auth | Authentication decorators, tokens, sessions, external identities, account mail | Auth |
/auth/db, /auth/db/models, /auth/db/tables | The User, Session and UserExternalIdentity tables and models | Auth |
/base | The component barrel: forms, tables, charts, cards, layout, trees | Base |
/base/types | Base props, colours, sizes, buttons, action targets, row-action rules, guards | Base |
/base/form | Form, the field and group shapes, FormComponents, FormEvents, the schema helpers | Base |
/base/table-view | TableView, @Column, TableViewRoutes, guards, row actions | Base |
/base/data-types | DataType, the registration decorators, DefaultDataTypes, DefaultDataCompareTypes, StatusType | Base |
/base/… | The per-component subpaths — chart, grid, stack, tab, tree, custom, layouts, helpers/… | Base |
/notifications, /notifications/types | Categories, subjects, the notification builder and its dispatch targets | Notifications |
/html-render | RegisterHtmlTemplate, GenerateHtml and the template reference types | HTML Render |
Beyond these entry points, built files are importable through the ./* export (@antelopejs/interface-dms/base/form-types). Moving or renaming a public path is a breaking change, like removing an export.
Importability does not make a declaration public. Paths under internal/, symbols tagged @internal, and internal namespaces are wiring between the interface and its implementation, not supported consumer APIs. This includes compatibility exports retained at old paths. Public types named by a supported signature remain part of its contract; use the documented entry points rather than calling internal proxies or raw writer helpers.
How to Read a Domain
Every domain folder opens with 1.introduction.md. It gives you the overview, the key features, the AntelopeJS packages the domain depends on, one runnable quick-start example, and the list of the folder's other pages.
The numbered pages after it are topic pages, ordered so that reading them front to back builds up. Each one starts with an overview, then works through the surface task by task with a code example per section and a table for anything that takes options. Every topic page ends with a link to the next one, so you can also follow a folder straight through from its introduction.
Read a topic page on its own when you already know which surface you need.
Ship a skill with your module
Teach coding agents (Claude Code, Codex) and the dms-ai assistant how to use your module by shipping a SKILL.md next to its code, declared in package.json.
Introduction
The core contract of the DMS: pages and modules, components, permissions, tenancy, invites, hooks, realtime, quick actions and layout banners.