@judo/actions
v0.1.1
Published
> Action handler system and REST API client for JUDO UI Runtime
Readme
@judo/actions
Action handler system and REST API client for JUDO UI Runtime
Purpose
Provides the complete action handler system — a registry of 40 built-in action handler hooks (navigation, CRUD, relation, operation, form, selector, autocomplete, table, and other), a full REST API client (JudoRestApi), transfer serialization, path building, a React context provider for the API, lifecycle composition for action overrides, and dispatcher/handler hooks for wiring actions to UI components.
Architecture Layer
Layer 4 (Features) — depends on model-api; consumed by components and app-shell.
Dependencies
@judo/model-api— model type definitions (Action,ActionDefinition,ClassType,RelationType, etc.)react ^19— React (peer dependency)
Note: While handlers conceptually use services from
core(navigation, data store),feedback(dialogs, notifications), andi18n(translations), these are not package dependencies. Handlers receive these services at runtime through theTypedActionHandlerContextobject passed to each handler invocation.
File Structure
src/
├── index.ts # Root barrel export
├── types.ts # Core action types, interfaces, context shapes
├── api/
│ ├── types.ts # REST API types (HTTP, serialization, validation, query)
│ ├── constants.ts # REST header names and URL suffixes
│ ├── transfer-serializer.ts # Default transfer serializer (strips internal props)
│ ├── judo-rest-api.ts # JudoRestApi class (~870 lines) - full REST client
│ ├── model-converters.ts # Convert model types → REST metadata (internal)
│ └── path-builder.ts # REST URL path construction
├── hooks/
│ ├── use-action-dispatcher.ts # useActionDispatcher hook
│ └── use-action-handler.ts # useActionHandler hook + hasActionHandler
├── provider/
│ └── api-context.tsx # ApiProvider + useApi context
├── registry/
│ └── action-handler-registry.ts # Maps 40 action types → handler hooks
├── lifecycle/
│ └── execute-with-lifecycle.ts # Lifecycle composition engine (before/execute/after/onError)
└── handlers/
├── navigation/ # 4 handlers
├── form/ # 3 handlers
├── selector/ # 5 handlers
├── crud/ # 7 handlers
├── relation/ # 8 handlers
├── table/ # 3 handlers
├── operation/ # 5 handlers
├── autocomplete/ # 3 handlers
└── other/ # 2 handlersExports Summary
Core Action Types
| Export | Kind | Description |
| --------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| ActionType | type | Union of 40 string literals — all action definition type names. |
| DialogCloseResultType | type | "cancelled" \| "created" \| "updated" \| "deleted" \| "selected" \| "submitted" |
| DialogCloseResult | type | Discriminated union for dialog/action outcomes. |
| TypedActionHandlerContext | interface | Runtime context: transfer, selectedRows, closeDialog, navigation, data, registry, validation, notifications, isEager, pageType, isEditMode, isPageAction, createDialog, onDialogClose. |
| ActionHandlerHookWithMeta | interface | Typed handler hook with .actionType metadata property for registration. |
| ActionHandlerFactoryProperties | interface | Custom handler registration properties (by sourceId). |
| BuiltInActionHandlerFactoryProperties | interface | Built-in handler registration properties (by actionType). |
| ACTION_HANDLER_FACTORY | symbol | Service symbol for DI registration (re-exported from model-api). |
Lifecycle
| Export | Kind | Description |
| ---------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------- |
| executeWithLifecycle(defaultHandler, overrides, baseContext, action) | function | Composes lifecycle overrides (before/execute/after/onError) around a default handler. |
REST API Client
| Export | Kind | Description |
| --------------------------- | --------- | ---------------------------------------------------------------------------------------------- |
| JudoRestApi (class) | class | Full REST client (~870 lines) with 25+ methods covering all JUDO REST operations. |
| createJudoRestApi(config) | function | Factory function for JudoRestApi. |
| JudoRestApiConfig | interface | Config: baseUrl, application: Application, optional interceptors, serializer/deserializer. |
Key REST methods:
| Method | REST Endpoint | Description |
| ------------------------------------------------------- | -------------------------------------- | --------------------------------------------- |
| getTemplate(classType) | GET /{classPath}/~template | Fetch template for new transfer |
| refresh(classType, target, qc?) | POST /{classPath}/~get | Refresh stored transfer by signed ID |
| update(classType, target, mask?) | POST /{classPath}/~update | Update existing transfer |
| validateUpdate(classType, target) | POST /{classPath}/~validate | Server-side update validation |
| delete(classType, target) | POST /{classPath}/~delete | Delete transfer |
| listRelation(relation, owner?, qc?, countRecords?) | POST /…/{relation}/~list | List transfers in relation |
| getRelation(relation, owner, qc?) | POST /…/{relation}/~get | Get single-valued relation |
| refreshAccessRelation(relation, qc?) | POST /…/{relation}/~get | Get non-collection access relation (no owner) |
| getRelationRange(relation, owner?, qc?) | POST /…/{relation}/~range | Fetch range for selectors |
| getRelationTemplate(relation) | GET /{targetClassPath}/~template | Get template for relation target |
| createRelation(relation, owner, data, mask?) | POST /…/~create | Create transfer in relation |
| validateCreateRelation(relation, owner, data) | POST /…/~validate | Validate create before persisting |
| setRelation(relation, owner, selected) | POST /…/~update/{relation}/~set | Set single-valued relation |
| unsetRelation(relation, owner) | POST /…/~update/{relation}/~unset | Clear single-valued relation |
| addToRelation(relation, owner, selected) | POST /…/~update/{relation}/~add | Add to collection relation |
| removeFromRelation(relation, owner, selected) | POST /…/~update/{relation}/~remove | Remove from collection relation |
| exportRelation(relation, owner?, qc?) | POST /…/{relation}/~export | Export relation data as blob |
| invokeOperation(classType, op, owner?, input?) | POST /{classPath}/{opName} | Invoke operation |
| validateOperationInput(classType, op, owner?, input?) | POST /{classPath}/{opName}/~validate | Validate operation input |
| getOperationInputTemplate(operation) | GET /{inputClassPath}/~template | Get template for operation input |
| getOperationInputRange(classType, op, owner?, qc?) | POST /{classPath}/{opName}/~range | Fetch range for operation selector |
| getPrincipal() | GET /{actorPath}/~principal | Get current principal |
| getMetadata() | GET /{actorPath}/~meta | Get application metadata |
| uploadFile(attributePath, file) | Two-step upload with token | Upload binary data |
| downloadFile(downloadToken, disposition?) | GET /download?disposition=… | Download binary data |
| findInstance(relation, identifier, mask?) | POST /…/{relation}/~list | Find transfer by business identifier |
Transfer Serialization (internal to api/ module)
These are exported from api/index.ts but not from the package's main entry point:
| Export | Kind | Description |
| ------------------------------- | ------------ | ---------------------------------------------------------------------------------------------- |
| BACKEND_PROPERTIES | constant Set | __identifier, __entityType, __deleteable, __updateable, __version — never send back. |
| FRONTEND_PROPERTIES | constant Set | __tempId, __isNew, __items — client-only, never serialize. |
| INTERNAL_PROPERTIES | constant Set | Union of both sets. |
| isInternalProperty(key) | function | Returns true for any internal prop (keeps __signedIdentifier). |
| stripInternalProperties(data) | function | Creates a new object without internal props. |
| defaultTransferSerializer | constant | Serializer that strips top-level internal properties (handles arrays by mapping). |
Path Building
| Function | Description |
| ------------------------------------------------------------------- | ---------------------------------------------------- |
| getPathForActor(application, path?) | Builds /{modelName}/{actorPath}{path} |
| getRelationPath(relation, application, suffix) | REST path for relation read endpoints |
| getClassPath(classType, application, suffix) | REST path for class endpoints |
| getMutationRelationPath(relation, application, suffix, isAccess?) | Mutation path with /~update/ prefix for non-access |
| getOperationPath(classType, operationName, application, suffix?) | REST path for operation invocations |
API Validation
| Export | Kind | Description |
| ------------------------- | --------- | ----------------------------------------------------------------------------- |
| ValidationError (class) | class | Extends Error with status, feedbackItems, and toFieldErrors() method. |
| FeedbackItem | interface | { code, level, location, message } from server responses. |
React Hooks
| Hook | Description |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| useActionDispatcher(options) | Returns { dispatch, canHandle }. Resolves handlers from registry, builds context, calls handlers. Supports lifecycle overrides via actionOverrides option. |
| useActionHandler(action) | Returns the handler function for a single action. Throws if no handler found. |
| hasActionHandler(action) | Checks whether a handler exists in the registry. |
React Provider
| Export | Kind | Description |
| ------------- | --------- | ----------------------------------------------------- |
| ApiProvider | component | Provides JudoRestApi via React context. |
| useApi() | hook | Consumes the API context; throws if outside provider. |
Built-in Action Handler Hooks (40 total)
Navigation (4)
| Handler | Action Type | Description |
| ----------------------------- | ----------------------------- | --------------------------------------------------------------------- |
| useBackActionHandler | BackActionDefinition | Closes dialog if open, otherwise goBack |
| useOpenPageActionHandler | OpenPageActionDefinition | Navigates to target page with transfer params; forwards eager context |
| useRowOpenPageActionHandler | RowOpenPageActionDefinition | Same as above but for table row clicks |
| useCancelActionHandler | CancelActionDefinition | Closes dialog → or resets transfer (VIEW edit mode) → or goBack |
Form (3)
| Handler | Action Type | Description |
| ---------------------------------------- | ---------------------------------------- | ---------------------------------------------------------------------- |
| useOpenFormActionHandler | OpenFormActionDefinition | Opens form dialog for editing |
| useOpenCreateFormActionHandler | OpenCreateFormActionDefinition | Opens create form dialog; supports eager/lazy modes with onDialogClose |
| useOpenOperationInputFormActionHandler | OpenOperationInputFormActionDefinition | Opens form for operation input parameters |
Selector (5)
| Handler | Action Type | Description |
| -------------------------------------------- | -------------------------------------------- | ------------------------------------------------ |
| useOpenSelectorActionHandler | OpenSelectorActionDefinition | Opens single-selection dialog |
| useOpenAddSelectorActionHandler | OpenAddSelectorActionDefinition | Opens multi-selection dialog for add |
| useOpenSetSelectorActionHandler | OpenSetSelectorActionDefinition | Opens selection dialog for set |
| useOpenOperationInputSelectorActionHandler | OpenOperationInputSelectorActionDefinition | Opens selector for operation input |
| useSelectorRangeActionHandler | SelectorRangeActionDefinition | Fetches range data via REST (or legacy callback) |
CRUD (7)
| Handler | Action Type | Description |
| ----------------------------- | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| useRefreshActionHandler | RefreshActionDefinition | Four modes: access relation list, transfer relation list, selector range, single transfer refresh. Eager mode seeds from parent store. |
| useCreateActionHandler | CreateActionDefinition | Eager (local with validation) or lazy (REST) create with validation flow |
| useUpdateActionHandler | UpdateActionDefinition | Eager (parent update) or lazy (REST update + refresh). Reads transfer from data store via pageTransferId. |
| useDeleteActionHandler | DeleteActionDefinition | REST delete, clears from store, navigates back |
| useBulkDeleteActionHandler | BulkDeleteActionDefinition | Deletes all selected rows via parallel REST calls |
| useRowDeleteActionHandler | RowDeleteActionDefinition | Eager (remove from parent) or lazy (REST delete) single row |
| useGetTemplateActionHandler | GetTemplateActionDefinition | Fetches default values via REST; stores at pageTransferId |
Relation (8)
| Handler | Action Type | Description |
| --------------------------------- | --------------------------------- | ------------------------------------------------------------ |
| useSetActionHandler | SetActionDefinition | Sets single-valued relation; closes dialog with "selected" |
| useUnsetActionHandler | UnsetActionDefinition | Clears single-valued relation |
| useAddActionHandler | AddActionDefinition | Adds to collection relation; closes dialog with "selected" |
| useRemoveActionHandler | RemoveActionDefinition | Eager (remove from parent array) or lazy (REST remove) |
| useBulkRemoveActionHandler | BulkRemoveActionDefinition | Eager or lazy removal of multiple selected transfers |
| useClearActionHandler | ClearActionDefinition | Clears all transfers from relation via unsetRelation |
| useRefreshRelationActionHandler | RefreshRelationActionDefinition | Refreshes relation data (list or get based on cardinality) |
| useFilterRelationActionHandler | FilterRelationActionDefinition | Signals filter intent via onFilterRelation callback |
Table (3)
| Handler | Action Type | Description |
| --------------------------------- | --------------------------------- | ------------------------------------------------------------ |
| useFilterActionHandler | FilterActionDefinition | Signals filter intent via onFilterRequest callback |
| useExportActionHandler | ExportActionDefinition | Exports via REST, triggers browser download |
| useInlineCreateRowActionHandler | InlineCreateRowActionDefinition | Signals inline row creation via onInlineCreateRow callback |
Operation (5)
| Handler | Action Type | Description |
| -------------------------------------------- | -------------------------------------------- | ---------------------------------------------------------------------------- |
| useCallOperationActionHandler | CallOperationActionDefinition | Invokes bound operation via REST; opens output dialog if result + targetPage |
| useBulkCallOperationActionHandler | BulkCallOperationActionDefinition | Invokes operation on each selected row in parallel |
| useInputFormCallOperationActionHandler | InputFormCallOperationActionDefinition | Invokes operation with form input; closes dialog only on success |
| useInputSelectorCallOperationActionHandler | InputSelectorCallOperationActionDefinition | Invokes operation with selected transfer; closes dialog only on success |
| useParameterlessCallOperationActionHandler | ParameterlessCallOperationActionDefinition | Invokes operation with no input |
Autocomplete (3)
| Handler | Action Type | Description |
| ----------------------------------- | ----------------------------------- | ----------------------------------------------- |
| useAutocompleteRangeActionHandler | AutocompleteRangeActionDefinition | Fetches range for autocomplete with search text |
| useAutocompleteSetActionHandler | AutocompleteSetActionDefinition | Sets single-valued relation via autocomplete |
| useAutocompleteAddActionHandler | AutocompleteAddActionDefinition | Adds to collection via autocomplete |
Other (2)
| Handler | Action Type | Description |
| -------------------------- | -------------------------- | ------------------------------------------ |
| usePreFetchActionHandler | PreFetchActionDefinition | Pre-fetches data via onPreFetch callback |
| useCustomActionHandler | CustomActionDefinition | Delegates to onCustomAction callback |
Key Patterns
- Hook factory pattern: Every handler is
(action) => (context) => Promise<void>. React hooks at the outer level; async handler at the inner level. - Discriminated union dispatch: Internal registry maps
@type→ handler hook. 40 entries cover all action types. - Eager vs Lazy: CRUD and relation handlers distinguish between eager (local aggregated, no REST) and lazy (REST-persisted) modes.
- Transfer serialization:
defaultTransferSerializerstrips all__*properties except__signedIdentifier. - Validation error flow:
ValidationErrorauto-parses 400 responses. Handlers set field errors onValidationContext. - Path construction:
getRelationPath/getClassPath/getMutationRelationPathcompose REST URLs from model metadata. - Context casting: Handlers cast
TypedActionHandlerContextto local interfaces for mode-specific properties (eager, selector, API, legacy callbacks). - React context for API:
ApiProvider/useApidecouple handler instantiation from API configuration. - Lifecycle composition:
executeWithLifecyclewraps built-in handlers with before/execute/after/onError hooks for customization. - Legacy callback support: All handlers support both legacy callbacks (on*) and API mode, enabling incremental migration.
