Menus API
Purpose and preconditions
scoped.menus manages admin menu configs. Admin pages should prefer configs/items/views/loadApis/actions/responses to create menus, views, APIs, actions, and response fields incrementally. Config-as-code or plugin installation can still use menus.config.* to save a complete MenuConfigInput. subject.menus is the user runtime entrypoint; it projects visible views, action state, view state, and response-field filtering from the same config.
New projects should not maintain low-level nodes, apiBindings, or owner relationships directly. Those are compiled compatibility records for historical v2 manifests, migration tooling, and batch import. Normal admin pages should treat menus.configs/items/views/loadApis/actions/responses as the main API and menus.config.* as the advanced full-config entrypoint.
Before using it:
pc.init()has completed.pc.scope(scope, defaults?)has created a trusted scoped management context; admin requests can bindactorId/requestIdindefaults.- Runtime projection uses
pc.forSubject({ userId, scope }).
What Do You Want to Do?
Signatures
Signature markers: configId locates one menu config; changes: NonEmptyMenuManagementChangeArray is an incremental change set; config: MenuConfigInput is a complete batch config.
MenuManagementExecuteOptions has two shapes:
Do not pass only half of the explicit-preview pair: previewToken without expectedRevisions, or expectedRevisions without previewToken, returns INVALID_ARGUMENT. menus.config.save/remove/applyChanges are the legacy full-config batch entrypoints and still require preview expected/previewToken.
Object methods also include matching previewUpdate/update/previewRemove/remove methods. Their signatures mirror previewCreate/create and add the target menuId/viewId/resource/actionId.
Parameters
Incremental management inputs
MenuResponseSetInput.owner has three forms:
ownerType: 'api' matches a load or API action in the current config that declares the API. When the admin UI can locate the exact page, prefer load or action; errors are easier to diagnose.
MenuConfigInput
MenuConfigMenuInput
MenuViewInput
load.resource: ApiResource must look like api:GET:/api/orders. actions[].resource: ApiResource | UiResource can point to a backend API or frontend UI capability. response?: ResponseProjectionConfigInput can be declared on loads or actions; see Configure APIs and Response Fields API.
Method details: config management
menus.config.preview(config, options?)
- Purpose: Validate a menu config before saving and preview its impact on internal menus, APIs, response fields, and existing role grants.
- Parameters:
configis the completeMenuConfigInput;optionscan includeactorId/reason/detailBudget. - State impact: Read-only; no config is written.
- Raw return:
ImpactPreview<MenuConfigPlan>; inspectexecutable,conflicts,plan.after,expected, andpreviewToken.
menus.config.save(config, options)
- Purpose: Commit a previously previewed menu config.
- Parameters:
configmust match the preview;optionsmust includeexpectedandpreviewToken, and may includeactorId/requestId;idempotencyKeyonly overrides the default idempotency strategy for advanced integrations. - State impact: Writes
_menu_configs, synchronizes internal menu nodes, endpoint contracts, response-field indexes, and affected role sources. - Raw return:
MutationResult<MenuConfigSaveResult>; the config snapshot is indata.config, and internal write summary is indata.manifestOperations.
menus.config.get(configId)
- Purpose: Read the latest snapshot for one config; use this when a management UI needs the complete menu tree.
- Parameters:
configIdis the config ID. - State impact: Read-only.
- Raw return:
VersionedResult<MenuConfigSnapshot>; the complete tree is indata.menusand includes menus, child menus, views, load APIs, actions, and response-field config.data.revisioncan be shown as management UI version information.
menus.config.list(query?)
- Purpose: Page through menu config summaries in the current scope.
- Parameters:
querycan includeconfigId/first/after. - State impact: Read-only.
- Raw return:
PageResult<MenuConfigSummary>; summaries includemenuCount/viewCount/actionCount/responseFieldCount. This lists multiple configs, not menu tree nodes inside one config; read the full tree withmenus.configs.get(configId)ormenus.config.get(configId).
menus.config.previewRemove(configId, options?)
- Purpose: Preview which config assets would be removed when deleting a menu config.
- Parameters:
configIdplus optional preview context. - State impact: Read-only; nothing is deleted.
- Raw return:
ImpactPreview<MenuConfigRemovePlan>; inspectremovedAssets. Deleting the config snapshot does not automatically rewrite role-menu grants; stale historical grants are handled by role-menu read and repair flows.
menus.config.remove(configId, options)
- Purpose: Execute a previously previewed config deletion.
- Parameters:
configIdmust match the preview;optionscarriesexpected/previewToken. - State impact: Deletes the config snapshot and removes internal menu/API assets; does not automatically revoke role-menu grants.
- Raw return:
MutationResult<MenuConfigRemoveResult>.
menus.config.previewChanges(changes, options?)
- Purpose: Preview saving or deleting several configs at once.
- Parameters:
changes: NonEmptyMenuConfigChangeArray; each item is{ operation: 'save', config }or{ operation: 'remove', configId }. - State impact: Read-only.
- Raw return:
ImpactPreview<MenuConfigChangeSetPlan>; use it before plugin installation, module upgrades, or batch imports.
menus.config.applyChanges(changes, options)
- Purpose: Atomically commit a previously previewed batch config change.
- Parameters: Original
changesplus previewexpected/previewToken. - State impact: Saves/deletes configs in a batch and synchronizes all internal menu and API assets.
- Raw return:
MutationResult<MenuConfigChangeSetResult>.
Method details: user runtime
subject.menus.getViewTree(options)
- Purpose: Return the current user’s visible navigation tree for a config.
- Parameters:
options.configIdselects the menu config. - State impact: Read-only; projected from the current user’s effective roles and menu grants.
- Raw return:
SubjectRuntimeResult<readonly ViewTreeNode[]>; actions are not returned as tree nodes.
subject.menus.getActionMap(input)
- Purpose: Return whether each action under a view is visible, enabled, and why.
- Parameters:
input.configIdandinput.viewId. - State impact: Read-only.
- Raw return:
SubjectRuntimeResult<Record<string, ActionPermissionState>>; object keys are action IDs.
subject.menus.getViewState(input)
- Purpose: Decide whether the current user may enter a view.
- Parameters: Pass
{ configId, viewId }or{ path }. - State impact: Read-only.
- Raw return:
SubjectRuntimeResult<ViewPermissionState>;allowedis the permission result andnavigationReachableindicates whether the navigation chain is reachable.
subject.menus.filterResponse(apiResource, payload)
- Purpose: Project an API response according to the current user’s response-field grants.
- Parameters:
apiResourceisapi:METHOD:/path;payloadis the data about to be returned. - State impact: Read-only, but first checks whether the user can
invoketheapiResource. - Raw return:
SubjectRuntimeResult<unknown>; the projected response is indata.
Responses and side effects
Saving config returns a mutation envelope, audit ID, revisions, cache invalidation results, and internal sync summaries. Runtime methods do not write to the database. They return SubjectRuntimeResult<T>, where data is the frontend-facing value and detailBudget is diagnostic metadata.
Failures and limits
Common failures include duplicate or missing config IDs, invalid resource formats, unsafe response-field paths, auto-commit requiring explicit preview confirmation, expired preview tokens, revision conflicts, and capacity limits. load.resource must be an api: resource; response fields can only reference fields declared by the config. Saving config does not automatically grant any role or user.
When incremental management auto mode sees cascade delete, grant-revoking delete, or another impact that cannot be auto-confirmed, it throws MENU_MANAGEMENT_PREVIEW_CONFLICT. Show details.operations/conflicts/warnings to the administrator, call the matching preview*() method, and then execute with expected/previewToken.
Example
Related
See Manage Menus, Configure APIs and Response Fields, and Role Menu Permissions API.