Developer Experience Features
View SourceAshTypescript provides features to improve developer experience: namespace organization, JSDoc generation, and API manifest documentation.
Namespaces
Namespaces organize RPC actions into logical groups, improving discoverability in large codebases.
Configuration Levels
Namespaces can be configured at three levels with cascading precedence:
Domain Level - Default namespace for all resources in a domain:
defmodule MyApp.Domain do
use Ash.Domain, extensions: [AshTypescript.Rpc]
typescript_rpc do
namespace :api # All resources default to "api" namespace
resource MyApp.Todo do
rpc_action :list_todos, :read
end
end
endResource Level - Override for all actions on a specific resource:
typescript_rpc do
namespace :api
resource MyApp.Todo do
namespace :todos # Overrides domain namespace
rpc_action :list_todos, :read
rpc_action :create_todo, :create
end
resource MyApp.User do
# Uses domain namespace "api"
rpc_action :list_users, :read
end
endAction Level - Override for a specific action:
typescript_rpc do
namespace :api
resource MyApp.Todo do
namespace :todos
rpc_action :list_todos, :read # Uses "todos"
rpc_action :admin_list, :read, namespace: :admin # Uses "admin"
end
endPrecedence Order
Action namespace > Resource namespace > Domain namespace > nil
Generated Output
With namespaces enabled, the generated JSDoc includes the namespace:
/**
* List all todos
*
* @ashActionType :read
* @namespace todos
*/
export async function listTodos(...) { ... }JSDoc Generation
Generated TypeScript functions include JSDoc comments that provide IDE discoverability through hover documentation and autocomplete hints.
Default Output
Every generated RPC function includes basic JSDoc:
/**
* List all todos
*
* @ashActionType :read
*/
export async function listTodos(...) { ... }Exposing Ash Metadata
Enable detailed Ash metadata in JSDoc for development:
config :ash_typescript,
add_ash_internals_to_jsdoc: trueThis adds internal references:
/**
* List all todos
*
* @ashActionType :read
* @ashResource MyApp.Todo
* @ashAction :list_todos
* @ashActionDef lib/my_app/resources/todo.ex
* @rpcActionDef lib/my_app/domain.ex
* @namespace todos
*/
export async function listTodos(...) { ... }JSDoc Tags Reference
| Tag | Description | When Shown |
|---|---|---|
@ashActionType | Ash action type (:read, :create, etc.) | Always |
@ashResource | Full Elixir module name | When add_ash_internals_to_jsdoc: true |
@ashAction | Internal Ash action name | When add_ash_internals_to_jsdoc: true |
@ashActionDef | Source file of Ash action definition | When add_ash_internals_to_jsdoc: true |
@rpcActionDef | Source file of RPC action configuration | When add_ash_internals_to_jsdoc: true |
@namespace | Action namespace | When namespace is configured |
@see | Related actions | When see: option is configured |
@deprecated | Deprecation notice | When deprecated: option is configured |
Source Path Prefix (Monorepos)
For monorepo setups where Elixir code is in a subdirectory:
config :ash_typescript,
source_path_prefix: "backend"Output:
/**
* @ashActionDef backend/lib/my_app/resources/todo.ex
* @rpcActionDef backend/lib/my_app/domain.ex
*/Custom Descriptions
Override default descriptions per action:
typescript_rpc do
resource MyApp.Todo do
rpc_action :list_todos, :read,
description: "Fetch all todos for the current user"
end
endWhen add_ash_internals_to_jsdoc: true, the Ash action's description is used as fallback if no RPC description is set.
Related Actions
Link related actions in JSDoc using the see option:
rpc_action :list_todos, :read,
see: [:create_todo, :update_todo]Output:
/**
* @see createTodo
* @see updateTodo
*/Deprecation Notices
Mark actions as deprecated:
rpc_action :old_list, :read,
deprecated: true
rpc_action :legacy_list, :read,
deprecated: "Use listTodos instead"Output:
/**
* @deprecated
*/
/**
* @deprecated Use listTodos instead
*/Manifest Generation
Generate a Markdown manifest documenting all RPC actions for API documentation and developer onboarding.
Configuration
config :ash_typescript,
manifest_file: "./docs/RPC_MANIFEST.md",
add_ash_internals_to_manifest: trueSample Output
# RPC Action Manifest
Generated: 2025-01-15
## Namespace: todos
### Todo
| Function | Action Type | Ash Action | Resource | Validation | Zod Schema | Channel |
|----------|-------------|------------|----------|------------|------------|---------|
| `listTodos` | read | `list` | `MyApp.Todo` | `validateListTodos` | `ListTodosInputSchema` | `listTodosChannel` |
| `createTodo` | create | `create` | `MyApp.Todo` | `validateCreateTodo` | `CreateTodoInputSchema` | `createTodoChannel` |
- **`listTodos`**: Fetch all todos for the current user
- **`createTodo`**: Create a new Todo | **See also:** `listTodos`
**Typed Queries:**
- `todoFields` -> `TodoFieldsResult`: Pre-defined field selectionGrouping Behavior
- With namespaces: Actions grouped by namespace
- Without namespaces: Actions grouped by domain
Controlling Manifest Content
The add_ash_internals_to_manifest config controls whether internal Ash details are shown:
| Setting | Columns Shown |
|---|---|
false | Function, Action Type |
true | Function, Action Type, Ash Action, Resource |
Configuration Reference
All Developer Experience Options
config :ash_typescript,
# JSDoc configuration
add_ash_internals_to_jsdoc: false, # Show Ash module/action details
source_path_prefix: nil, # Prefix for source paths (monorepos)
# Manifest configuration
manifest_file: nil, # Path to generate manifest (nil = disabled)
add_ash_internals_to_manifest: false # Show Ash details in manifestDevelopment vs Production
Development Configuration:
# config/dev.exs
config :ash_typescript,
add_ash_internals_to_jsdoc: true,
add_ash_internals_to_manifest: true,
manifest_file: "./docs/RPC_MANIFEST.md"Production Configuration:
# config/prod.exs
config :ash_typescript,
add_ash_internals_to_jsdoc: false,
add_ash_internals_to_manifest: falseCommon Patterns
Namespace Organization by Feature
typescript_rpc do
resource MyApp.Todo do
namespace :todos
rpc_action :list_todos, :read
rpc_action :create_todo, :create
end
resource MyApp.User do
namespace :users
rpc_action :list_users, :read
rpc_action :get_current_user, :get_current, namespace: :auth
end
resource MyApp.Session do
namespace :auth
rpc_action :login, :create
rpc_action :logout, :destroy
end
endDevelopment-Only Metadata
# config/config.exs
config :ash_typescript,
add_ash_internals_to_jsdoc: Mix.env() == :dev,
add_ash_internals_to_manifest: Mix.env() == :devMonorepo Setup
# backend/config/config.exs
config :ash_typescript,
source_path_prefix: "backend",
output_file: "../frontend/src/generated/ash_rpc.ts"Next Steps
- RPC Action Options - All action configuration options
- Configuration Reference - Complete configuration options
- Lifecycle Hooks - HTTP and channel lifecycle hooks