
Product
Socket Now Protects the Microsoft Edge Extension Ecosystem
Enterprise security teams can now detect malware, credential theft, suspicious network activity, and risky updates across Microsoft Edge extensions.
@ultimat3/admin
Advanced tools
Two dashboards: the /_x framework dev panels and the generated, AI-first app admin
Two dashboards live here. They are not the same thing — and they have two doors.
/_x — framework dev dashboard | admin — generated app admin | |
|---|---|---|
| Import | @ultimat3/admin/dev | @ultimat3/admin |
| Audience | you, debugging the framework | your operators, and their agents |
| Environment | development only — mounting it with env=production or role=production throws X_DEV_DASHBOARD_IN_PROD | production |
| Authz | none: it is your own machine | the app's policies, one decision per surface |
| Data | introspection calls (describeRoutes, inspect, dependentsOf, …) | the entity registry + repos |
| Shipped in the app image | never mounted | mounted at /admin |
/_x panelsOne panel per file. Each kills one question, and each is available as --json — the tab is a rendering of the payload, not a second source.
| Panel | Kills |
|---|---|
routes | which handler serves this? — render mode, offline strategy, revalidate tags, budget |
timeline | where did the time go? — flamegraph of SQL, cache, action, policy spans + the N+1 count |
live | what does each subscriber receive, and why — the matcher's decision trace |
jobs | queue depth, step traces, retry-from-step target, dead letter |
db | psql in a tab (read-only; assertReadOnly refuses DML), schema + drift (null unless a host wires the check) |
mail | caught mail, rendered, per locale, with the locale gaps listed |
cache | the tag graph — what invalidated what, and which tags are orphans |
policy | the permission matrix per actor, every cell carrying its trace |
manifest | emitted x.manifest.json diffed against the committed one |
import { devDashboard, defaultDevSources } from '@ultimat3/admin/dev';
const dev = devDashboard({ sources: defaultDevSources({ authz, actors }) }); // throws in prod
const response = await dev.handle(request); // null when the path is not /_x
await dev.json('jobs'); // the same payload /_x/jobs renders from
The root barrel does not re-export any of this: x dev mounts /_x without pulling a Solid
component tree into the process, and an admin view cannot reach a dev panel by accident.
One call, a working CRUD admin: columns from the entity's columns, filters from indexed columns, validation from the entity's schema, labels from i18n keys.
entities takes the entities themselves — the objects entity() returned, not their describeEntities() projection. The admin reads $columns, $primaryKey, $schema and $describe() off them; RegisteredEntity in registry.ts is the compile-time check that it may.
import { defineAdmin, adminRoutes, policyAuthz, memoryAuditLog } from '@ultimat3/admin';
import { posts, users } from '@app/db/schema';
export const admin = defineAdmin({
entities: [posts, users],
// `AdminAction` is the admin's own shape: a `permission` (never optional) plus a handler.
actions: [{ name: 'post.publish', permission: 'post:publish', entity: 'posts', handle }],
resources: { posts: { repo: postsAdminRepo, listFields: ['title', 'status', 'publishedAt'] } },
branding: { nameKey: 'admin.brand.name', accent: '--x-color-brand', mode: 'system' },
auth: { actor: (request) => session(request), authz: policyAuthz({ policies }) },
audit: memoryAuditLog({ sinks: [auditTable] }),
});
export const routes = adminRoutes(admin); // every view `ssr`, gated — an admin screen is per-actor
There is no view DSL here, and there will not be one. Every renderer is an ordinary SolidJS
component in an ordinary .tsx file importing @ultimat3/ui — AdminList, AdminForm,
AdminDetail, Widget, AdminLayout are each exported on their own, so a table can be lifted
out of its page and dropped into a screen the generator never wrote:
import { AdminList, AdminForm, Widget } from '@ultimat3/admin';
<AdminList resource={admin.resource('posts')} page={page} ctx={ctx} … />; // just the table
<Widget field={field} value={row.total} ctx={ctx} mode="read" />; // just one cell
Widget takes the field and the raw row value, not pre-derived props: widgetProps() is the
guard (money is minor units, a timestamp has an IANA zone) and the component calls it, so there is
no way to render a cell that skipped it. mode is read or edit; an edit cell also takes the
control the surrounding <Field> hands its child, and onInput.
An admin route is an ordinary route primitive; an admin action is an ordinary action. Nothing
in this package is written in a second language that only the dashboard understands — the escape
hatch is the same TSX as the main path, which is why there is no cliff to fall off when a screen
stops being CRUD.
The bespoke ops screen is the common case, not the corner: a reconciliation fixer, a proxy health
board, a deploy button. Declare it in pages: and it becomes a real admin route.
// admin/ops/page.tsx — a component, nothing framework-shaped about it
export function OpsPage(props: AdminPageProps) {
return <OpsBoard counts={await mediaStateCounts()} />;
}
// admin/index.ts
defineAdmin({
entities: [posts],
pages: [
{
path: '/ops', // rooted at basePath → /admin/ops
titleKey: 'admin.ops.title',
navGroup: 'admin.group.operations', // omit to keep it out of the nav
permissions: ['ops:read'], // `admin:read` is composed in front of it
component: OpsPage,
},
],
auth,
});
| What you get | How |
|---|---|
a row in app.routes, adminRoutes(), x manifest | pageRoutes() folds it in beside the generated screens |
| a nav item that disappears for an actor who cannot open it | NavItem.permissions → visibleNav |
a defineRoute({ policy }) you never wrote and cannot omit | adminRouteConfig composes permissions[0] into it |
| a per-request refusal, audited, before your component runs | guardedPage() wraps it in decideAll |
The guard is not yours to remember. adminRoutes() hands the router the wrapped component,
never the one you wrote, and AdminPageProps.ctx is required by the type — a page component
cannot be called without the handle the guard decides on. permissions: [] throws
X_ADMIN_PAGE_UNGUARDED where it is written, not on the first unauthenticated request. A path
that shadows a generated screen throws X_ADMIN_PAGE_PATH_INVALID the same way.
Custom pages are render: 'ssr', hydrate: 'never': the guard runs on the server, so there is no
shell to ship and nothing to decide twice.
A host whose router is file-based writes its own page.tsx for an admin URL. Take the gate from
the route table — never type it a second time:
import { adminRouteFor } from '@ultimat3/admin';
import { admin } from './admin';
const route = adminRouteFor(admin, `${admin.basePath}/users`);
export const config = defineRoute({
render: 'ssr',
hydrate: 'never',
offline: 'network-only',
policy: route.policy, // `defineAdmin()`'s, from `permissionsForOperation('users', 'list')`
meta: () => ({ title: t('admin.users.title') }),
});
route.policy is the same object route.config.policy carries, so the gate has one declaration
and one reader. A path the admin does not declare throws X_ADMIN_PAGE_PATH_INVALID listing the
paths that would have worked — a page serving an admin URL the admin never built is a screen whose
permissions nothing composed.
defineAdmin takes plain values — entities, resources, actions, jobs, pages, nav,
branding, auth, audit. Every one of them can be imported from its own module, so the cut is
along the input's own keys and there is exactly one layout:
app/admin/
index.ts defineAdmin({ … }) — composition only, no logic
auth.ts actor() + policyAuthz({ policies })
nav.ts groups, order, extras
<resource>/
resource.ts the AdminResourceOptions entry (listFields, sensitive, labelField)
repo.ts the AdminRepo binding
actions.ts the AdminAction[] for this entity
pages/<name>.tsx a custom page component for this entity, if any
pages/<name>.tsx an app-wide custom page (ops, reconciliation, deploy)
index.ts imports each and composes. Nothing here is a framework rule — it is what the input
shape already is, written down once so two apps do not invent two layouts. x g admin emits it.
| Admin decision | Read from |
|---|---|
| field type + widget | $meta.kind, refined by values (select) and references (reference) |
| one line vs prose | text({ max }) has a length; text() does not |
| read-only | a generated default (uuid(), defaultNow(), onUpdateNow()) or a key column |
| filters, sort | $meta.index / unique / primaryKey — never an unindexed column |
| row address | $primaryKey[0], composite keys included |
| validation | $schema, the entity's own Standard Schema |
sensitive, a fixed currency and labelField have no entity source and are never guessed: declare them in resources: { <entity>: { … } } or they are absent.
| Rule | Where |
|---|---|
Money is { minor, currency } — a float throws X_ADMIN_FIELD_UNSUPPORTED | widgetProps |
| A timestamp never renders without an IANA zone | assertZone |
Pagination is keyset — AdminListQuery has no offset field | pagination.ts |
A cursor is signed by @ultimat3/core and scoped to its resource — a forged or borrowed one is page one, never another table's position | pagination.ts |
| A button an actor cannot press is never rendered, and the call is refused by the same decision | action-gate.ts |
Destructive operations re-confirm (<entity>:<id>) and are always audited | permissions.ts, crud.ts |
| Every mutation and every denial is on the audit log, with a before/after diff | audit.ts |
Branding aliases tokens only — accent: '#7c3aed' is a compile error | theme.ts |
Reads are audited too, and on both branches: adminDetail keys its entry on the row,
adminList and adminSearch key theirs on the table (entityId: null), and a refusal is an
entry of its own. AdminSearchResult.audit carries one entry per resource the call decided
about — searched or refused — so a jump box that walked every readable entity leaves a trace.
The admin exposes its own MCP surface, derived from the same resources and gated by the same authz — an agent sees exactly the tools its actor could have clicked.
import { adminMcp, adminMcpTools } from '@ultimat3/admin';
export const mcp = adminMcp({ app: admin, actor: (session) => actorFor(session.token) });
adminMcpTools(admin, ctx); // admin.post.list · admin.post.read · admin.search · admin.action.post.publish
Opt-in AI panes, each declaring the scope it needs (aiPanes({ enable: ['anomaly'] })):
| Pane | Scope |
|---|---|
anomaly | jobs:read, metrics:read |
nl-query | db:read-only |
backlog-forecast | jobs:read, metrics:read |
Panes are off until enabled, and runAiPane refuses (never no-ops) without a runner.
X_ADMIN_ENTITY_UNKNOWN · X_ADMIN_FIELD_UNSUPPORTED · X_ADMIN_POLICY_MISSING · X_ADMIN_PAGE_UNGUARDED · X_ADMIN_PAGE_PATH_INVALID · X_ADMIN_DENIED · X_ADMIN_TOOL_FORBIDDEN · X_ADMIN_INVALID · X_DEV_DASHBOARD_IN_PROD · X_NOT_IMPLEMENTED (an unwired /_x source, carrying the wiring line).
FAQs
Two dashboards: the /_x framework dev panels and the generated, AI-first app admin
The npm package @ultimat3/admin receives a total of 2,598 weekly downloads. As such, @ultimat3/admin popularity was classified as popular.
We found that @ultimat3/admin demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Product
Enterprise security teams can now detect malware, credential theft, suspicious network activity, and risky updates across Microsoft Edge extensions.

Research
/Security News
Socket researchers found 18 Chrome extensions and one Edge extension delivering a wallet drainer, credential theft, and other malicious payloads.

Product
Create ClickUp tasks from Socket alerts, automate ticketing with custom rules, and keep alert and task status synchronized.