@judo/actions 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +277 -0
- package/README.md +257 -0
- package/dist/api/constants.d.ts +27 -0
- package/dist/api/constants.d.ts.map +1 -0
- package/dist/api/index.d.ts +9 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/judo-rest-api.d.ts +262 -0
- package/dist/api/judo-rest-api.d.ts.map +1 -0
- package/dist/api/model-converters.d.ts +29 -0
- package/dist/api/model-converters.d.ts.map +1 -0
- package/dist/api/path-builder.d.ts +50 -0
- package/dist/api/path-builder.d.ts.map +1 -0
- package/dist/api/transfer-deserializer.d.ts +46 -0
- package/dist/api/transfer-deserializer.d.ts.map +1 -0
- package/dist/api/transfer-serializer.d.ts +85 -0
- package/dist/api/transfer-serializer.d.ts.map +1 -0
- package/dist/api/types.d.ts +278 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/handlers/autocomplete/autocomplete-handlers.d.ts +20 -0
- package/dist/handlers/autocomplete/autocomplete-handlers.d.ts.map +1 -0
- package/dist/handlers/autocomplete/index.d.ts +2 -0
- package/dist/handlers/autocomplete/index.d.ts.map +1 -0
- package/dist/handlers/crud/crud-handlers.d.ts +76 -0
- package/dist/handlers/crud/crud-handlers.d.ts.map +1 -0
- package/dist/handlers/crud/index.d.ts +2 -0
- package/dist/handlers/crud/index.d.ts.map +1 -0
- package/dist/handlers/form/form-handlers.d.ts +28 -0
- package/dist/handlers/form/form-handlers.d.ts.map +1 -0
- package/dist/handlers/form/index.d.ts +2 -0
- package/dist/handlers/form/index.d.ts.map +1 -0
- package/dist/handlers/index.d.ts +10 -0
- package/dist/handlers/index.d.ts.map +1 -0
- package/dist/handlers/navigation/index.d.ts +2 -0
- package/dist/handlers/navigation/index.d.ts.map +1 -0
- package/dist/handlers/navigation/navigation-handlers.d.ts +23 -0
- package/dist/handlers/navigation/navigation-handlers.d.ts.map +1 -0
- package/dist/handlers/operation/index.d.ts +2 -0
- package/dist/handlers/operation/index.d.ts.map +1 -0
- package/dist/handlers/operation/operation-handlers.d.ts +43 -0
- package/dist/handlers/operation/operation-handlers.d.ts.map +1 -0
- package/dist/handlers/other/index.d.ts +2 -0
- package/dist/handlers/other/index.d.ts.map +1 -0
- package/dist/handlers/other/other-handlers.d.ts +10 -0
- package/dist/handlers/other/other-handlers.d.ts.map +1 -0
- package/dist/handlers/relation/index.d.ts +2 -0
- package/dist/handlers/relation/index.d.ts.map +1 -0
- package/dist/handlers/relation/relation-handlers.d.ts +49 -0
- package/dist/handlers/relation/relation-handlers.d.ts.map +1 -0
- package/dist/handlers/selector/index.d.ts +2 -0
- package/dist/handlers/selector/index.d.ts.map +1 -0
- package/dist/handlers/selector/selector-handlers.d.ts +30 -0
- package/dist/handlers/selector/selector-handlers.d.ts.map +1 -0
- package/dist/handlers/table/index.d.ts +2 -0
- package/dist/handlers/table/index.d.ts.map +1 -0
- package/dist/handlers/table/table-handlers.d.ts +18 -0
- package/dist/handlers/table/table-handlers.d.ts.map +1 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/use-action-dispatcher.d.ts +61 -0
- package/dist/hooks/use-action-dispatcher.d.ts.map +1 -0
- package/dist/hooks/use-action-handler.d.ts +29 -0
- package/dist/hooks/use-action-handler.d.ts.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1427 -0
- package/dist/index.js.map +1 -0
- package/dist/lifecycle/execute-with-lifecycle.d.ts +20 -0
- package/dist/lifecycle/execute-with-lifecycle.d.ts.map +1 -0
- package/dist/lifecycle/index.d.ts +2 -0
- package/dist/lifecycle/index.d.ts.map +1 -0
- package/dist/provider/api-context.d.ts +30 -0
- package/dist/provider/api-context.d.ts.map +1 -0
- package/dist/provider/index.d.ts +2 -0
- package/dist/provider/index.d.ts.map +1 -0
- package/dist/registry/action-handler-registry.d.ts +11 -0
- package/dist/registry/action-handler-registry.d.ts.map +1 -0
- package/dist/registry/index.d.ts +2 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/types-BsQmyhQI.js +14 -0
- package/dist/types-BsQmyhQI.js.map +1 -0
- package/dist/types-CbA9-fcJ.js +2 -0
- package/dist/types.d.ts +260 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["listData: TransferStored[]","queryCustomizer: QueryCustomizer","tableData: TransferData","refreshedEntity: TransferStored","relation: RelationType | undefined","createdEntity: TransferStored","transfer: TransferStored | undefined","updatedEntity: TransferStored","template: TransferStored","value: ApiContextType","lifecycleContext: ActionLifecycleContext","result: unknown","context: ActionHandlerContext","headers: Record<string, string>","init: RequestInit","data: T","body: RangeRequestBody","body: QueryCustomizer","result: Partial<T>","defaultTransferSerializer: TransferSerializer","result: Record<string, unknown>"],"sources":["../../model-api/dist/index.js","../src/handlers/navigation/navigation-handlers.ts","../src/handlers/form/form-handlers.ts","../src/handlers/selector/selector-handlers.ts","../src/handlers/crud/crud-handlers.ts","../src/handlers/relation/relation-handlers.ts","../src/handlers/table/table-handlers.ts","../src/handlers/operation/operation-handlers.ts","../src/handlers/autocomplete/autocomplete-handlers.ts","../src/handlers/other/other-handlers.ts","../src/provider/api-context.tsx","../src/lifecycle/execute-with-lifecycle.ts","../src/registry/action-handler-registry.ts","../src/hooks/use-action-dispatcher.ts","../src/hooks/use-action-handler.ts","../src/api/constants.ts","../src/api/path-builder.ts","../src/api/judo-rest-api.ts","../src/api/transfer-serializer.ts","../src/api/transfer-deserializer.ts"],"sourcesContent":["const Axis = {\n\tHORIZONTAL: \"HORIZONTAL\",\n\tVERTICAL: \"VERTICAL\"\n}, Fit = {\n\tNONE: \"NONE\",\n\tLOOSE: \"LOOSE\",\n\tTIGHT: \"TIGHT\"\n}, Stretch = {\n\tNONE: \"NONE\",\n\tHORIZONTAL: \"HORIZONTAL\",\n\tVERTICAL: \"VERTICAL\",\n\tBOTH: \"BOTH\"\n}, MainAxisAlignment = {\n\tCENTER: \"CENTER\",\n\tEND: \"END\",\n\tSPACEAROUND: \"SPACEAROUND\",\n\tSPACEBETWEEN: \"SPACEBETWEEN\",\n\tSPACEEVENLY: \"SPACEEVENLY\",\n\tSTART: \"START\"\n}, CrossAxisAlignment = {\n\tBASELINE: \"BASELINE\",\n\tCENTER: \"CENTER\",\n\tEND: \"END\",\n\tSTART: \"START\",\n\tSTRETCH: \"STRETCH\"\n}, MainAxisSize = {\n\tMIN: \"MIN\",\n\tMAX: \"MAX\"\n}, Alignment = {\n\tTOP_LEFT: \"TOP_LEFT\",\n\tTOP_CENTER: \"TOP_CENTER\",\n\tTOP_RIGHT: \"TOP_RIGHT\",\n\tCENTER_LEFT: \"CENTER_LEFT\",\n\tCENTER: \"CENTER\",\n\tCENTER_RIGHT: \"CENTER_RIGHT\",\n\tBOTTOM_LEFT: \"BOTTOM_LEFT\",\n\tBOTTOM_CENTER: \"BOTTOM_CENTER\",\n\tBOTTOM_RIGHT: \"BOTTOM_RIGHT\"\n}, DialogSize = {\n\tXS: \"XS\",\n\tSM: \"SM\",\n\tMD: \"MD\",\n\tLG: \"LG\",\n\tXL: \"XL\"\n}, PageContainerType = {\n\tTABLE: \"TABLE\",\n\tFORM: \"FORM\",\n\tVIEW: \"VIEW\"\n}, ButtonStyle = {\n\tCONTAINED: \"contained\",\n\tTEXT: \"text\",\n\tOUTLINED: \"outlined\"\n}, ConfirmationType = {\n\tNONE: \"NONE\",\n\tCONDITIONAL: \"CONDITIONAL\",\n\tMANDATORY: \"MANDATORY\"\n}, Sort = {\n\tNONE: \"NONE\",\n\tASC: \"ASC\",\n\tDESC: \"DESC\"\n}, FilterOperationType = {\n\tEQUAL: \"EQUAL\",\n\tNOT_EQUAL: \"NOT_EQUAL\",\n\tIS_EMPTY: \"IS_EMPTY\",\n\tIS_NOT_EMPTY: \"IS_NOT_EMPTY\",\n\tLESS: \"LESS\",\n\tLESS_OR_EQUAL: \"LESS_OR_EQUAL\",\n\tGREATER: \"GREATER\",\n\tGREATER_OR_EQUAL: \"GREATER_OR_EQUAL\",\n\tLIKE: \"LIKE\"\n}, CheckboxSelection = {\n\tAUTO: \"AUTO\",\n\tENABLED: \"ENABLED\",\n\tDISABLED: \"DISABLED\"\n}, TableRepresentation = {\n\tTABLE: \"TABLE\",\n\tTAG: \"TAG\",\n\tCARD: \"CARD\"\n}, MenuLayout = {\n\tVERTICAL: \"VERTICAL\",\n\tHORIZONTAL: \"HORIZONTAL\"\n}, TabOrientation = {\n\tHORIZONTAL: \"HORIZONTAL\",\n\tVERTICAL: \"VERTICAL\"\n}, DurationUnit = {\n\tNANOSECOND: \"NANOSECOND\",\n\tMICROSECOND: \"MICROSECOND\",\n\tMILLISECOND: \"MILLISECOND\",\n\tSECOND: \"SECOND\",\n\tMINUTE: \"MINUTE\",\n\tHOUR: \"HOUR\",\n\tDAY: \"DAY\",\n\tWEEK: \"WEEK\",\n\tMONTH: \"MONTH\",\n\tYEAR: \"YEAR\"\n}, Placement = {\n\tTOP: \"TOP\",\n\tBOTTOM: \"BOTTOM\",\n\tSTART: \"START\",\n\tEND: \"END\",\n\tDEFAULT: \"DEFAULT\"\n}, TitleFrom = {\n\tLABEL: \"LABEL\",\n\tATTRIBUTE: \"ATTRIBUTE\"\n}, ClaimType = {\n\tUNDEFINED: \"UNDEFINED\",\n\tEMAIL: \"EMAIL\",\n\tUSERNAME: \"USERNAME\"\n}, RelationKind = {\n\tASSOCIATION: \"ASSOCIATION\",\n\tCOMPOSITION: \"COMPOSITION\",\n\tAGGREGATION: \"AGGREGATION\",\n\tSTATIC: \"STATIC\"\n}, MemberType = {\n\tSTORED: \"STORED\",\n\tDERIVED: \"DERIVED\",\n\tMAPPED: \"MAPPED\",\n\tTRANSIENT: \"TRANSIENT\",\n\tACCESS: \"ACCESS\"\n}, RelationBehaviourType = {\n\tLIST: \"LIST\",\n\tCREATE: \"CREATE\",\n\tSET: \"SET\",\n\tUNSET: \"UNSET\",\n\tADD: \"ADD\",\n\tREMOVE: \"REMOVE\",\n\tRANGE: \"RANGE\",\n\tVALIDATE_CREATE: \"VALIDATE_CREATE\",\n\tTEMPLATE: \"TEMPLATE\",\n\tUPDATE: \"UPDATE\",\n\tVALIDATE_UPDATE: \"VALIDATE_UPDATE\",\n\tDELETE: \"DELETE\",\n\tREFRESH: \"REFRESH\",\n\tEXPORT: \"EXPORT\"\n}, ClassBehaviourType = {\n\tREFRESH: \"REFRESH\",\n\tUPDATE: \"UPDATE\",\n\tVALIDATE_UPDATE: \"VALIDATE_UPDATE\",\n\tDELETE: \"DELETE\",\n\tTEMPLATE: \"TEMPLATE\"\n}, OperationTypeEnum = {\n\tMAPPED: \"MAPPED\",\n\tSTATIC: \"STATIC\"\n}, OperationTargetBehaviourType = {\n\tREFRESH: \"REFRESH\",\n\tUPDATE: \"UPDATE\",\n\tDELETE: \"DELETE\",\n\tVALIDATE_INPUT: \"VALIDATE_INPUT\"\n}, MODEL_LOADER_SERVICE = Symbol.for(\"@judo/MODEL_LOADER_SERVICE\"), MODEL_REGISTRY_SERVICE = Symbol.for(\"@judo/MODEL_REGISTRY_SERVICE\"), NAVIGATION_BADGE_SERVICE = Symbol.for(\"@judo/NAVIGATION_BADGE_SERVICE\"), THEME_SERVICE = Symbol.for(\"@judo/THEME_SERVICE\"), ACTION_HANDLER_FACTORY = Symbol.for(\"@judo/ACTION_HANDLER_FACTORY\"), COMPONENT_OVERRIDE = Symbol.for(\"@judo/COMPONENT_OVERRIDE\"), COMPONENT_OVERRIDE_SERVICE = Symbol.for(\"@judo/COMPONENT_OVERRIDE_SERVICE\"), NOTIFICATION_SERVICE = Symbol.for(\"@judo/NOTIFICATION_SERVICE\"), DIALOG_SERVICE = Symbol.for(\"@judo/DIALOG_SERVICE\"), UNSAVED_CHANGES_GUARD = Symbol.for(\"@judo/UNSAVED_CHANGES_GUARD\"), SESSION_TIMEOUT_GUARD = Symbol.for(\"@judo/SESSION_TIMEOUT_GUARD\"), LOADING_SERVICE = Symbol.for(\"@judo/LOADING_SERVICE\"), I18N_SERVICE = Symbol.for(\"@judo/I18N_SERVICE\");\nexport { ACTION_HANDLER_FACTORY, Alignment, Axis, ButtonStyle, COMPONENT_OVERRIDE, COMPONENT_OVERRIDE_SERVICE, CheckboxSelection, ClaimType, ClassBehaviourType, ConfirmationType, CrossAxisAlignment, DIALOG_SERVICE, DialogSize, DurationUnit, FilterOperationType, Fit, I18N_SERVICE, LOADING_SERVICE, MODEL_LOADER_SERVICE, MODEL_REGISTRY_SERVICE, MainAxisAlignment, MainAxisSize, MemberType, MenuLayout, NAVIGATION_BADGE_SERVICE, NOTIFICATION_SERVICE, OperationTargetBehaviourType, OperationTypeEnum, PageContainerType, Placement, RelationBehaviourType, RelationKind, SESSION_TIMEOUT_GUARD, Sort, Stretch, THEME_SERVICE, TabOrientation, TableRepresentation, TitleFrom, UNSAVED_CHANGES_GUARD };\n","import type { Action, ActionHandlerHookWithMeta, TypedActionHandlerContext } from \"../../types\";\n\n/**\n * Handle back navigation - hook factory.\n */\nexport const useBackActionHandler = ((_action: Action) => {\n\t// React hooks can be called here\n\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\t// Close dialog if open\n\t\tif (context.closeDialog) {\n\t\t\tcontext.closeDialog();\n\t\t\treturn;\n\t\t}\n\t\t// Otherwise navigate back\n\t\tcontext.navigation!.goBack();\n\t};\n}) as ActionHandlerHookWithMeta;\nuseBackActionHandler.actionType = \"BackActionDefinition\";\n\n/**\n * Handle page navigation - hook factory.\n */\nexport const useOpenPageActionHandler = ((action: Action) => {\n\t// React hooks can be called here\n\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst targetPage = action.targetPageDefinition;\n\t\tif (!targetPage) {\n\t\t\tthrow new Error(\"No target page defined for OpenPageAction\");\n\t\t}\n\n\t\tif (!context.navigation) {\n\t\t\tthrow new Error(\"Navigation context is undefined\");\n\t\t}\n\n\t\t// For eager tables, forward isEager, parentTransferId, and relationName so the opened\n\t\t// dialog page knows it's operating on an aggregated child (no REST calls on save).\n\t\tconst eagerContext = context as TypedActionHandlerContext & {\n\t\t\tparentTransferId?: string;\n\t\t\trelationName?: string;\n\t\t};\n\n\t\t// Pass transfer data as params\n\t\tcontext.navigation.navigateTo(targetPage, {\n\t\t\ttransfer: context.transfer,\n\t\t\t...(context.isEager && {\n\t\t\t\tisEager: true,\n\t\t\t\tparentTransferId: eagerContext.parentTransferId,\n\t\t\t\trelationName: eagerContext.relationName,\n\t\t\t}),\n\t\t});\n\t};\n}) as ActionHandlerHookWithMeta;\nuseOpenPageActionHandler.actionType = \"OpenPageActionDefinition\";\n\n/**\n * Handle row-based page navigation (from table row) - hook factory.\n */\nexport const useRowOpenPageActionHandler = ((action: Action) => {\n\t// React hooks can be called here\n\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst targetPage = action.targetPageDefinition;\n\t\tif (!targetPage) {\n\t\t\tthrow new Error(\"No target page defined for RowOpenPageAction\");\n\t\t}\n\n\t\tif (!context.navigation) {\n\t\t\tthrow new Error(\"Navigation context is undefined\");\n\t\t}\n\n\t\t// Navigate with row transfer\n\t\t// For eager tables, forward isEager, parentTransferId, and relationName so the opened\n\t\t// dialog page knows it's operating on an aggregated child (no REST calls on save).\n\t\tconst eagerContext = context as TypedActionHandlerContext & {\n\t\t\tparentTransferId?: string;\n\t\t\trelationName?: string;\n\t\t};\n\n\t\tcontext.navigation.navigateTo(targetPage, {\n\t\t\ttransfer: context.transfer,\n\t\t\t...(context.isEager && {\n\t\t\t\tisEager: true,\n\t\t\t\tparentTransferId: eagerContext.parentTransferId,\n\t\t\t\trelationName: eagerContext.relationName,\n\t\t\t}),\n\t\t});\n\t};\n}) as ActionHandlerHookWithMeta;\nuseRowOpenPageActionHandler.actionType = \"RowOpenPageActionDefinition\";\n\n/**\n * Handle cancel action (close dialog or go back) - hook factory.\n *\n * Behavior depends on context:\n * - In a dialog: closes the dialog\n * - On a VIEW page with edits: resets transfer to original data (no navigation)\n * - Otherwise: navigates back\n */\nexport const useCancelActionHandler = ((_action: Action) => {\n\t// React hooks can be called here\n\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\t// Close dialog if open\n\t\tif (context.closeDialog) {\n\t\t\tcontext.closeDialog();\n\t\t\treturn;\n\t\t}\n\n\t\t// On VIEW pages with edits, reset transfer data instead of navigating\n\t\tif (context.pageType === \"VIEW\" && context.isEditMode && context.data && context.transfer?.__identifier) {\n\t\t\tcontext.data.resetTransfer(context.transfer.__identifier);\n\t\t\treturn;\n\t\t}\n\n\t\t// Otherwise navigate back\n\t\tcontext.navigation!.goBack();\n\t};\n}) as ActionHandlerHookWithMeta;\nuseCancelActionHandler.actionType = \"CancelActionDefinition\";\n","import type { OpenOperationInputFormActionDefinition as OpenOpInputFormDef, RelationType } from \"@judo/model-api\";\nimport type { Action, ActionHandlerHookWithMeta, TransferData, TypedActionHandlerContext } from \"../../types\";\n\n/**\n * Handle form open for editing - hook factory.\n */\nexport const useOpenFormActionHandler = ((action: Action) => {\n\t// React hooks can be called here\n\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst targetPage = action.targetPageDefinition;\n\t\tif (!targetPage) {\n\t\t\tthrow new Error(\"No target page defined for OpenFormAction\");\n\t\t}\n\n\t\t// Open form dialog with transfer\n\t\tcontext.navigation!.openDialog(targetPage, {\n\t\t\ttransfer: context.transfer,\n\t\t});\n\t};\n}) as ActionHandlerHookWithMeta;\nuseOpenFormActionHandler.actionType = \"OpenFormActionDefinition\";\n\n/**\n * Handle form open for create - hook factory.\n *\n * Creates a dialog for creating new transfers. The behavior depends on the source component:\n *\n * **Eager Components** (tables/links with isEager=true):\n * - Dialog submission returns data to the caller\n * - Caller (table/link) adds transfer to local __items array\n * - No REST call until parent transfer is saved\n * - onSubmitCreate callback is provided in dialog params\n *\n * **Lazy Components** (default):\n * - Dialog submission calls validateCreateRelation API\n * - If validation passes, calls createRelation API\n * - If validation fails, displays field errors and stays open\n * - After successful create, caller is notified via onDialogClose callback\n */\nexport const useOpenCreateFormActionHandler = ((action: Action) => {\n\t// React hooks can be called here\n\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst targetPage = action.targetPageDefinition;\n\t\tif (!targetPage) {\n\t\t\tthrow new Error(\"No target page defined for OpenCreateFormAction\");\n\t\t}\n\n\t\t// Get relation from action (ownerDataElement is the RelationType for the target)\n\t\tconst relation = action.ownerDataElement as RelationType | undefined;\n\n\t\t// Determine if this is an eager (aggregated) creation\n\t\tconst isEager = context.isEager === true;\n\n\t\t// Get owner transfer for non-access relations\n\t\tconst ownerTransfer = context.transfer;\n\n\t\t// Get parent context for eager tables (where to add the created transfer)\n\t\tconst eagerContext = context as {\n\t\t\tparentTransferId?: string;\n\t\t\trelationName?: string;\n\t\t\tonDialogClose?: (result?: unknown) => void;\n\t\t};\n\n\t\t// Open create form dialog with necessary context\n\t\t// Pass onDialogClose callback so caller can refresh after successful create\n\t\tcontext.navigation!.openDialog(\n\t\t\ttargetPage,\n\t\t\t{\n\t\t\t\tisCreate: true,\n\t\t\t\tisEager,\n\t\t\t\t// Relation context for API calls\n\t\t\t\trelation,\n\t\t\t\townerTransfer,\n\t\t\t\t// For eager mode, provide parent context so CreateActionHandler knows where to add the transfer\n\t\t\t\t...(isEager && {\n\t\t\t\t\tparentTransferId: eagerContext.parentTransferId,\n\t\t\t\t\trelationName: eagerContext.relationName,\n\t\t\t\t\tonSubmitCreate: async (data: TransferData) => {\n\t\t\t\t\t\t// In eager mode, the create action handler will add to local store\n\t\t\t\t\t\t// This callback is handled by the CreateActionHandler\n\t\t\t\t\t\treturn data;\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t\teagerContext.onDialogClose\n\t\t);\n\t};\n}) as ActionHandlerHookWithMeta;\nuseOpenCreateFormActionHandler.actionType = \"OpenCreateFormActionDefinition\";\n\n/**\n * Handle form open for operation input - hook factory.\n */\nexport const useOpenOperationInputFormActionHandler = ((action: Action) => {\n\t// React hooks can be called here\n\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst targetPage = action.targetPageDefinition;\n\t\tif (!targetPage) {\n\t\t\tthrow new Error(\"No target page defined for OpenOperationInputFormAction\");\n\t\t}\n\n\t\t// Cast to access formFor.operation if needed\n\t\tconst formDef = action.actionDefinition as OpenOpInputFormDef;\n\t\tconst formForAction = formDef.formFor as { operation?: unknown } | undefined;\n\n\t\t// Open operation input form dialog\n\t\tcontext.navigation!.openDialog(targetPage, {\n\t\t\ttransfer: context.transfer,\n\t\t\toperation: formForAction?.operation,\n\t\t\tisOperationInput: true,\n\t\t});\n\t};\n}) as ActionHandlerHookWithMeta;\nuseOpenOperationInputFormActionHandler.actionType = \"OpenOperationInputFormActionDefinition\";\n","import type { ClassType, RelationType } from \"@judo/model-api\";\nimport type { JudoRestApi } from \"../../api/judo-rest-api\";\nimport type { TransferStored } from \"../../api/types\";\nimport type { Action, ActionHandlerHookWithMeta, TypedActionHandlerContext } from \"../../types\";\n\n// Interface for API context\ninterface ApiContext {\n\tapi?: JudoRestApi;\n}\n\n// Interface for relation context\ninterface RelationContext {\n\townerTransfer?: TransferStored;\n\townerClassType?: ClassType;\n\trelation?: RelationType;\n}\n\n// Legacy callback interfaces for backward compatibility\ninterface LegacyCallbacks {\n\tonRangeRequest?: (classType: ClassType) => void;\n}\n\n/**\n * Get RelationType from context.\n */\nfunction getRelation(relationContext: RelationContext, action: Action): RelationType | null {\n\tif (relationContext.relation) {\n\t\treturn relationContext.relation;\n\t}\n\t// Check if action has a relation in ownerDataElement\n\tconst ownerDataElement = action.ownerDataElement;\n\tif (ownerDataElement && ownerDataElement[\"@type\"] === \"RelationType\") {\n\t\treturn ownerDataElement as RelationType;\n\t}\n\treturn null;\n}\n\n/**\n * Handle selector open for single selection - hook factory.\n * Navigation action - no REST call.\n */\nexport const useOpenSelectorActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst targetPage = action.targetPageDefinition;\n\t\tif (!targetPage) {\n\t\t\tthrow new Error(\"No target page defined for OpenSelectorAction\");\n\t\t}\n\n\t\tconst selectorContext = context as { onDialogClose?: (result?: unknown) => void };\n\n\t\tcontext.navigation?.openDialog(\n\t\t\ttargetPage,\n\t\t\t{\n\t\t\t\townerTransfer: context.transfer,\n\t\t\t\tisSelector: true,\n\t\t\t\tselectionMode: \"single\",\n\t\t\t},\n\t\t\tselectorContext.onDialogClose\n\t\t);\n\t};\n}) as ActionHandlerHookWithMeta;\nuseOpenSelectorActionHandler.actionType = \"OpenSelectorActionDefinition\";\n\n/**\n * Handle selector open for add operation (multi-select) - hook factory.\n * Navigation action - no REST call.\n */\nexport const useOpenAddSelectorActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst targetPage = action.targetPageDefinition;\n\t\tif (!targetPage) {\n\t\t\tthrow new Error(\"No target page defined for OpenAddSelectorAction\");\n\t\t}\n\n\t\tconst selectorContext = context as { onDialogClose?: (result?: unknown) => void };\n\n\t\tcontext.navigation?.openDialog(\n\t\t\ttargetPage,\n\t\t\t{\n\t\t\t\townerTransfer: context.transfer,\n\t\t\t\tisSelector: true,\n\t\t\t\tselectionMode: \"multiple\",\n\t\t\t\toperation: \"add\",\n\t\t\t},\n\t\t\tselectorContext.onDialogClose\n\t\t);\n\t};\n}) as ActionHandlerHookWithMeta;\nuseOpenAddSelectorActionHandler.actionType = \"OpenAddSelectorActionDefinition\";\n\n/**\n * Handle selector open for set operation (single-select) - hook factory.\n * Navigation action - no REST call.\n */\nexport const useOpenSetSelectorActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst targetPage = action.targetPageDefinition;\n\t\tif (!targetPage) {\n\t\t\tthrow new Error(\"No target page defined for OpenSetSelectorAction\");\n\t\t}\n\n\t\tconst selectorContext = context as { onDialogClose?: (result?: unknown) => void };\n\n\t\tcontext.navigation?.openDialog(\n\t\t\ttargetPage,\n\t\t\t{\n\t\t\t\townerTransfer: context.transfer,\n\t\t\t\tisSelector: true,\n\t\t\t\tselectionMode: \"single\",\n\t\t\t\toperation: \"set\",\n\t\t\t},\n\t\t\tselectorContext.onDialogClose\n\t\t);\n\t};\n}) as ActionHandlerHookWithMeta;\nuseOpenSetSelectorActionHandler.actionType = \"OpenSetSelectorActionDefinition\";\n\n/**\n * Handle selector open for operation input - hook factory.\n * Navigation action - no REST call.\n * Registers an onClose callback to refresh the caller page after a\n * successful operation, but only when the caller is not in edit mode.\n */\nexport const useOpenOperationInputSelectorActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst targetPage = action.targetPageDefinition;\n\t\tif (!targetPage) {\n\t\t\tthrow new Error(\"No target page defined for OpenOperationInputSelectorAction\");\n\t\t}\n\n\t\t// Capture caller page's refreshPage callback and edit mode state.\n\t\t// These come from ViewContainerRenderer's additionalContext.\n\t\tconst { refreshPage, isEditMode } = context as unknown as {\n\t\t\trefreshPage?: () => void;\n\t\t\tisEditMode?: boolean;\n\t\t};\n\n\t\tcontext.navigation?.openDialog(\n\t\t\ttargetPage,\n\t\t\t{\n\t\t\t\townerTransfer: context.transfer,\n\t\t\t\tisSelector: true,\n\t\t\t\tisOperationInput: true,\n\t\t\t},\n\t\t\t(result) => {\n\t\t\t\t// Refresh caller page after successful operation, but only if not in edit mode\n\t\t\t\tif (result?.type === \"submitted\" && !isEditMode) {\n\t\t\t\t\trefreshPage?.();\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t};\n}) as ActionHandlerHookWithMeta;\nuseOpenOperationInputSelectorActionHandler.actionType = \"OpenOperationInputSelectorActionDefinition\";\n\n/**\n * Handle selector range query (fetch data for selector) - hook factory.\n * Fetches range data for selector table via REST API.\n * Supports both legacy callback mode and API mode.\n */\nexport const useSelectorRangeActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst targetType = action.actionDefinition.targetType as ClassType | undefined;\n\t\tif (!targetType) {\n\t\t\tthrow new Error(\"No target type defined for SelectorRangeAction\");\n\t\t}\n\n\t\tconst selectorContext = context as unknown as ApiContext &\n\t\t\tRelationContext &\n\t\t\tLegacyCallbacks & {\n\t\t\t\tqueryCustomizer?: Record<string, unknown>;\n\t\t\t\tonRangeResult?: (results: TransferStored[]) => void;\n\t\t\t};\n\n\t\tconst { onRangeRequest, api, onRangeResult } = selectorContext;\n\n\t\t// Use legacy callback if provided\n\t\tif (onRangeRequest) {\n\t\t\tonRangeRequest(targetType);\n\t\t\treturn;\n\t\t}\n\n\t\t// Use API if available\n\t\tif (api) {\n\t\t\tconst relation = getRelation(selectorContext, action);\n\t\t\tif (!relation) {\n\t\t\t\tthrow new Error(\"Cannot determine relation for selector range\");\n\t\t\t}\n\n\t\t\tconst response = await api.getRelationRange(\n\t\t\t\trelation,\n\t\t\t\tselectorContext.ownerTransfer,\n\t\t\t\tselectorContext.queryCustomizer\n\t\t\t);\n\n\t\t\t// Signal results to selector component\n\t\t\tonRangeResult?.(response.data);\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseSelectorRangeActionHandler.actionType = \"SelectorRangeActionDefinition\";\n","import {\n\ttype ClassType,\n\ttype DataElement,\n\ttype OperationType,\n\ttype PageDefinition,\n\tRelationBehaviourType,\n\ttype RelationType,\n} from \"@judo/model-api\";\nimport type { JudoRestApi } from \"../../api/judo-rest-api\";\nimport type { TransferData, TransferStored, QueryCustomizer, ValidationError } from \"../../api/types\";\nimport type { Action, ActionHandlerHookWithMeta, TypedActionHandlerContext } from \"../../types\";\n\n// Interface for API context - will be provided via context\ninterface ApiContext {\n\tapi?: JudoRestApi;\n}\n\n// Extended context for page-level operations (e.g., table list)\ninterface PageContext {\n\t/** Transfer ID for the page (used to store table data) */\n\tpageTransferId?: string;\n\t/** Number of rows per page for table pagination */\n\trowsPerPage?: number;\n\t/** Whether this is a selector page (Add/Set selector) */\n\tisSelector?: boolean;\n\t/** Owner transfer for selector range queries */\n\townerTransfer?: TransferStored;\n\t/** Whether this is an operation input selector page */\n\tisOperationInput?: boolean;\n}\n\n// Legacy callback interfaces for backward compatibility\ninterface LegacyCallbacks {\n\tonRefresh?: (transferId: string, classType: ClassType) => Promise<TransferStored>;\n\tonListRelation?: (relation: RelationType) => Promise<TransferStored[]>;\n\tonCreate?: (transfer: TransferStored, classType: ClassType) => Promise<TransferStored>;\n\tonUpdate?: (transfer: TransferStored, classType: ClassType) => Promise<TransferStored>;\n\tonDelete?: (transferId: string, classType: ClassType) => Promise<void>;\n\tonBulkDelete?: (transferIds: string[], classType: ClassType) => Promise<void>;\n\tonRowDelete?: (transferId: string, classType: ClassType) => Promise<void>;\n\tonGetTemplate?: (classType: ClassType) => Promise<TransferStored>;\n\t/** Custom validation callback for create operations */\n\tonValidateCreate?: (\n\t\ttransfer: TransferStored,\n\t\trelation: RelationType,\n\t\townerTransfer?: TransferStored\n\t) => Promise<Record<string, string> | null>;\n}\n\n// Relation context for create operations - supports both new format (relation property) and legacy format (flat)\ninterface CreateRelationContext {\n\townerTransfer?: TransferStored;\n\trelationMetadata?:\n\t\t| RelationType\n\t\t| {\n\t\t\t\trelation?: RelationType;\n\t\t\t\tisAccess?: boolean;\n\t\t\t\t// Legacy format: relation props directly in relationMetadata\n\t\t\t\tname?: string;\n\t\t\t\towner?: unknown;\n\t\t\t\ttarget?: unknown;\n\t\t };\n}\n\n/**\n * Helper to check if an error is a ValidationError.\n */\nfunction isValidationError(error: unknown): error is ValidationError {\n\treturn error !== null && typeof error === \"object\" && (error as { name?: string }).name === \"ValidationError\";\n}\n\n/**\n * Resolve the target ClassType for an action.\n *\n * Resolution order:\n * 1. actionDefinition.targetType (explicitly set in the model)\n * 2. Page's dataElement (via eContainer traversal from Action to PageDefinition)\n * - If dataElement is a ClassType, use it directly\n * - If dataElement is a RelationType, follow its .target to get the ClassType\n *\n * UpdateActionDefinition, DeleteActionDefinition, and RefreshActionDefinition\n * typically don't have targetType set in the XMI model. The target type is\n * derived from the page's dataElement instead.\n */\nfunction resolveTargetClassType(action: Action): ClassType | undefined {\n\t// 1. Try explicit targetType on the action definition\n\tconst explicit = action.actionDefinition?.targetType as ClassType | undefined;\n\tif (explicit) {\n\t\treturn explicit;\n\t}\n\n\t// 2. Fall back to the page's dataElement\n\t// Action.eContainer is PageDefinition (since PageDefinition.actions contains Action[])\n\tconst page = (action as unknown as { eContainer?: unknown }).eContainer as PageDefinition | undefined;\n\tif (!page?.dataElement) {\n\t\treturn undefined;\n\t}\n\n\tconst dataElement = page.dataElement as DataElement & { target?: ClassType; \"@type\"?: string };\n\n\t// If the dataElement is a ClassType, use it directly\n\tif (dataElement[\"@type\"] === \"ClassType\" || dataElement[\"@type\"] === \"data:ClassType\") {\n\t\treturn dataElement as unknown as ClassType;\n\t}\n\n\t// If the dataElement is a RelationType, follow .target to get the ClassType\n\tif (dataElement[\"@type\"] === \"RelationType\" || dataElement[\"@type\"] === \"data:RelationType\") {\n\t\treturn dataElement.target;\n\t}\n\n\t// OperationParameterType (output/input) has no @type from the parser but inherits\n\t// .target from ReferenceType, just like RelationType. Follow .target if present.\n\tif (dataElement.target) {\n\t\treturn dataElement.target;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Check if the action is for listing an ACCESS relation (top-level table load).\n * This is the case when:\n * - ownerDataElement is a RelationType\n * - The relation is an access relation (isAccess=true)\n * - No transfer exists in context (initial table load)\n */\nfunction isAccessRelationListAction(action: Action, transfer?: TransferStored): boolean {\n\tconst ownerDataElement = action.ownerDataElement;\n\tif (!ownerDataElement || ownerDataElement[\"@type\"] !== \"RelationType\") {\n\t\treturn false;\n\t}\n\n\tconst relation = ownerDataElement as RelationType;\n\t// isAccess can be boolean true or string \"true\" depending on model parsing\n\t// Use String() comparison to handle both cases\n\tconst isAccessRelation = String(relation.isAccess) === \"true\";\n\tconst hasNoEntity = !transfer?.__identifier && !transfer?.__signedIdentifier;\n\n\treturn isAccessRelation && hasNoEntity;\n}\n\n/**\n * Check if the action is for listing an transfer's relation (relation table page).\n * This is the case when:\n * - ownerDataElement is a RelationType\n * - The relation is NOT an access relation (isAccess=false)\n * - Transfer exists with a signedIdentifier (the owner transfer)\n */\nfunction isEntityRelationListAction(action: Action, transfer?: TransferStored): boolean {\n\tconst ownerDataElement = action.ownerDataElement;\n\n\t// Parser maps \"data:RelationType\" -> \"RelationType\"\n\tif (!ownerDataElement || ownerDataElement[\"@type\"] !== \"RelationType\") {\n\t\treturn false;\n\t}\n\n\tconst relation = ownerDataElement as RelationType;\n\tconst isAccessRelation = String(relation.isAccess) === \"true\";\n\tconst hasEntity = !!transfer?.__signedIdentifier;\n\n\treturn !isAccessRelation && hasEntity;\n}\n\n/**\n * Handle data refresh - hook factory.\n * Calls REST API to refresh transfer data OR list relation data.\n *\n * Three modes:\n * 1. Access relation list: When action.ownerDataElement is an access RelationType (top-level table)\n * 2. Transfer relation list: When action.ownerDataElement is a non-access RelationType with owner transfer\n * 3. Single transfer refresh: When context.transfer has an identifier\n *\n * Supports both legacy callback mode and API mode.\n */\nexport const useRefreshActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst transfer = context.transfer as TransferStored | undefined;\n\t\tconst callbackContext = context as unknown as LegacyCallbacks & ApiContext & PageContext;\n\t\tconst { api, pageTransferId, rowsPerPage } = callbackContext;\n\n\t\t// Extract queryCustomizer and countRecords from action if provided (e.g., from table sorting/filtering)\n\t\tconst actionQueryCustomizer = (action as Action & { queryCustomizer?: QueryCustomizer }).queryCustomizer;\n\t\tconst countRecords = (action as Action & { countRecords?: boolean }).countRecords;\n\n\t\t// Check if this is an ACCESS relation list operation (top-level table load)\n\t\tif (isAccessRelationListAction(action, transfer)) {\n\t\t\tconst relation = action.ownerDataElement as RelationType;\n\n\t\t\t// Use provided pageTransferId or generate one from action\n\t\t\tconst tableEntityId = pageTransferId ?? `table::${action[\"xmi:id\"]}`;\n\t\t\tcontext.data?.setTransferLoading(tableEntityId, true);\n\n\t\t\ttry {\n\t\t\t\tconst { onListRelation } = callbackContext;\n\n\t\t\t\tlet listData: TransferStored[];\n\n\t\t\t\tif (onListRelation) {\n\t\t\t\t\t// Use legacy callback if provided\n\t\t\t\t\tlistData = await onListRelation(relation);\n\t\t\t\t} else if (api) {\n\t\t\t\t\t// Use API to list the access relation\n\t\t\t\t\t// Build query customizer: merge action's queryCustomizer with pagination\n\t\t\t\t\tconst queryCustomizer: QueryCustomizer = {\n\t\t\t\t\t\t_seek: { limit: rowsPerPage ?? 10 },\n\t\t\t\t\t\t...actionQueryCustomizer,\n\t\t\t\t\t};\n\t\t\t\t\tconst response = await api.listRelation(relation, undefined, queryCustomizer, countRecords);\n\t\t\t\t\tlistData = response.data;\n\n\t\t\t\t\t// Extract total count from response header if present\n\t\t\t\t\tconst totalCountHeader = response.headers.get(\"x-judo-count\");\n\t\t\t\t\tconst totalCount = totalCountHeader ? Number.parseInt(totalCountHeader, 10) : undefined;\n\n\t\t\t\t\t// Store the list data - wrap in object with __items key for table consumption\n\t\t\t\t\t// Include total count if available\n\t\t\t\t\tconst tableData: TransferData = { __items: listData };\n\t\t\t\t\tif (totalCount !== undefined && !Number.isNaN(totalCount)) {\n\t\t\t\t\t\ttableData.__totalCount = totalCount;\n\t\t\t\t\t}\n\t\t\t\t\tcontext.data?.setTransferData(tableEntityId, tableData);\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(\"API not available in context\");\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tcontext.data?.setTransferError(tableEntityId, error as Error);\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tcontext.data?.setTransferLoading(tableEntityId, false);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if this is an ENTITY relation list operation (relation table page)\n\t\tif (isEntityRelationListAction(action, transfer)) {\n\t\t\tconst relation = action.ownerDataElement as RelationType;\n\n\t\t\t// Use provided pageTransferId or generate one from action\n\t\t\tconst tableEntityId = pageTransferId ?? `table::${action[\"xmi:id\"]}`;\n\t\t\tcontext.data?.setTransferLoading(tableEntityId, true);\n\n\t\t\ttry {\n\t\t\t\tif (api) {\n\t\t\t\t\t// For transfer relations, pass the relation directly to the API\n\t\t\t\t\t// Build query customizer: merge action's queryCustomizer with pagination\n\t\t\t\t\tconst queryCustomizer: QueryCustomizer = {\n\t\t\t\t\t\t_seek: { limit: rowsPerPage ?? 10 },\n\t\t\t\t\t\t...actionQueryCustomizer,\n\t\t\t\t\t};\n\t\t\t\t\t// Pass the owner transfer to include X-Judo-SignedIdentifier header\n\t\t\t\t\tconst response = await api.listRelation(relation, transfer, queryCustomizer, countRecords);\n\t\t\t\t\tconst listData = response.data;\n\n\t\t\t\t\t// Extract total count from response header if present\n\t\t\t\t\tconst totalCountHeader = response.headers.get(\"x-judo-count\");\n\t\t\t\t\tconst totalCount = totalCountHeader ? Number.parseInt(totalCountHeader, 10) : undefined;\n\n\t\t\t\t\t// Store the list data - wrap in object with __items key for table consumption\n\t\t\t\t\tconst tableData: TransferData = { __items: listData };\n\t\t\t\t\tif (totalCount !== undefined && !Number.isNaN(totalCount)) {\n\t\t\t\t\t\ttableData.__totalCount = totalCount;\n\t\t\t\t\t}\n\t\t\t\t\tcontext.data?.setTransferData(tableEntityId, tableData);\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(\"API not available in context\");\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tcontext.data?.setTransferError(tableEntityId, error as Error);\n\t\t\t\tthrow error;\n\t\t\t} finally {\n\t\t\t\tcontext.data?.setTransferLoading(tableEntityId, false);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if this is a SELECTOR range query (Add/Set selector dialog)\n\t\t// Selector pages need to fetch the available range of items via getRelationRange()\n\t\tif (callbackContext.isSelector) {\n\t\t\tconst ownerDataElement = action.ownerDataElement;\n\n\t\t\t// Relation selector: ownerDataElement is a RelationType → getRelationRange\n\t\t\tif (ownerDataElement && ownerDataElement[\"@type\"] === \"RelationType\") {\n\t\t\t\tconst relation = ownerDataElement as RelationType;\n\t\t\t\tconst tableEntityId = pageTransferId ?? `table::${action[\"xmi:id\"]}`;\n\t\t\t\tcontext.data?.setTransferLoading(tableEntityId, true);\n\n\t\t\t\ttry {\n\t\t\t\t\tif (api) {\n\t\t\t\t\t\tconst queryCustomizer: QueryCustomizer = {\n\t\t\t\t\t\t\t_seek: { limit: rowsPerPage ?? 10 },\n\t\t\t\t\t\t\t...actionQueryCustomizer,\n\t\t\t\t\t\t};\n\t\t\t\t\t\t// Range calls only need __signedIdentifier on the owner - strip __identifier\n\t\t\t\t\t\tconst rangeOwner = callbackContext.ownerTransfer?.__signedIdentifier\n\t\t\t\t\t\t\t? ({\n\t\t\t\t\t\t\t\t\t__signedIdentifier: callbackContext.ownerTransfer.__signedIdentifier,\n\t\t\t\t\t\t\t\t} as TransferStored)\n\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\t\tconst response = await api.getRelationRange(relation, rangeOwner, queryCustomizer, countRecords);\n\t\t\t\t\t\tconst rangeData = response.data;\n\n\t\t\t\t\t\t// Extract total count from response header if present\n\t\t\t\t\t\tconst totalCountHeader = response.headers.get(\"x-judo-count\");\n\t\t\t\t\t\tconst totalCount = totalCountHeader ? Number.parseInt(totalCountHeader, 10) : undefined;\n\n\t\t\t\t\t\tconst tableData: TransferData = { __items: rangeData };\n\t\t\t\t\t\tif (totalCount !== undefined && !Number.isNaN(totalCount)) {\n\t\t\t\t\t\t\ttableData.__totalCount = totalCount;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontext.data?.setTransferData(tableEntityId, tableData);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow new Error(\"API not available in context\");\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tcontext.data?.setTransferError(tableEntityId, error as Error);\n\t\t\t\t\tthrow error;\n\t\t\t\t} finally {\n\t\t\t\t\tcontext.data?.setTransferLoading(tableEntityId, false);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Operation input selector: ownerDataElement is an OperationType → getOperationInputRange\n\t\t\t// Derive the owning ClassType from the OperationType's eContainer (set during model resolution)\n\t\t\tif (ownerDataElement && ownerDataElement[\"@type\"] === \"OperationType\") {\n\t\t\t\tconst operationType = ownerDataElement as OperationType;\n\t\t\t\tconst ownerClassType = (ownerDataElement as unknown as { eContainer?: ClassType }).eContainer;\n\n\t\t\t\tif (!ownerClassType) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"Cannot determine owning ClassType for operation input selector (OperationType.eContainer is missing)\"\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst tableEntityId = pageTransferId ?? `table::${action[\"xmi:id\"]}`;\n\t\t\t\tcontext.data?.setTransferLoading(tableEntityId, true);\n\n\t\t\t\ttry {\n\t\t\t\t\tif (api) {\n\t\t\t\t\t\tconst queryCustomizer: QueryCustomizer = {\n\t\t\t\t\t\t\t_seek: { limit: rowsPerPage ?? 10 },\n\t\t\t\t\t\t\t...actionQueryCustomizer,\n\t\t\t\t\t\t};\n\t\t\t\t\t\t// Range calls only need __signedIdentifier on the owner - strip __identifier\n\t\t\t\t\t\tconst rangeOwner = callbackContext.ownerTransfer?.__signedIdentifier\n\t\t\t\t\t\t\t? ({\n\t\t\t\t\t\t\t\t\t__signedIdentifier: callbackContext.ownerTransfer.__signedIdentifier,\n\t\t\t\t\t\t\t\t} as TransferStored)\n\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\t\tconst response = await api.getOperationInputRange(\n\t\t\t\t\t\t\townerClassType,\n\t\t\t\t\t\t\toperationType,\n\t\t\t\t\t\t\trangeOwner,\n\t\t\t\t\t\t\tqueryCustomizer,\n\t\t\t\t\t\t\tcountRecords\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst rangeData = response.data;\n\n\t\t\t\t\t\t// Extract total count from response header if present\n\t\t\t\t\t\tconst totalCountHeader = response.headers.get(\"x-judo-count\");\n\t\t\t\t\t\tconst totalCount = totalCountHeader ? Number.parseInt(totalCountHeader, 10) : undefined;\n\n\t\t\t\t\t\tconst tableData: TransferData = { __items: rangeData };\n\t\t\t\t\t\tif (totalCount !== undefined && !Number.isNaN(totalCount)) {\n\t\t\t\t\t\t\ttableData.__totalCount = totalCount;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontext.data?.setTransferData(tableEntityId, tableData);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow new Error(\"API not available in context\");\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tcontext.data?.setTransferError(tableEntityId, error as Error);\n\t\t\t\t\tthrow error;\n\t\t\t\t} finally {\n\t\t\t\t\tcontext.data?.setTransferLoading(tableEntityId, false);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Single transfer refresh mode\n\t\tconst transferId = transfer?.__identifier ?? transfer?.__signedIdentifier;\n\t\tif (!transferId) {\n\t\t\t// No transfer to refresh and not a list operation - nothing to do\n\t\t\treturn;\n\t\t}\n\n\t\t// Eager mode: seed the data store from the parent transfer's relation array.\n\t\t// No REST call — the authoritative data lives locally in the parent and was\n\t\t// placed there by CreateActionHandler / UpdateActionHandler.\n\t\t// context.transfer only carries identifiers (ViewContainerRenderer strips\n\t\t// fields), so we must look up the full transfer from the parent's store.\n\t\tif (context.isEager) {\n\t\t\tconst eagerCtx = context as TypedActionHandlerContext & {\n\t\t\t\tparentTransferId?: string;\n\t\t\t\trelationName?: string;\n\t\t\t};\n\n\t\t\tif (eagerCtx.parentTransferId && eagerCtx.relationName && context.data) {\n\t\t\t\tconst parentData = context.data.getSnapshot((state: unknown) => {\n\t\t\t\t\tconst typedState = state as { transfers: Map<string, { data: TransferData | null }> };\n\t\t\t\t\treturn typedState.transfers.get(eagerCtx.parentTransferId!)?.data;\n\t\t\t\t}) as TransferData | undefined;\n\n\t\t\t\tif (parentData) {\n\t\t\t\t\tconst relationValue = (parentData as Record<string, unknown>)[eagerCtx.relationName!];\n\n\t\t\t\t\tif (Array.isArray(relationValue)) {\n\t\t\t\t\t\t// Collection relation (Table) — find matching transfer in array\n\t\t\t\t\t\tconst fullEntity = relationValue.find((item: TransferStored) => {\n\t\t\t\t\t\t\tif (transfer!.__signedIdentifier && item.__signedIdentifier === transfer!.__signedIdentifier) return true;\n\t\t\t\t\t\t\tif (transfer!.__identifier && item.__identifier === transfer!.__identifier) return true;\n\t\t\t\t\t\t\tconst itemTempId = (item as { __tempId?: string }).__tempId;\n\t\t\t\t\t\t\tconst entityTempId = (transfer as { __tempId?: string })?.__tempId;\n\t\t\t\t\t\t\tif (itemTempId && entityTempId && itemTempId === entityTempId) return true;\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tif (fullEntity) {\n\t\t\t\t\t\t\tcontext.data.setTransferData(transferId, fullEntity);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (relationValue && typeof relationValue === \"object\") {\n\t\t\t\t\t\t// Single relation (Link) — use the value directly\n\t\t\t\t\t\tcontext.data.setTransferData(transferId, relationValue as TransferStored);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Fallback: store whatever we have (at least the identifiers)\n\t\t\tcontext.data?.setTransferData(transferId, transfer!);\n\t\t\treturn;\n\t\t}\n\n\t\tcontext.data?.setTransferLoading(transferId, true);\n\n\t\ttry {\n\t\t\tconst targetType = resolveTargetClassType(action);\n\t\t\tif (!targetType) {\n\t\t\t\tthrow new Error(\"No target type for refresh\");\n\t\t\t}\n\n\t\t\tconst { onRefresh } = callbackContext;\n\n\t\t\tlet refreshedEntity: TransferStored;\n\n\t\t\t// Use legacy callback if provided\n\t\t\tif (onRefresh) {\n\t\t\t\trefreshedEntity = await onRefresh(transferId, targetType);\n\t\t\t} else if (api) {\n\t\t\t\t// Use API if available\n\t\t\t\t// Use actionQueryCustomizer if provided (e.g., for custom masks)\n\t\t\t\tconst response = await api.refresh(targetType, transfer!, actionQueryCustomizer);\n\t\t\t\trefreshedEntity = response.data;\n\t\t\t} else {\n\t\t\t\tthrow new Error(\"API not available in context\");\n\t\t\t}\n\n\t\t\tcontext.data?.setTransferData(transferId, refreshedEntity);\n\t\t} catch (error) {\n\t\t\tcontext.data?.setTransferError(transferId, error as Error);\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tcontext.data?.setTransferLoading(transferId, false);\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseRefreshActionHandler.actionType = \"RefreshActionDefinition\";\n\n// Local storage context for eager table operations\ninterface LocalStorageContext {\n\t/** Parent transfer ID for storing new items in local table data */\n\tparentTransferId?: string;\n}\n\n/**\n * Handle transfer create - hook factory.\n *\n * Create behavior varies based on context:\n *\n * 1. **Eager components** (isEager=true):\n * - Validates data via validateCreateRelation API if relation is provided\n * - If validation fails, sets field errors via validation context (dialog stays open)\n * - If validation passes, returns data to caller (no REST create call)\n * - Caller (table/link) adds transfer to local __items array\n * - Transfer is persisted when parent is saved\n *\n * 2. **Lazy components** (isEager=false, default):\n * - Validates data via validateCreateRelation API\n * - If validation fails, sets field errors via validation context (dialog stays open)\n * - If validation passes, creates transfer via createRelation API\n * - BLOCKED if on a FORM page (forms save all data together)\n * - BLOCKED if on a VIEW page that is in edit mode (unsaved changes)\n *\n * After creation, optionally navigates to view page based on autoOpenAfterCreate.\n *\n * Supports both legacy callback mode and API mode.\n */\nexport const useCreateActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\t// Get transfer from context or from data store using pageTransferId\n\t\t// For create forms, transfer data is stored in data store by GetTemplateActionHandler\n\t\tlet transfer = context.transfer as TransferStored | undefined;\n\t\tif (!transfer && context.data) {\n\t\t\tconst pageTransferId = (context as { pageTransferId?: string }).pageTransferId;\n\t\t\tif (pageTransferId) {\n\t\t\t\ttransfer = context.data.getSnapshot((state: unknown) => {\n\t\t\t\t\tconst typedState = state as { transfers: Map<string, { data: TransferData | null }> };\n\t\t\t\t\treturn typedState.transfers.get(pageTransferId)?.data;\n\t\t\t\t}) as TransferStored | undefined;\n\t\t\t}\n\t\t}\n\n\t\tif (!transfer) {\n\t\t\tthrow new Error(\"No transfer data to create\");\n\t\t}\n\n\t\tconst { isEager, pageType, isEditMode, isPageAction, validation, createDialog } = context;\n\n\t\t// For lazy components, check if create is allowed\n\t\t// Page-level actions (dialog footer buttons) are always allowed\n\t\tif (!isEager && !isPageAction) {\n\t\t\tif (pageType === \"FORM\") {\n\t\t\t\tthrow new Error(\"Create operation is not allowed on FORM pages. Save the form first.\");\n\t\t\t}\n\t\t\tif (pageType === \"VIEW\" && isEditMode) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"Create operation is not allowed while the view has unsaved changes. Save or cancel changes first.\"\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Use pageTransferId if available (for dialogs), otherwise transfer.__identifier or \"new\"\n\t\tconst pageTransferId = (context as { pageTransferId?: string }).pageTransferId;\n\t\tconst transferId = pageTransferId ?? transfer.__identifier ?? \"new\";\n\t\tcontext.data?.setTransferLoading(transferId, true);\n\n\t\t// Clear any previous validation errors before attempting create\n\t\tvalidation?.clearErrors();\n\n\t\ttry {\n\t\t\tconst callbackContext = context as unknown as LegacyCallbacks &\n\t\t\t\tApiContext &\n\t\t\t\tCreateRelationContext &\n\t\t\t\tLocalStorageContext;\n\t\t\tconst { onCreate, onValidateCreate, api, relationMetadata, ownerTransfer, parentTransferId } = callbackContext;\n\n\t\t\t// Get relation from createDialog context or relationMetadata or action.ownerDataElement\n\t\t\t// Support both new format (relationMetadata.relation) and legacy format (relationMetadata as RelationType)\n\t\t\t// Priority: action.ownerDataElement is most authoritative (model-defined for this specific action),\n\t\t\t// then createDialog context (set by the dialog opener), then relationMetadata (legacy).\n\t\t\tlet relation: RelationType | undefined;\n\t\t\t// 1. Prefer action.ownerDataElement - it's the model-defined relation for this specific create action\n\t\t\t// (e.g., the form page's Create action points to \"stars\", not the parent \"galaxies\" access relation)\n\t\t\tif (action.ownerDataElement?.[\"@type\"] === \"RelationType\") {\n\t\t\t\trelation = action.ownerDataElement as RelationType;\n\t\t\t}\n\t\t\t// 2. Fall back to createDialog context (set by the dialog opener)\n\t\t\tif (!relation) {\n\t\t\t\trelation = createDialog?.relation as RelationType | undefined;\n\t\t\t}\n\t\t\t// 3. Fall back to relationMetadata\n\t\t\tif (!relation && relationMetadata) {\n\t\t\t\t// Check if relationMetadata has nested relation property\n\t\t\t\tif (\"relation\" in relationMetadata && relationMetadata.relation) {\n\t\t\t\t\trelation = relationMetadata.relation as RelationType;\n\t\t\t\t} else if (\"name\" in relationMetadata && relationMetadata.name) {\n\t\t\t\t\t// Legacy format: relationMetadata is the relation itself\n\t\t\t\t\trelation = relationMetadata as unknown as RelationType;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Get targetType from relation.target or actionDefinition.targetType\n\t\t\tconst targetType =\n\t\t\t\t(relation?.target as ClassType | undefined) ?? (action.actionDefinition.targetType as ClassType | undefined);\n\t\t\tif (!targetType) {\n\t\t\t\tthrow new Error(\"No target type for create\");\n\t\t\t}\n\t\t\tconst dialogOwnerEntity = (createDialog?.ownerTransfer as TransferStored) ?? ownerTransfer;\n\n\t\t\tlet createdEntity: TransferStored;\n\n\t\t\t// --- VALIDATION STEP (EAGER MODE ONLY) ---\n\t\t\t// For eager mode, validate before adding to local store since there's no immediate server call\n\t\t\t// For lazy mode, skip separate validation - the createRelation API will validate during create\n\t\t\t// and return validation errors which we'll handle there\n\t\t\tconst hasValidateCreateBehaviour = relation?.behaviours?.includes(RelationBehaviourType.VALIDATE_CREATE);\n\n\t\t\tif (isEager && hasValidateCreateBehaviour && api) {\n\t\t\t\ttry {\n\t\t\t\t\t// Call validateCreateRelation API (eager mode only)\n\t\t\t\t\tawait api.validateCreateRelation(relation!, dialogOwnerEntity, transfer);\n\t\t\t\t} catch (validationError) {\n\t\t\t\t\t// Check if it's a validation error with field-level feedback\n\t\t\t\t\tif (isValidationError(validationError)) {\n\t\t\t\t\t\t// Set field errors in validation context so form can display them\n\t\t\t\t\t\tconst fieldErrors = validationError.toFieldErrors();\n\t\t\t\t\t\tif (validation && Object.keys(fieldErrors).length > 0) {\n\t\t\t\t\t\t\tvalidation.setErrors(fieldErrors);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Re-throw to stop the create process (dialog stays open)\n\t\t\t\t\t\tthrow validationError;\n\t\t\t\t\t}\n\t\t\t\t\t// For other errors, re-throw as-is\n\t\t\t\t\tthrow validationError;\n\t\t\t\t}\n\t\t\t} else if (isEager && hasValidateCreateBehaviour && onValidateCreate && relation) {\n\t\t\t\t// Use legacy validation callback if provided (only if relation supports validation)\n\t\t\t\tconst fieldErrors = await onValidateCreate(transfer, relation, dialogOwnerEntity);\n\t\t\t\tif (fieldErrors && Object.keys(fieldErrors).length > 0) {\n\t\t\t\t\tvalidation?.setErrors(fieldErrors);\n\t\t\t\t\tthrow new Error(\"Validation failed\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// --- CREATE STEP ---\n\t\t\t// Eager mode: add to local store only, no REST call\n\t\t\tif (isEager) {\n\t\t\t\t// Generate a temporary client-side ID for tracking the new transfer\n\t\t\t\t// Note: __identifier is backend-assigned, so we use __tempId for frontend-created transfers\n\t\t\t\tconst tempId = `temp::${Date.now()}::${Math.random().toString(36).substring(2, 9)}`;\n\t\t\t\tcreatedEntity = {\n\t\t\t\t\t...transfer,\n\t\t\t\t\t__tempId: tempId, // Frontend-only temporary ID (not __identifier which is backend-assigned)\n\t\t\t\t\t__isNew: true, // Mark as new/unsaved\n\t\t\t\t};\n\n\t\t\t\t// Get parent context from createDialog (preferred) or legacy context\n\t\t\t\tconst eagerParentEntityId = createDialog?.parentTransferId ?? parentTransferId;\n\t\t\t\tconst eagerRelationName = createDialog?.relationName;\n\n\t\t\t\t// If we have a parent transfer ID, add the created transfer to the parent's data\n\t\t\t\tif (eagerParentEntityId && context.data) {\n\t\t\t\t\tconst parentData = context.data.getSnapshot((state: unknown) => {\n\t\t\t\t\t\tconst typedState = state as { transfers: Map<string, { data: TransferData | null }> };\n\t\t\t\t\t\treturn typedState.transfers.get(eagerParentEntityId)?.data;\n\t\t\t\t\t}) as TransferData | undefined;\n\n\t\t\t\t\tif (eagerRelationName) {\n\t\t\t\t\t\t// Eager component embedded in VIEW page: add to parent transfer's relation property\n\t\t\t\t\t\tconst currentValue = (parentData as any)?.[eagerRelationName];\n\n\t\t\t\t\t\tif (Array.isArray(currentValue)) {\n\t\t\t\t\t\t\t// Collection relation (Table) — append to array\n\t\t\t\t\t\t\tcontext.data.updateTransferFields(eagerParentEntityId, {\n\t\t\t\t\t\t\t\t[eagerRelationName]: [...currentValue, createdEntity],\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Single relation (Link) — set the field directly\n\t\t\t\t\t\t\tcontext.data.updateTransferFields(eagerParentEntityId, {\n\t\t\t\t\t\t\t\t[eagerRelationName]: createdEntity,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Fallback: add to __items array (legacy behavior for standalone tables)\n\t\t\t\t\t\tconst currentItems = (parentData?.__items as TransferStored[] | undefined) ?? [];\n\t\t\t\t\t\tconst newItems = [...currentItems, createdEntity];\n\n\t\t\t\t\t\t// Use updateTransferFields to preserve dirty tracking and trigger edit mode\n\t\t\t\t\t\tcontext.data.updateTransferFields(eagerParentEntityId, {\n\t\t\t\t\t\t\t__items: newItems,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// For eager mode with onSubmitCreate callback, invoke it\n\t\t\t\tif (createDialog?.onSubmitCreate) {\n\t\t\t\t\tawait createDialog.onSubmitCreate(createdEntity);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Lazy mode: create via REST API\n\t\t\t\tif (onCreate) {\n\t\t\t\t\t// Use legacy callback if provided\n\t\t\t\t\tcreatedEntity = await onCreate(transfer, targetType);\n\t\t\t\t} else if (api && relation) {\n\t\t\t\t\t// Use API if available - pass the relation directly\n\t\t\t\t\t// Handle validation errors from create endpoint\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst result = await api.createRelation(relation, dialogOwnerEntity, transfer);\n\t\t\t\t\t\tcreatedEntity = result.data;\n\t\t\t\t\t} catch (createError) {\n\t\t\t\t\t\t// Check if it's a validation error with field-level feedback\n\t\t\t\t\t\tif (isValidationError(createError)) {\n\t\t\t\t\t\t\t// Set field errors in validation context so form can display them\n\t\t\t\t\t\t\tconst fieldErrors = createError.toFieldErrors();\n\t\t\t\t\t\t\tif (validation && Object.keys(fieldErrors).length > 0) {\n\t\t\t\t\t\t\t\tvalidation.setErrors(fieldErrors);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Re-throw to stop the create process (dialog stays open)\n\t\t\t\t\t\t\tthrow createError;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// For other errors, re-throw as-is\n\t\t\t\t\t\tthrow createError;\n\t\t\t\t\t}\n\t\t\t\t} else if (!onCreate && !api) {\n\t\t\t\t\t// No callback or API - nothing to do\n\t\t\t\t\treturn;\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"Create requires relation context. Provide relation in createDialog or relationMetadata in additionalContext.\"\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Close dialog with success result so caller can refresh\n\t\t\tif (context.closeDialog) {\n\t\t\t\tcontext.closeDialog({ type: \"created\", isEager: isEager ?? false });\n\t\t\t}\n\n\t\t\t// Navigate to view page with created transfer if autoOpenAfterCreate is enabled\n\t\t\t// CreateActionDefinition has autoOpenAfterCreate attribute (defaults to true based on meta-model)\n\t\t\tconst actionDef = action.actionDefinition as { autoOpenAfterCreate?: boolean };\n\t\t\tconst shouldAutoOpen = actionDef.autoOpenAfterCreate !== false; // Default true\n\n\t\t\tconst viewPage = action.targetPageDefinition;\n\t\t\tif (shouldAutoOpen && viewPage && context.navigation && !isEager) {\n\t\t\t\t// Only navigate for lazy (persisted) transfers\n\t\t\t\tcontext.navigation.replacePage(viewPage, { transfer: createdEntity });\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// For validation errors, don't set transfer error (let validation context handle it)\n\t\t\tif (!isValidationError(error)) {\n\t\t\t\tcontext.data?.setTransferError(transferId, error as Error);\n\t\t\t}\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tcontext.data?.setTransferLoading(transferId, false);\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseCreateActionHandler.actionType = \"CreateActionDefinition\";\n\n/**\n * Handle transfer update - hook factory.\n * Updates an existing transfer via REST API.\n * Supports both legacy callback mode and API mode.\n *\n * In eager mode (aggregated child transfers opened from an eager table):\n * - Skips REST API calls entirely\n * - Updates the parent transfer's relation array with the modified transfer data\n * - The actual persistence happens when the aggregate root (parent) is saved\n */\nexport const useUpdateActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst contextEntity = context.transfer as TransferStored | undefined;\n\t\tconst rawEntityId = contextEntity?.__identifier ?? contextEntity?.__signedIdentifier;\n\t\tif (!rawEntityId) {\n\t\t\tthrow new Error(\"No transfer to update (missing identifier)\");\n\t\t}\n\n\t\t// For dialog dispatchers, context.transfer carries the original transfer identifiers\n\t\t// (e.g., from params.transfer), while the actual data is stored under the\n\t\t// dialog-specific pageTransferId (e.g., \"dialog::transfer::abc123\").\n\t\t// Prefer pageTransferId for data store lookups when available.\n\t\tconst pageTransferId = (context as { pageTransferId?: string }).pageTransferId;\n\t\tconst transferId = pageTransferId ?? rawEntityId;\n\n\t\t// Read the full transfer from the data store.\n\t\t// context.transfer may only contain identifiers (__identifier / __signedIdentifier)\n\t\t// because the dispatcher receives a minimal stub. The actual user-modified fields\n\t\t// are in the data store, populated by the initial refresh and updated by bindings.\n\t\tlet transfer: TransferStored | undefined;\n\t\tif (context.data) {\n\t\t\ttransfer = context.data.getSnapshot((state: unknown) => {\n\t\t\t\tconst typedState = state as { transfers: Map<string, { data: TransferData | null }> };\n\t\t\t\treturn typedState.transfers.get(transferId)?.data;\n\t\t\t}) as TransferStored | undefined;\n\t\t}\n\n\t\t// Fall back to context.transfer if data store lookup fails (e.g., legacy callback mode)\n\t\tif (!transfer) {\n\t\t\ttransfer = contextEntity;\n\t\t}\n\n\t\tcontext.data?.setTransferLoading(transferId, true);\n\n\t\ttry {\n\t\t\tconst { isEager } = context;\n\t\t\tconst eagerContext = context as TypedActionHandlerContext & {\n\t\t\t\tparentTransferId?: string;\n\t\t\t\trelationName?: string;\n\t\t\t};\n\n\t\t\t// Eager mode: update parent transfer's local relation data, no REST call\n\t\t\tif (isEager) {\n\t\t\t\tconst { parentTransferId, relationName } = eagerContext;\n\n\t\t\t\tif (parentTransferId && relationName && context.data) {\n\t\t\t\t\tconst parentData = context.data.getSnapshot((state: unknown) => {\n\t\t\t\t\t\tconst typedState = state as { transfers: Map<string, { data: TransferData | null }> };\n\t\t\t\t\t\treturn typedState.transfers.get(parentTransferId)?.data;\n\t\t\t\t\t}) as TransferData | undefined;\n\n\t\t\t\t\tif (parentData) {\n\t\t\t\t\t\tconst currentValue = (parentData as Record<string, unknown>)[relationName];\n\n\t\t\t\t\t\tif (Array.isArray(currentValue)) {\n\t\t\t\t\t\t\t// Collection relation (Table) — find and replace matching transfer in array\n\t\t\t\t\t\t\tconst updatedItems = currentValue.map((item: TransferStored) => {\n\t\t\t\t\t\t\t\tconst itemTempId = (item as { __tempId?: string }).__tempId;\n\t\t\t\t\t\t\t\tconst entityTempId = (transfer as { __tempId?: string }).__tempId;\n\n\t\t\t\t\t\t\t\tif (itemTempId && entityTempId && itemTempId === entityTempId) {\n\t\t\t\t\t\t\t\t\treturn { ...transfer! };\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (item.__identifier && item.__identifier === transfer!.__identifier) {\n\t\t\t\t\t\t\t\t\treturn { ...transfer! };\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (item.__signedIdentifier && item.__signedIdentifier === transfer!.__signedIdentifier) {\n\t\t\t\t\t\t\t\t\treturn { ...transfer! };\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn item;\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tcontext.data.updateTransferFields(parentTransferId, {\n\t\t\t\t\t\t\t\t[relationName]: updatedItems,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Single relation (Link) — replace the entire field value\n\t\t\t\t\t\t\tcontext.data.updateTransferFields(parentTransferId, {\n\t\t\t\t\t\t\t\t[relationName]: { ...transfer! },\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Reset the transfer in the data store (marks it as \"saved\" within the dialog)\n\t\t\t\tcontext.data?.setTransferData(transferId, transfer!);\n\n\t\t\t\t// Navigate back (close the dialog) after successful eager update\n\t\t\t\tcontext.navigation?.goBack();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Lazy mode: update via REST API\n\t\t\tconst targetType = resolveTargetClassType(action);\n\t\t\tif (!targetType) {\n\t\t\t\tthrow new Error(\"No target type for update\");\n\t\t\t}\n\n\t\t\tconst callbackContext = context as unknown as LegacyCallbacks & ApiContext;\n\t\t\tconst { onUpdate, api } = callbackContext;\n\n\t\t\tlet updatedEntity: TransferStored;\n\n\t\t\t// Use legacy callback if provided\n\t\t\tif (onUpdate) {\n\t\t\t\tupdatedEntity = await onUpdate(transfer!, targetType);\n\t\t\t} else if (api) {\n\t\t\t\t// Use API if available - pass the ClassType directly\n\t\t\t\tconst response = await api.update(targetType, transfer!);\n\t\t\t\tupdatedEntity = response.data;\n\n\t\t\t\t// Refresh after successful update to get the complete transfer state\n\t\t\t\t// (the update response may only contain the masked subset of fields)\n\t\t\t\tconst refreshResponse = await api.refresh(targetType, updatedEntity);\n\t\t\t\tupdatedEntity = refreshResponse.data;\n\t\t\t} else {\n\t\t\t\t// No callback or API - nothing to do\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcontext.data?.setTransferData(transferId, updatedEntity);\n\t\t} catch (error) {\n\t\t\tcontext.data?.setTransferError(transferId, error as Error);\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tcontext.data?.setTransferLoading(transferId, false);\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseUpdateActionHandler.actionType = \"UpdateActionDefinition\";\n\n/**\n * Handle transfer delete - hook factory.\n * Deletes an transfer via REST API.\n * Supports both legacy callback mode and API mode.\n */\nexport const useDeleteActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst transfer = context.transfer as TransferStored | undefined;\n\t\tconst transferId = transfer?.__identifier ?? transfer?.__signedIdentifier;\n\t\tif (!transferId) {\n\t\t\tthrow new Error(\"No transfer to delete (missing identifier)\");\n\t\t}\n\n\t\tcontext.data?.setTransferLoading(transferId, true);\n\n\t\ttry {\n\t\t\tconst targetType = resolveTargetClassType(action);\n\t\t\tif (!targetType) {\n\t\t\t\tthrow new Error(\"No target type for delete\");\n\t\t\t}\n\n\t\t\tconst callbackContext = context as unknown as LegacyCallbacks & ApiContext;\n\t\t\tconst { onDelete, api } = callbackContext;\n\n\t\t\t// Use legacy callback if provided\n\t\t\tif (onDelete) {\n\t\t\t\tawait onDelete(transferId, targetType);\n\t\t\t} else if (api) {\n\t\t\t\t// Use API if available - pass the ClassType directly\n\t\t\t\tawait api.delete(targetType, transfer!);\n\t\t\t} else {\n\t\t\t\t// No callback or API - nothing to do\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Clear transfer from store and navigate back\n\t\t\tcontext.data?.clearTransfer(transferId);\n\t\t\tcontext.navigation?.goBack();\n\t\t} catch (error) {\n\t\t\tcontext.data?.setTransferError(transferId, error as Error);\n\t\t\tthrow error;\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseDeleteActionHandler.actionType = \"DeleteActionDefinition\";\n\n/**\n * Handle bulk delete - hook factory.\n * Deletes multiple selected transfers via REST API.\n * Supports both legacy callback mode and API mode.\n */\nexport const useBulkDeleteActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst selectedRows = context.selectedRows as TransferStored[] | undefined;\n\t\tif (!selectedRows || selectedRows.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst targetType = action.actionDefinition.targetType as ClassType | undefined;\n\t\tif (!targetType) {\n\t\t\tthrow new Error(\"No target type for bulk delete\");\n\t\t}\n\n\t\tconst callbackContext = context as unknown as LegacyCallbacks & ApiContext;\n\t\tconst { onBulkDelete, api } = callbackContext;\n\n\t\tconst transferIds = selectedRows\n\t\t\t.map((row) => row.__identifier ?? row.__signedIdentifier)\n\t\t\t.filter(Boolean) as string[];\n\n\t\t// Use legacy callback if provided\n\t\tif (onBulkDelete) {\n\t\t\tawait onBulkDelete(transferIds, targetType);\n\t\t} else if (api) {\n\t\t\t// Use API if available - pass the ClassType directly\n\t\t\t// Delete all selected transfers\n\t\t\tconst deletePromises = selectedRows\n\t\t\t\t.filter((row) => row.__signedIdentifier)\n\t\t\t\t.map((row) => api.delete(targetType, row));\n\n\t\t\tawait Promise.all(deletePromises);\n\t\t} else {\n\t\t\t// No callback or API - nothing to do\n\t\t\treturn;\n\t\t}\n\n\t\t// Clear deleted transfers from store\n\t\tfor (const rowId of transferIds) {\n\t\t\tcontext.data?.clearTransfer(rowId);\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseBulkDeleteActionHandler.actionType = \"BulkDeleteActionDefinition\";\n\n/**\n * Handle single row delete from table - hook factory.\n * Deletes a single transfer from a table row via REST API.\n * Supports both legacy callback mode and API mode.\n */\nexport const useRowDeleteActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst transfer = context.transfer as TransferStored | undefined;\n\t\tconst transferId = transfer?.__identifier ?? transfer?.__signedIdentifier;\n\n\t\tconst eagerContext = context as unknown as {\n\t\t\tisEager?: boolean;\n\t\t\tparentTransferId?: string;\n\t\t\trelationName?: string;\n\t\t};\n\t\tconst { isEager, parentTransferId, relationName } = eagerContext;\n\n\t\t// Eager mode: remove transfer from parent's local data store\n\t\tif (isEager && parentTransferId && context.data) {\n\t\t\tconst parentData = context.data.getSnapshot((state: unknown) => {\n\t\t\t\tconst typedState = state as { transfers: Map<string, { data: TransferData | null }> };\n\t\t\t\treturn typedState.transfers.get(parentTransferId)?.data;\n\t\t\t}) as TransferData | undefined;\n\n\t\t\tif (relationName) {\n\t\t\t\tconst currentValue = (parentData as any)?.[relationName];\n\n\t\t\t\tif (Array.isArray(currentValue)) {\n\t\t\t\t\t// Collection relation (Table) — remove matching transfer from array\n\t\t\t\t\tconst newItems = currentValue.filter((item: TransferStored) => {\n\t\t\t\t\t\tconst itemId = item.__identifier ?? item.__signedIdentifier ?? (item as any).__tempId;\n\t\t\t\t\t\tconst targetId = transferId ?? (transfer as any)?.__tempId;\n\t\t\t\t\t\treturn itemId !== targetId;\n\t\t\t\t\t});\n\n\t\t\t\t\tcontext.data.updateTransferFields(parentTransferId, {\n\t\t\t\t\t\t[relationName]: newItems,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\t// Single relation (Link) — set the field to null\n\t\t\t\t\tcontext.data.updateTransferFields(parentTransferId, {\n\t\t\t\t\t\t[relationName]: null,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Fallback: remove from __items array\n\t\t\t\tconst currentItems = (parentData?.__items as TransferStored[] | undefined) ?? [];\n\t\t\t\tconst newItems = currentItems.filter((item) => {\n\t\t\t\t\tconst itemId = item.__identifier ?? item.__signedIdentifier ?? (item as any).__tempId;\n\t\t\t\t\tconst targetId = transferId ?? (transfer as any)?.__tempId;\n\t\t\t\t\treturn itemId !== targetId;\n\t\t\t\t});\n\n\t\t\t\t// Use updateTransferFields to preserve dirty tracking and trigger edit mode\n\t\t\t\tcontext.data.updateTransferFields(parentTransferId, {\n\t\t\t\t\t__items: newItems,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Lazy mode: delete via REST API\n\t\tif (!transferId) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst targetType = action.actionDefinition.targetType as ClassType | undefined;\n\t\tif (!targetType) {\n\t\t\tthrow new Error(\"No target type for row delete\");\n\t\t}\n\n\t\tconst callbackContext = context as unknown as LegacyCallbacks & ApiContext;\n\t\tconst { onRowDelete, api } = callbackContext;\n\n\t\t// Use legacy callback if provided\n\t\tif (onRowDelete) {\n\t\t\tawait onRowDelete(transferId, targetType);\n\t\t} else if (api) {\n\t\t\t// Use API if available - pass the ClassType directly\n\t\t\tawait api.delete(targetType, transfer!);\n\t\t} else {\n\t\t\t// No callback or API - nothing to do\n\t\t\treturn;\n\t\t}\n\n\t\t// Clear transfer from store\n\t\tcontext.data?.clearTransfer(transferId);\n\t};\n}) as ActionHandlerHookWithMeta;\nuseRowDeleteActionHandler.actionType = \"RowDeleteActionDefinition\";\n\n/**\n * Get template for new transfer - hook factory.\n * Fetches default values for a new transfer via REST API.\n * Supports both legacy callback mode and API mode.\n *\n * Stores template data using pageTransferId from context (if available) or \"new\" as fallback.\n * This ensures the form bindings can find the data at the correct transfer ID.\n */\nexport const useGetTemplateActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst targetType = action.actionDefinition.targetType as ClassType | undefined;\n\t\tif (!targetType) {\n\t\t\tthrow new Error(\"No target type for get template\");\n\t\t}\n\n\t\tconst callbackContext = context as unknown as LegacyCallbacks & ApiContext;\n\t\tconst { onGetTemplate, api } = callbackContext;\n\n\t\tlet template: TransferStored;\n\n\t\t// Use legacy callback if provided\n\t\tif (onGetTemplate) {\n\t\t\ttemplate = await onGetTemplate(targetType);\n\t\t} else if (api) {\n\t\t\t// Use API if available - pass the ClassType directly\n\t\t\tconst response = await api.getTemplate(targetType);\n\t\t\ttemplate = response.data;\n\t\t} else {\n\t\t\tthrow new Error(\"API not available in context\");\n\t\t}\n\n\t\t// Store template using pageTransferId from context, fallback to \"new\"\n\t\t// This ensures form bindings can find the data at the correct transfer ID\n\t\tconst transferId = (context as { pageTransferId?: string }).pageTransferId ?? \"new\";\n\t\tcontext.data?.setTransferData(transferId, template);\n\t};\n}) as ActionHandlerHookWithMeta;\nuseGetTemplateActionHandler.actionType = \"GetTemplateActionDefinition\";\n","import type { ClassType, RelationType } from \"@judo/model-api\";\nimport type { JudoRestApi } from \"../../api/judo-rest-api\";\nimport type { TransferData, TransferStored } from \"../../api/types\";\nimport type { Action, ActionHandlerHookWithMeta, TypedActionHandlerContext } from \"../../types\";\n\n// Interface for API context - will be provided via context\ninterface ApiContext {\n\tapi?: JudoRestApi;\n}\n\n// Interface for relation context - provides relation metadata\ninterface RelationContext {\n\townerTransfer?: TransferStored;\n\townerClassType?: ClassType;\n\trelation?: RelationType;\n}\n\n// Legacy callback interfaces for backward compatibility\ninterface LegacyCallbacks {\n\tonSet?: (ownerId: string, relationName: string, targetId: string) => Promise<void>;\n\tonUnset?: (transferId: string, relationName: string) => Promise<void>;\n\tonAdd?: (ownerId: string, relationName: string, targetIds: string[]) => Promise<void>;\n\tonRemove?: (ownerId: string, relationName: string, targetIds: string[]) => Promise<void>;\n\tonBulkRemove?: (ownerId: string, relationName: string, targetIds: string[]) => Promise<void>;\n\tonClear?: (transferId: string, relationName: string) => Promise<void>;\n\tonRefreshRelation?: (transferId: string, relationName: string) => Promise<void>;\n\tonFilterRelation?: (relationName: string) => void;\n}\n\n/**\n * Get RelationType from context.\n */\nfunction getRelation(relationContext: RelationContext, action: Action): RelationType | null {\n\tif (relationContext.relation) {\n\t\treturn relationContext.relation;\n\t}\n\t// Check if action has a relation in ownerDataElement\n\tconst ownerDataElement = action.ownerDataElement;\n\tif (ownerDataElement && ownerDataElement[\"@type\"] === \"RelationType\") {\n\t\treturn ownerDataElement as RelationType;\n\t}\n\treturn null;\n}\n\n/**\n * Handle relation set (single) - hook factory.\n * Sets a single-valued relation to a selected transfer.\n * Supports both legacy callback mode and API mode.\n */\nexport const useSetActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst relationContext = context as unknown as RelationContext & {\n\t\t\tselectedEntity?: TransferStored;\n\t\t} & ApiContext &\n\t\t\tLegacyCallbacks;\n\n\t\tconst { ownerTransfer, selectedEntity, api, onSet } = relationContext;\n\n\t\tif (!ownerTransfer || !selectedEntity) {\n\t\t\tthrow new Error(\"Missing owner or selected transfer for set\");\n\t\t}\n\n\t\tconst ownerId = ownerTransfer.__identifier ?? ownerTransfer.__signedIdentifier;\n\t\tconst selectedId = selectedEntity.__identifier ?? selectedEntity.__signedIdentifier;\n\n\t\tif (!ownerId || !selectedId) {\n\t\t\tthrow new Error(\"Missing transfer identifiers for set\");\n\t\t}\n\n\t\tconst relationName = action.actionDefinition.name ?? \"\";\n\n\t\t// Use legacy callback if provided\n\t\tif (onSet) {\n\t\t\tawait onSet(ownerId, relationName, selectedId);\n\t\t} else if (api) {\n\t\t\t// Use API if available\n\t\t\tconst relation = getRelation(relationContext, action);\n\t\t\tif (!relation) {\n\t\t\t\tthrow new Error(\"Cannot determine relation for set action\");\n\t\t\t}\n\t\t\tawait api.setRelation(relation, ownerTransfer, selectedEntity);\n\t\t}\n\n\t\tcontext.closeDialog?.({ type: \"selected\", data: selectedEntity });\n\t};\n}) as ActionHandlerHookWithMeta;\nuseSetActionHandler.actionType = \"SetActionDefinition\";\n\n/**\n * Handle relation unset - hook factory.\n * Clears a single-valued relation.\n * Supports both legacy callback mode and API mode.\n */\nexport const useUnsetActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst transfer = context.transfer as TransferStored | undefined;\n\t\tconst transferId = transfer?.__identifier ?? transfer?.__signedIdentifier;\n\t\tif (!transferId) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst relationName = action.actionDefinition.name ?? \"\";\n\t\tconst callbackContext = context as unknown as LegacyCallbacks & ApiContext & RelationContext;\n\t\tconst { onUnset, api } = callbackContext;\n\n\t\t// Use legacy callback if provided\n\t\tif (onUnset) {\n\t\t\tawait onUnset(transferId, relationName);\n\t\t} else if (api) {\n\t\t\t// Use API if available\n\t\t\tconst relation = getRelation(callbackContext, action);\n\t\t\tif (!relation) {\n\t\t\t\tthrow new Error(\"Cannot determine relation for unset action\");\n\t\t\t}\n\t\t\tawait api.unsetRelation(relation, transfer!);\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseUnsetActionHandler.actionType = \"UnsetActionDefinition\";\n\n/**\n * Handle relation add (multi) - hook factory.\n * Adds selected transfers to a collection relation.\n * Supports both legacy callback mode and API mode.\n */\nexport const useAddActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst addContext = context as unknown as RelationContext & {\n\t\t\tselectedEntities?: TransferStored[];\n\t\t} & ApiContext &\n\t\t\tLegacyCallbacks;\n\n\t\tconst { ownerTransfer, selectedEntities, api, onAdd } = addContext;\n\n\t\tif (!ownerTransfer || !selectedEntities?.length) {\n\t\t\tthrow new Error(\"Missing transfers for add\");\n\t\t}\n\n\t\tconst ownerId = ownerTransfer.__identifier ?? ownerTransfer.__signedIdentifier;\n\t\tif (!ownerId) {\n\t\t\tthrow new Error(\"Missing owner transfer identifier for add\");\n\t\t}\n\n\t\tconst selectedIds = selectedEntities.map((e) => e.__identifier ?? e.__signedIdentifier).filter(Boolean) as string[];\n\t\tconst relationName = action.actionDefinition.name ?? \"\";\n\n\t\t// Use legacy callback if provided\n\t\tif (onAdd) {\n\t\t\tawait onAdd(ownerId, relationName, selectedIds);\n\t\t} else if (api) {\n\t\t\t// Use API if available\n\t\t\tconst relation = getRelation(addContext, action);\n\t\t\tif (!relation) {\n\t\t\t\tthrow new Error(\"Cannot determine relation for add action\");\n\t\t\t}\n\t\t\tawait api.addToRelation(relation, ownerTransfer, selectedEntities);\n\t\t}\n\n\t\tcontext.closeDialog?.({ type: \"selected\", data: selectedEntities });\n\t};\n}) as ActionHandlerHookWithMeta;\nuseAddActionHandler.actionType = \"AddActionDefinition\";\n\n/**\n * Handle relation remove - hook factory.\n * Removes a single transfer from a collection relation.\n * Supports both legacy callback mode and API mode.\n */\nexport const useRemoveActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst removeContext = context as unknown as RelationContext & ApiContext & LegacyCallbacks;\n\t\tconst eagerContext = context as unknown as {\n\t\t\tisEager?: boolean;\n\t\t\tparentTransferId?: string;\n\t\t\trelationName?: string;\n\t\t};\n\n\t\tconst transfer = context.transfer as TransferStored | undefined;\n\t\tconst transferId = transfer?.__identifier ?? transfer?.__signedIdentifier;\n\n\t\t// Eager mode: remove transfer from parent's local data store\n\t\tif (eagerContext.isEager && eagerContext.parentTransferId && context.data) {\n\t\t\tconst parentTransferId = eagerContext.parentTransferId;\n\t\t\tconst eagerRelationName = eagerContext.relationName;\n\n\t\t\tconst parentData = context.data.getSnapshot((state: unknown) => {\n\t\t\t\tconst typedState = state as { transfers: Map<string, { data: TransferData | null }> };\n\t\t\t\treturn typedState.transfers.get(parentTransferId)?.data;\n\t\t\t}) as TransferData | undefined;\n\n\t\t\tif (eagerRelationName) {\n\t\t\t\tconst currentItems = ((parentData as any)?.[eagerRelationName] as TransferStored[] | undefined) ?? [];\n\t\t\t\tconst newItems = currentItems.filter((item) => {\n\t\t\t\t\tconst itemId = item.__identifier ?? item.__signedIdentifier ?? (item as any).__tempId;\n\t\t\t\t\tconst targetId = transferId ?? (transfer as any)?.__tempId;\n\t\t\t\t\treturn itemId !== targetId;\n\t\t\t\t});\n\n\t\t\t\t// Use updateTransferFields to preserve dirty tracking and trigger edit mode\n\t\t\t\tcontext.data.updateTransferFields(parentTransferId, {\n\t\t\t\t\t[eagerRelationName]: newItems,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst currentItems = (parentData?.__items as TransferStored[] | undefined) ?? [];\n\t\t\t\tconst newItems = currentItems.filter((item) => {\n\t\t\t\t\tconst itemId = item.__identifier ?? item.__signedIdentifier ?? (item as any).__tempId;\n\t\t\t\t\tconst targetId = transferId ?? (transfer as any)?.__tempId;\n\t\t\t\t\treturn itemId !== targetId;\n\t\t\t\t});\n\n\t\t\t\t// Use updateTransferFields to preserve dirty tracking and trigger edit mode\n\t\t\t\tcontext.data.updateTransferFields(parentTransferId, {\n\t\t\t\t\t__items: newItems,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Lazy mode: remove via REST API\n\t\tconst { ownerTransfer, api, onRemove } = removeContext;\n\n\t\tconst ownerId = ownerTransfer?.__identifier ?? ownerTransfer?.__signedIdentifier;\n\n\t\tif (!ownerId || !transferId) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst relationName = action.actionDefinition.name ?? \"\";\n\n\t\t// Use legacy callback if provided\n\t\tif (onRemove) {\n\t\t\tawait onRemove(ownerId, relationName, [transferId]);\n\t\t} else if (api) {\n\t\t\t// Use API if available\n\t\t\tconst relation = getRelation(removeContext, action);\n\t\t\tif (!relation) {\n\t\t\t\tthrow new Error(\"Cannot determine relation for remove action\");\n\t\t\t}\n\t\t\tawait api.removeFromRelation(relation, ownerTransfer!, [transfer!]);\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseRemoveActionHandler.actionType = \"RemoveActionDefinition\";\n\n/**\n * Handle bulk remove - hook factory.\n * Removes multiple selected transfers from a collection relation.\n * Supports both legacy callback mode and API mode.\n */\nexport const useBulkRemoveActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst removeContext = context as unknown as RelationContext & ApiContext & LegacyCallbacks;\n\t\tconst eagerContext = context as unknown as {\n\t\t\tisEager?: boolean;\n\t\t\tparentTransferId?: string;\n\t\t\trelationName?: string;\n\t\t};\n\n\t\tconst selectedRows = context.selectedRows as TransferStored[] | undefined;\n\n\t\tif (!selectedRows?.length) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Eager mode: remove transfers from parent's local data store\n\t\tif (eagerContext.isEager && eagerContext.parentTransferId && context.data) {\n\t\t\tconst parentTransferId = eagerContext.parentTransferId;\n\t\t\tconst eagerRelationName = eagerContext.relationName;\n\n\t\t\t// Collect IDs of transfers to remove (support both backend and frontend IDs)\n\t\t\tconst removeIds = new Set(\n\t\t\t\tselectedRows.map((e) => e.__identifier ?? e.__signedIdentifier ?? (e as any).__tempId).filter(Boolean)\n\t\t\t);\n\n\t\t\tconst parentData = context.data.getSnapshot((state: unknown) => {\n\t\t\t\tconst typedState = state as { transfers: Map<string, { data: TransferData | null }> };\n\t\t\t\treturn typedState.transfers.get(parentTransferId)?.data;\n\t\t\t}) as TransferData | undefined;\n\n\t\t\tif (eagerRelationName) {\n\t\t\t\tconst currentItems = ((parentData as any)?.[eagerRelationName] as TransferStored[] | undefined) ?? [];\n\t\t\t\tconst newItems = currentItems.filter((item) => {\n\t\t\t\t\tconst itemId = item.__identifier ?? item.__signedIdentifier ?? (item as any).__tempId;\n\t\t\t\t\treturn !removeIds.has(itemId);\n\t\t\t\t});\n\n\t\t\t\t// Use updateTransferFields to preserve dirty tracking and trigger edit mode\n\t\t\t\tcontext.data.updateTransferFields(parentTransferId, {\n\t\t\t\t\t[eagerRelationName]: newItems,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tconst currentItems = (parentData?.__items as TransferStored[] | undefined) ?? [];\n\t\t\t\tconst newItems = currentItems.filter((item) => {\n\t\t\t\t\tconst itemId = item.__identifier ?? item.__signedIdentifier ?? (item as any).__tempId;\n\t\t\t\t\treturn !removeIds.has(itemId);\n\t\t\t\t});\n\n\t\t\t\t// Use updateTransferFields to preserve dirty tracking and trigger edit mode\n\t\t\t\tcontext.data.updateTransferFields(parentTransferId, {\n\t\t\t\t\t__items: newItems,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Lazy mode: remove via REST API\n\t\tconst { ownerTransfer, api, onBulkRemove } = removeContext;\n\n\t\tconst ownerId = ownerTransfer?.__identifier ?? ownerTransfer?.__signedIdentifier;\n\n\t\tif (!ownerId) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst selectedIds = selectedRows.map((e) => e.__identifier ?? e.__signedIdentifier).filter(Boolean) as string[];\n\t\tconst relationName = action.actionDefinition.name ?? \"\";\n\n\t\t// Use legacy callback if provided\n\t\tif (onBulkRemove) {\n\t\t\tawait onBulkRemove(ownerId, relationName, selectedIds);\n\t\t} else if (api) {\n\t\t\t// Use API if available\n\t\t\tconst relation = getRelation(removeContext, action);\n\t\t\tif (!relation) {\n\t\t\t\tthrow new Error(\"Cannot determine relation for bulk remove action\");\n\t\t\t}\n\t\t\tconst entitiesToRemove = selectedRows.filter((row) => row.__signedIdentifier);\n\t\t\tawait api.removeFromRelation(relation, ownerTransfer!, entitiesToRemove);\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseBulkRemoveActionHandler.actionType = \"BulkRemoveActionDefinition\";\n\n/**\n * Handle relation clear - hook factory.\n * Clears all transfers from a collection relation (unset for collection).\n * Supports both legacy callback mode and API mode.\n */\nexport const useClearActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst transfer = context.transfer as TransferStored | undefined;\n\t\tconst transferId = transfer?.__identifier ?? transfer?.__signedIdentifier;\n\t\tif (!transferId) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst callbackContext = context as unknown as ApiContext & RelationContext & LegacyCallbacks;\n\t\tconst { api, onClear } = callbackContext;\n\t\tconst relationName = action.actionDefinition.name ?? \"\";\n\n\t\t// Use legacy callback if provided\n\t\tif (onClear) {\n\t\t\tawait onClear(transferId, relationName);\n\t\t} else if (api) {\n\t\t\t// Use API if available\n\t\t\tconst relation = getRelation(callbackContext, action);\n\t\t\tif (!relation) {\n\t\t\t\tthrow new Error(\"Cannot determine relation for clear action\");\n\t\t\t}\n\t\t\t// Clear relation using unset (works for both single and collection)\n\t\t\tawait api.unsetRelation(relation, transfer!);\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseClearActionHandler.actionType = \"ClearActionDefinition\";\n\n/**\n * Handle relation refresh - hook factory.\n * Refreshes/reloads a relation's data.\n * Supports both legacy callback mode and API mode.\n */\nexport const useRefreshRelationActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst transfer = context.transfer as TransferStored | undefined;\n\t\tconst transferId = transfer?.__identifier ?? transfer?.__signedIdentifier;\n\t\tif (!transferId) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst callbackContext = context as unknown as ApiContext & RelationContext & LegacyCallbacks;\n\t\tconst { api, onRefreshRelation } = callbackContext;\n\t\tconst relationName = action.actionDefinition.name ?? \"\";\n\n\t\t// Use legacy callback if provided\n\t\tif (onRefreshRelation) {\n\t\t\tawait onRefreshRelation(transferId, relationName);\n\t\t} else if (api) {\n\t\t\t// Use API if available\n\t\t\tconst relation = getRelation(callbackContext, action);\n\t\t\tif (!relation) {\n\t\t\t\tthrow new Error(\"Cannot determine relation for refresh action\");\n\t\t\t}\n\t\t\t// For collection relations, list; for single, get\n\t\t\tif (relation.isCollection !== false) {\n\t\t\t\tawait api.listRelation(relation, transfer!);\n\t\t\t} else {\n\t\t\t\tawait api.getRelation(relation, transfer!);\n\t\t\t}\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseRefreshRelationActionHandler.actionType = \"RefreshRelationActionDefinition\";\n\n/**\n * Handle relation filter - hook factory.\n * Applies a filter to a relation (UI-side operation, no REST call).\n */\nexport const useFilterRelationActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\t// Filter is a UI-side operation - signal the intent\n\t\tconst filterContext = context as unknown as LegacyCallbacks;\n\n\t\tif (filterContext.onFilterRelation) {\n\t\t\tfilterContext.onFilterRelation(action.actionDefinition.name ?? \"\");\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseFilterRelationActionHandler.actionType = \"FilterRelationActionDefinition\";\n","import type { ClassType, RelationType } from \"@judo/model-api\";\nimport type { JudoRestApi } from \"../../api/judo-rest-api\";\nimport type { TransferStored } from \"../../api/types\";\nimport type { Action, ActionHandlerHookWithMeta, TypedActionHandlerContext } from \"../../types\";\n\n// Interface for API context\ninterface ApiContext {\n\tapi?: JudoRestApi;\n}\n\n// Interface for relation context\ninterface RelationContext {\n\townerTransfer?: TransferStored;\n\townerClassType?: ClassType;\n\trelation?: RelationType;\n}\n\n// Legacy callback interfaces for backward compatibility\ninterface LegacyCallbacks {\n\tonFilterRequest?: () => void;\n\tonExport?: (classType: ClassType) => Promise<void>;\n\tonInlineCreateRow?: () => void;\n}\n\n/**\n * Get relation from context.\n */\nfunction getRelation(relationContext: RelationContext): RelationType | null {\n\treturn relationContext.relation ?? null;\n}\n\n/**\n * Handle filter action (opens filter dialog) - hook factory.\n * Filter is primarily a UI operation - signals filter intent.\n */\nexport const useFilterActionHandler = ((_action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\t// Filter handling is typically done by Table component\n\t\t// This handler just signals filter intent\n\t\tconst filterContext = context as unknown as LegacyCallbacks;\n\t\tfilterContext.onFilterRequest?.();\n\t};\n}) as ActionHandlerHookWithMeta;\nuseFilterActionHandler.actionType = \"FilterActionDefinition\";\n\n/**\n * Handle export action - hook factory.\n * Exports relation data as a downloadable file via REST API.\n * Supports both legacy callback mode and API mode.\n */\nexport const useExportActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst targetType = action.actionDefinition.targetType as ClassType | undefined;\n\t\tif (!targetType) {\n\t\t\tthrow new Error(\"No target type for export\");\n\t\t}\n\n\t\tconst callbackContext = context as unknown as ApiContext & RelationContext & LegacyCallbacks;\n\t\tconst { onExport, api } = callbackContext;\n\n\t\t// Use legacy callback if provided\n\t\tif (onExport) {\n\t\t\tawait onExport(targetType);\n\t\t\treturn;\n\t\t}\n\n\t\t// Use API if available\n\t\tif (api) {\n\t\t\tconst relation = getRelation(callbackContext);\n\t\t\tif (!relation) {\n\t\t\t\tthrow new Error(\"Cannot determine relation for export action\");\n\t\t\t}\n\n\t\t\tconst transfer = context.transfer as TransferStored | undefined;\n\t\t\tconst response = await api.exportRelation(relation, transfer);\n\t\t\tconst blob = response.data;\n\n\t\t\t// Download file\n\t\t\tconst url = URL.createObjectURL(blob);\n\t\t\tconst a = document.createElement(\"a\");\n\t\t\ta.href = url;\n\t\t\ta.download = `export_${targetType.simpleName ?? targetType.name}_${Date.now()}.csv`;\n\t\t\ta.click();\n\t\t\tURL.revokeObjectURL(url);\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseExportActionHandler.actionType = \"ExportActionDefinition\";\n\n/**\n * Handle inline row creation in table - hook factory.\n * Inline creation is primarily a UI operation.\n */\nexport const useInlineCreateRowActionHandler = ((_action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\t// Signal inline create intent (UI-side operation)\n\t\tconst inlineContext = context as unknown as LegacyCallbacks;\n\t\tinlineContext.onInlineCreateRow?.();\n\t};\n}) as ActionHandlerHookWithMeta;\nuseInlineCreateRowActionHandler.actionType = \"InlineCreateRowActionDefinition\";\n","import type {\n\tCallOperationActionDefinition as CallOpDef,\n\tClassType,\n\tOperationType,\n\tPageDefinition,\n} from \"@judo/model-api\";\nimport type { JudoRestApi, OperationInfo } from \"../../api/judo-rest-api\";\nimport type { TransferStored, ValidationError } from \"../../api/types\";\nimport type { Action, ActionHandlerHookWithMeta, NotificationService, TypedActionHandlerContext } from \"../../types\";\n\n// Interface for API context - will be provided via context\ninterface ApiContext {\n\tapi?: JudoRestApi;\n}\n\n// Interface for page-level refresh callback provided by ViewContainerRenderer\ninterface RefreshPageContext {\n\trefreshPage?: () => void;\n}\n\n/**\n * Helper to check if an error is a ValidationError (400 response).\n */\nfunction isValidationError(error: unknown): error is ValidationError {\n\treturn error !== null && typeof error === \"object\" && (error as { name?: string }).name === \"ValidationError\";\n}\n\n/**\n * Helper to check if an error has a specific HTTP status code.\n */\nfunction hasStatus(error: unknown, ...statuses: number[]): boolean {\n\tif (error !== null && typeof error === \"object\") {\n\t\tconst status = (error as { status?: number }).status;\n\t\treturn status !== undefined && statuses.includes(status);\n\t}\n\treturn false;\n}\n\n/**\n * Handle operation errors with appropriate notifications.\n * - 400: Validation error toast + set field errors\n * - 401/403: Access denied toast\n * - Other 4xx/5xx: Generic error toast\n */\nfunction handleOperationError(\n\terror: unknown,\n\toperationName: string,\n\tnotifications: NotificationService | undefined,\n\tvalidation?: { setErrors: (errors: Record<string, string>) => void }\n): void {\n\tif (isValidationError(error)) {\n\t\t// 400 - Validation error\n\t\tconst fieldErrors = error.toFieldErrors();\n\t\tif (validation && Object.keys(fieldErrors).length > 0) {\n\t\t\tvalidation.setErrors(fieldErrors);\n\t\t}\n\t\tnotifications?.error(`Validation failed for ${operationName}`);\n\t} else if (hasStatus(error, 401, 403)) {\n\t\t// 401/403 - Access denied\n\t\tnotifications?.error(`Access denied: You don't have permission to execute ${operationName}`);\n\t} else if (hasStatus(error, 404)) {\n\t\t// 404 - Not found\n\t\tnotifications?.error(`Resource not found for ${operationName}`);\n\t} else {\n\t\t// Other errors (5xx, network, etc.)\n\t\tconst message = error instanceof Error ? error.message : \"Unknown error\";\n\t\tnotifications?.error(`Operation ${operationName} failed: ${message}`);\n\t}\n}\n\n/**\n * Open operation output page/dialog if action has a target page and operation returned data.\n * Uses `navigateTo` for full-page output or `openDialog` when the target page has `openInDialog=true`.\n */\nfunction openOperationOutputPage(\n\taction: Action,\n\tresult: TransferStored | undefined,\n\toperation: OperationType,\n\tcontext: TypedActionHandlerContext\n): void {\n\t// Check if operation returned data and action has a target page for the output\n\tconst targetPage = action.targetPageDefinition as PageDefinition | undefined;\n\tif (!result || !targetPage) {\n\t\treturn;\n\t}\n\n\t// Determine if output is mapped (has lifecycle) based on operation.output.behaviours\n\tconst outputParam = operation.output;\n\tconst behaviours = (outputParam as { behaviours?: string[] } | undefined)?.behaviours ?? [];\n\tconst isMappedOutput = behaviours.some((b) => [\"UPDATE\", \"DELETE\", \"REFRESH\"].includes(b));\n\n\tconst params = {\n\t\ttransfer: result,\n\t\tisOperationOutput: true,\n\t\tisMappedOutput,\n\t};\n\n\t// Check PageDefinition.openInDialog to decide between dialog and page navigation\n\tif (String(targetPage.openInDialog) === \"true\") {\n\t\tcontext.navigation?.openDialog(targetPage, params);\n\t} else {\n\t\tcontext.navigation?.navigateTo(targetPage, params);\n\t}\n}\n\n/**\n * Trigger a full page refresh after a successful operation.\n * Calls the refreshPage callback provided by ViewContainerRenderer\n * via additionalContext. This causes the transfer data AND all embedded\n * tables to re-fetch their data.\n */\nfunction triggerPageRefresh(context: TypedActionHandlerContext): void {\n\tconst { refreshPage } = context as unknown as RefreshPageContext;\n\trefreshPage?.();\n}\n\n// Legacy callback interfaces for backward compatibility\ninterface LegacyCallbacks {\n\tonCallOperation?: (\n\t\toperation: OperationType,\n\t\towner: TransferStored | undefined,\n\t\ttarget: TransferStored | undefined\n\t) => Promise<unknown>;\n\tonBulkCallOperation?: (operation: OperationType, transfers: TransferStored[]) => Promise<void>;\n\tonInputFormCallOperation?: (\n\t\toperation: OperationType,\n\t\ttransfer: TransferStored | undefined,\n\t\tinputData: TransferStored\n\t) => Promise<unknown>;\n\tonInputSelectorCallOperation?: (\n\t\toperation: OperationType,\n\t\ttransfer: TransferStored | undefined,\n\t\tselectedEntity: TransferStored\n\t) => Promise<unknown>;\n\tonParameterlessCallOperation?: (operation: OperationType, transfer: TransferStored | undefined) => Promise<unknown>;\n}\n\n/**\n * Convert OperationType to OperationInfo for the REST API.\n */\nfunction toOperationInfo(operation: OperationType): OperationInfo {\n\treturn {\n\t\tname: operation.name,\n\t\tisStatic: operation.operationType === \"STATIC\",\n\t\tisMapped: operation.operationType === \"MAPPED\",\n\t\thasInput: !!operation.input,\n\t\tinputType: operation.input?.target,\n\t};\n}\n\n/**\n * Handle operation calls - hook factory.\n * Calls a bound operation via REST API.\n * Supports both legacy callback mode and API mode.\n * Opens output dialog if operation returns data and action has targetPageDefinition.\n * Shows success toast on success, error toast on failure.\n */\nexport const useCallOperationActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\t// Cast actionDefinition to CallOperationActionDefinition to access operation\n\t\tconst opDef = action.actionDefinition as CallOpDef;\n\t\tconst operation = opDef.operation as OperationType | undefined;\n\t\tif (!operation) {\n\t\t\tthrow new Error(\"No operation defined for CallOperationAction\");\n\t\t}\n\n\t\tconst callbackContext = context as unknown as LegacyCallbacks & ApiContext;\n\t\tconst { onCallOperation, api } = callbackContext;\n\t\tconst { notifications, validation } = context;\n\n\t\tconst transfer = context.transfer as TransferStored | undefined;\n\n\t\ttry {\n\t\t\t// Use legacy callback if provided\n\t\t\tif (onCallOperation) {\n\t\t\t\tconst result = await onCallOperation(operation, transfer, transfer);\n\t\t\t\tnotifications?.success(`${operation.name} completed successfully`);\n\t\t\t\topenOperationOutputPage(action, result as TransferStored | undefined, operation, context);\n\t\t\t\ttriggerPageRefresh(context);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Use API if available\n\t\t\tif (api) {\n\t\t\t\t// Get the owner ClassType - either from actionDefinition.targetType or operation's eContainer\n\t\t\t\tconst ownerType = (opDef.targetType ?? operation.eContainer) as ClassType | undefined;\n\t\t\t\tif (!ownerType) {\n\t\t\t\t\tthrow new Error(\"No owner type for operation call\");\n\t\t\t\t}\n\n\t\t\t\tconst operationInfo = toOperationInfo(operation);\n\n\t\t\t\t// Invoke the operation\n\t\t\t\tconst response = await api.invokeOperation(ownerType, operationInfo, transfer, transfer);\n\t\t\t\tnotifications?.success(`${operation.name} completed successfully`);\n\t\t\t\topenOperationOutputPage(action, response.data as TransferStored | undefined, operation, context);\n\t\t\t\ttriggerPageRefresh(context);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\thandleOperationError(error, operation.name, notifications, validation);\n\t\t\tthrow error;\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseCallOperationActionHandler.actionType = \"CallOperationActionDefinition\";\n\n/**\n * Handle bulk operation calls - hook factory.\n * Calls an operation on multiple selected transfers.\n * Supports both legacy callback mode and API mode.\n * Shows success toast on success, error toast on failure.\n */\nexport const useBulkCallOperationActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\t// Cast actionDefinition to access operation\n\t\tconst opDef = action.actionDefinition as CallOpDef;\n\t\tconst operation = opDef.operation as OperationType | undefined;\n\t\tif (!operation) {\n\t\t\tthrow new Error(\"No operation defined for BulkCallOperationAction\");\n\t\t}\n\n\t\tconst selectedRows = context.selectedRows as TransferStored[] | undefined;\n\t\tif (!selectedRows || selectedRows.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst callbackContext = context as unknown as LegacyCallbacks & ApiContext;\n\t\tconst { onBulkCallOperation, api } = callbackContext;\n\t\tconst { notifications, validation } = context;\n\n\t\ttry {\n\t\t\t// Use legacy callback if provided\n\t\t\tif (onBulkCallOperation) {\n\t\t\t\tawait onBulkCallOperation(operation, selectedRows);\n\t\t\t\tnotifications?.success(`${operation.name} completed on ${selectedRows.length} item(s)`);\n\t\t\t\ttriggerPageRefresh(context);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Use API if available\n\t\t\tif (api) {\n\t\t\t\t// Get the owner ClassType - either from actionDefinition.targetType or operation's eContainer\n\t\t\t\tconst ownerType = (opDef.targetType ?? operation.eContainer) as ClassType | undefined;\n\t\t\t\tif (!ownerType) {\n\t\t\t\t\tthrow new Error(\"No owner type for bulk operation call\");\n\t\t\t\t}\n\n\t\t\t\tconst operationInfo = toOperationInfo(operation);\n\n\t\t\t\t// Call operation on each selected transfer\n\t\t\t\tconst operationPromises = selectedRows.map((row) => api.invokeOperation(ownerType, operationInfo, row, row));\n\n\t\t\t\tawait Promise.all(operationPromises);\n\t\t\t\tnotifications?.success(`${operation.name} completed on ${selectedRows.length} item(s)`);\n\t\t\t\ttriggerPageRefresh(context);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\thandleOperationError(error, operation.name, notifications, validation);\n\t\t\tthrow error;\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseBulkCallOperationActionHandler.actionType = \"BulkCallOperationActionDefinition\";\n\n/**\n * Handle operation with input form - hook factory.\n * Calls an operation with form data as input.\n * Supports both legacy callback mode and API mode.\n * Opens output dialog if operation returns data and action has targetPageDefinition.\n * Shows success toast on success, error toast on failure.\n * Only closes dialog on success.\n */\nexport const useInputFormCallOperationActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\t// Cast actionDefinition to access operation\n\t\tconst opDef = action.actionDefinition as CallOpDef;\n\t\tconst operation = opDef.operation as OperationType | undefined;\n\t\tif (!operation) {\n\t\t\tthrow new Error(\"No operation defined for InputFormCallOperationAction\");\n\t\t}\n\n\t\tconst inputFormContext = context as unknown as {\n\t\t\tinputData?: TransferStored;\n\t\t\tpageTransferId?: string;\n\t\t} & LegacyCallbacks &\n\t\t\tApiContext;\n\n\t\tconst { onInputFormCallOperation, api, pageTransferId } = inputFormContext;\n\t\tconst { notifications, validation } = context;\n\t\tconst transfer = context.transfer as TransferStored | undefined;\n\n\t\t// Get input data from context or from data store using pageTransferId\n\t\t// For input forms, the form data is stored in data store by the form components\n\t\tlet inputData = inputFormContext.inputData;\n\t\tif (!inputData && context.data && pageTransferId) {\n\t\t\tinputData = context.data.getSnapshot((state: unknown) => {\n\t\t\t\tconst typedState = state as { transfers: Map<string, { data: TransferStored | null }> };\n\t\t\t\treturn typedState.transfers.get(pageTransferId)?.data;\n\t\t\t}) as TransferStored | undefined;\n\t\t}\n\n\t\tif (!inputData) {\n\t\t\t// No input data - cannot proceed\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\t// Use legacy callback if provided\n\t\t\tif (onInputFormCallOperation) {\n\t\t\t\tconst result = await onInputFormCallOperation(operation, transfer, inputData);\n\t\t\t\t// Success: close input dialog first, then show toast and open output page\n\t\t\t\tcontext.closeDialog?.({ type: \"submitted\" });\n\t\t\t\tnotifications?.success(`${operation.name} completed successfully`);\n\t\t\t\topenOperationOutputPage(action, result as TransferStored | undefined, operation, context);\n\t\t\t\ttriggerPageRefresh(context);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Use API if available\n\t\t\tif (api) {\n\t\t\t\t// Get the owner ClassType - either from actionDefinition.targetType or operation's eContainer\n\t\t\t\tconst ownerType = (opDef.targetType ?? operation.eContainer) as ClassType | undefined;\n\t\t\t\tif (!ownerType) {\n\t\t\t\t\tthrow new Error(\"No owner type for input form operation call\");\n\t\t\t\t}\n\n\t\t\t\tconst operationInfo = toOperationInfo(operation);\n\n\t\t\t\t// Invoke operation with form input\n\t\t\t\tconst response = await api.invokeOperation(ownerType, operationInfo, transfer, inputData);\n\n\t\t\t\t// Success: close input dialog first, then show toast and open output page\n\t\t\t\tcontext.closeDialog?.({ type: \"submitted\" });\n\t\t\t\tnotifications?.success(`${operation.name} completed successfully`);\n\t\t\t\topenOperationOutputPage(action, response.data as TransferStored | undefined, operation, context);\n\t\t\t\ttriggerPageRefresh(context);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Error: do NOT close dialog, show error toast\n\t\t\thandleOperationError(error, operation.name, notifications, validation);\n\t\t\tthrow error;\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseInputFormCallOperationActionHandler.actionType = \"InputFormCallOperationActionDefinition\";\n\n/**\n * Handle operation with input selector - hook factory.\n * Calls an operation with selected transfer as input.\n * Supports both legacy callback mode and API mode.\n * Opens output dialog if operation returns data and action has targetPageDefinition.\n * Shows success toast on success, error toast on failure.\n * Only closes dialog on success.\n */\nexport const useInputSelectorCallOperationActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\t// Cast actionDefinition to access operation\n\t\tconst opDef = action.actionDefinition as CallOpDef;\n\t\tconst operation = opDef.operation as OperationType | undefined;\n\t\tif (!operation) {\n\t\t\tthrow new Error(\"No operation defined for InputSelectorCallOperationAction\");\n\t\t}\n\n\t\tconst selectorContext = context as unknown as {\n\t\t\tselectedEntity?: TransferStored;\n\t\t\townerTransfer?: TransferStored;\n\t\t} & LegacyCallbacks &\n\t\t\tApiContext;\n\n\t\tconst { onInputSelectorCallOperation, api, selectedEntity, ownerTransfer } = selectorContext;\n\t\tconst { notifications, validation } = context;\n\t\t// In selector dialogs, context.transfer is undefined because the dialog was\n\t\t// opened without a transfer param. The ownerTransfer (the entity that owns\n\t\t// the operation) is injected by pageActionDispatch from the selection context.\n\t\t// Use ownerTransfer as the API owner so X-Judo-SignedIdentifier is sent.\n\t\tconst transfer = (context.transfer ?? ownerTransfer) as TransferStored | undefined;\n\n\t\tif (!selectedEntity) {\n\t\t\t// No selected transfer - cannot proceed\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\t// Use legacy callback if provided\n\t\t\tif (onInputSelectorCallOperation) {\n\t\t\t\tconst result = await onInputSelectorCallOperation(operation, transfer, selectedEntity);\n\t\t\t\t// Success: close selector dialog first, then show toast and open output page\n\t\t\t\tcontext.closeDialog?.({ type: \"submitted\" });\n\t\t\t\tnotifications?.success(`${operation.name} completed successfully`);\n\t\t\t\topenOperationOutputPage(action, result as TransferStored | undefined, operation, context);\n\t\t\t\ttriggerPageRefresh(context);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Use API if available\n\t\t\tif (api) {\n\t\t\t\t// Get the owner ClassType - either from actionDefinition.targetType or operation's eContainer\n\t\t\t\tconst ownerType = (opDef.targetType ?? operation.eContainer) as ClassType | undefined;\n\t\t\t\tif (!ownerType) {\n\t\t\t\t\tthrow new Error(\"No owner type for input selector operation call\");\n\t\t\t\t}\n\n\t\t\t\tconst operationInfo = toOperationInfo(operation);\n\n\t\t\t\t// Invoke operation with selected transfer as input\n\t\t\t\tconst response = await api.invokeOperation(ownerType, operationInfo, transfer, selectedEntity);\n\n\t\t\t\t// Success: close selector dialog first, then show toast and open output page\n\t\t\t\tcontext.closeDialog?.({ type: \"submitted\" });\n\t\t\t\tnotifications?.success(`${operation.name} completed successfully`);\n\t\t\t\topenOperationOutputPage(action, response.data as TransferStored | undefined, operation, context);\n\t\t\t\ttriggerPageRefresh(context);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Error: do NOT close dialog, show error toast\n\t\t\thandleOperationError(error, operation.name, notifications, validation);\n\t\t\tthrow error;\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseInputSelectorCallOperationActionHandler.actionType = \"InputSelectorCallOperationActionDefinition\";\n\n/**\n * Handle parameterless operation calls - hook factory.\n * Calls an operation with no input.\n * Supports both legacy callback mode and API mode.\n * Opens output dialog if operation returns data and action has targetPageDefinition.\n * Shows success toast on success, error toast on failure.\n */\nexport const useParameterlessCallOperationActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\t// Cast actionDefinition to access operation\n\t\tconst opDef = action.actionDefinition as CallOpDef;\n\t\tconst operation = opDef.operation as OperationType | undefined;\n\t\tif (!operation) {\n\t\t\tthrow new Error(\"No operation defined for ParameterlessCallOperationAction\");\n\t\t}\n\n\t\tconst callbackContext = context as unknown as LegacyCallbacks & ApiContext;\n\t\tconst { onParameterlessCallOperation, api } = callbackContext;\n\t\tconst { notifications, validation } = context;\n\n\t\tconst transfer = context.transfer as TransferStored | undefined;\n\n\t\ttry {\n\t\t\t// Use legacy callback if provided\n\t\t\tif (onParameterlessCallOperation) {\n\t\t\t\tconst result = await onParameterlessCallOperation(operation, transfer);\n\t\t\t\tnotifications?.success(`${operation.name} completed successfully`);\n\t\t\t\topenOperationOutputPage(action, result as TransferStored | undefined, operation, context);\n\t\t\t\ttriggerPageRefresh(context);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Use API if available\n\t\t\tif (api) {\n\t\t\t\t// Get the owner ClassType - either from actionDefinition.targetType or operation's eContainer\n\t\t\t\tconst ownerType = (opDef.targetType ?? operation.eContainer) as ClassType | undefined;\n\t\t\t\tif (!ownerType) {\n\t\t\t\t\tthrow new Error(\"No owner type for parameterless operation call\");\n\t\t\t\t}\n\n\t\t\t\tconst operationInfo = toOperationInfo(operation);\n\n\t\t\t\t// Invoke operation without input parameters\n\t\t\t\tconst response = await api.invokeOperation(ownerType, operationInfo, transfer, undefined);\n\t\t\t\tnotifications?.success(`${operation.name} completed successfully`);\n\t\t\t\topenOperationOutputPage(action, response.data as TransferStored | undefined, operation, context);\n\t\t\t\ttriggerPageRefresh(context);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\thandleOperationError(error, operation.name, notifications, validation);\n\t\t\tthrow error;\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseParameterlessCallOperationActionHandler.actionType = \"ParameterlessCallOperationActionDefinition\";\n","import type { ClassType, RelationType } from \"@judo/model-api\";\nimport type { JudoRestApi } from \"../../api/judo-rest-api\";\nimport type { TransferStored } from \"../../api/types\";\nimport type { Action, ActionHandlerHookWithMeta, TypedActionHandlerContext } from \"../../types\";\n\n// Interface for API context\ninterface ApiContext {\n\tapi?: JudoRestApi;\n}\n\n// Interface for relation context\ninterface RelationContext {\n\townerTransfer?: TransferStored;\n\townerClassType?: ClassType;\n\trelation?: RelationType;\n}\n\n// Legacy callback interfaces for backward compatibility\ninterface LegacyCallbacks {\n\tonAutocompleteRange?: (classType: ClassType, searchText: string) => Promise<TransferStored[]>;\n\tonAutocompleteSet?: (ownerId: string, relationName: string, selectedId: string) => Promise<void>;\n\tonAutocompleteAdd?: (ownerId: string, relationName: string, selectedIds: string[]) => Promise<void>;\n}\n\n/**\n * Get RelationType from context.\n */\nfunction getRelation(relationContext: RelationContext, action: Action): RelationType | null {\n\tif (relationContext.relation) {\n\t\treturn relationContext.relation;\n\t}\n\t// Check if action has a relation in ownerDataElement\n\tconst ownerDataElement = action.ownerDataElement;\n\tif (ownerDataElement && ownerDataElement[\"@type\"] === \"RelationType\") {\n\t\treturn ownerDataElement as RelationType;\n\t}\n\treturn null;\n}\n\n/**\n * Handle autocomplete range query - hook factory.\n * Fetches range data for autocomplete via REST API.\n * Supports both legacy callback mode and API mode.\n */\nexport const useAutocompleteRangeActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst targetType = action.actionDefinition.targetType as ClassType | undefined;\n\t\tif (!targetType) {\n\t\t\tthrow new Error(\"No target type for autocomplete range\");\n\t\t}\n\n\t\tconst callbackContext = context as unknown as ApiContext &\n\t\t\tRelationContext &\n\t\t\tLegacyCallbacks & {\n\t\t\t\tsearchText?: string;\n\t\t\t\tonRangeResult?: (results: TransferStored[]) => void;\n\t\t\t};\n\n\t\tconst { onAutocompleteRange, api, onRangeResult } = callbackContext;\n\t\tconst searchText = callbackContext.searchText ?? \"\";\n\n\t\t// Use legacy callback if provided\n\t\tif (onAutocompleteRange) {\n\t\t\tconst results = await onAutocompleteRange(targetType, searchText);\n\t\t\tonRangeResult?.(results);\n\t\t\treturn;\n\t\t}\n\n\t\t// Use API if available\n\t\tif (api) {\n\t\t\tconst relation = getRelation(callbackContext, action);\n\t\t\tif (!relation) {\n\t\t\t\tthrow new Error(\"Cannot determine relation for autocomplete range\");\n\t\t\t}\n\n\t\t\t// Build query customizer for search\n\t\t\tconst queryCustomizer = searchText\n\t\t\t\t? {\n\t\t\t\t\t\t_filter: { contains: searchText },\n\t\t\t\t\t}\n\t\t\t\t: undefined;\n\n\t\t\tconst response = await api.getRelationRange(relation, callbackContext.ownerTransfer, queryCustomizer);\n\n\t\t\t// Signal results to UI\n\t\t\tonRangeResult?.(response.data);\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseAutocompleteRangeActionHandler.actionType = \"AutocompleteRangeActionDefinition\";\n\n/**\n * Handle autocomplete set action - hook factory.\n * Sets a single-valued relation via autocomplete selection.\n * Supports both legacy callback mode and API mode.\n */\nexport const useAutocompleteSetActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst autocompleteContext = context as unknown as RelationContext & {\n\t\t\tselectedEntity?: TransferStored;\n\t\t} & ApiContext &\n\t\t\tLegacyCallbacks;\n\n\t\tconst { ownerTransfer, selectedEntity, api, onAutocompleteSet } = autocompleteContext;\n\n\t\tconst ownerId = ownerTransfer?.__identifier ?? ownerTransfer?.__signedIdentifier;\n\t\tconst selectedId = selectedEntity?.__identifier ?? selectedEntity?.__signedIdentifier;\n\n\t\tif (!ownerId || !selectedId) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst relationName = action.actionDefinition.name ?? \"\";\n\n\t\t// Use legacy callback if provided\n\t\tif (onAutocompleteSet) {\n\t\t\tawait onAutocompleteSet(ownerId, relationName, selectedId);\n\t\t\treturn;\n\t\t}\n\n\t\t// Use API if available\n\t\tif (api) {\n\t\t\tconst relation = getRelation(autocompleteContext, action);\n\t\t\tif (!relation) {\n\t\t\t\tthrow new Error(\"Cannot determine relation for autocomplete set\");\n\t\t\t}\n\n\t\t\tawait api.setRelation(relation, ownerTransfer!, selectedEntity!);\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseAutocompleteSetActionHandler.actionType = \"AutocompleteSetActionDefinition\";\n\n/**\n * Handle autocomplete add action - hook factory.\n * Adds selected transfers to a collection relation via autocomplete.\n * Supports both legacy callback mode and API mode.\n */\nexport const useAutocompleteAddActionHandler = ((action: Action) => {\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst autocompleteContext = context as unknown as RelationContext & {\n\t\t\tselectedEntities?: TransferStored[];\n\t\t} & ApiContext &\n\t\t\tLegacyCallbacks;\n\n\t\tconst { ownerTransfer, selectedEntities, api, onAutocompleteAdd } = autocompleteContext;\n\n\t\tconst ownerId = ownerTransfer?.__identifier ?? ownerTransfer?.__signedIdentifier;\n\n\t\tif (!ownerId || !selectedEntities?.length) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst selectedIds = selectedEntities.map((e) => e.__identifier ?? e.__signedIdentifier).filter(Boolean) as string[];\n\t\tconst relationName = action.actionDefinition.name ?? \"\";\n\n\t\t// Use legacy callback if provided\n\t\tif (onAutocompleteAdd) {\n\t\t\tawait onAutocompleteAdd(ownerId, relationName, selectedIds);\n\t\t\treturn;\n\t\t}\n\n\t\t// Use API if available\n\t\tif (api) {\n\t\t\tconst relation = getRelation(autocompleteContext, action);\n\t\t\tif (!relation) {\n\t\t\t\tthrow new Error(\"Cannot determine relation for autocomplete add\");\n\t\t\t}\n\n\t\t\tconst entitiesToAdd = selectedEntities.filter((e) => e.__signedIdentifier);\n\t\t\tawait api.addToRelation(relation, ownerTransfer!, entitiesToAdd);\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseAutocompleteAddActionHandler.actionType = \"AutocompleteAddActionDefinition\";\n","import type { Action, ActionHandlerHookWithMeta, TransferData, TypedActionHandlerContext } from \"../../types\";\n\n/**\n * Handle pre-fetch action (load data before navigation) - hook factory.\n */\nexport const usePreFetchActionHandler = ((action: Action) => {\n\t// React hooks can be called here\n\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst classType = action.actionDefinition.targetType;\n\t\tif (!classType) {\n\t\t\tthrow new Error(\"No target type for pre-fetch\");\n\t\t}\n\n\t\tconst preFetchContext = context as unknown as {\n\t\t\tonPreFetch?: (classType: unknown, transferId: string | undefined) => Promise<TransferData>;\n\t\t};\n\n\t\tif (preFetchContext.onPreFetch) {\n\t\t\tconst data = await preFetchContext.onPreFetch(classType, context.transfer?.__identifier);\n\t\t\tif (data.__identifier) {\n\t\t\t\tcontext.data!.setTransferData(data.__identifier, data);\n\t\t\t}\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nusePreFetchActionHandler.actionType = \"PreFetchActionDefinition\";\n\n/**\n * Handle custom action (user-defined logic) - hook factory.\n */\nexport const useCustomActionHandler = ((action: Action) => {\n\t// React hooks can be called here\n\n\treturn async (context: TypedActionHandlerContext): Promise<void> => {\n\t\tconst customContext = context as unknown as {\n\t\t\tonCustomAction?: (action: Action, context: TypedActionHandlerContext) => Promise<void>;\n\t\t};\n\n\t\tif (customContext.onCustomAction) {\n\t\t\tawait customContext.onCustomAction(action, context);\n\t\t}\n\t};\n}) as ActionHandlerHookWithMeta;\nuseCustomActionHandler.actionType = \"CustomActionDefinition\";\n","import { type ReactNode, createContext, useContext } from \"react\";\nimport type { JudoRestApi } from \"../api/judo-rest-api\";\n\n/**\n * API context type.\n */\nexport interface ApiContextType {\n\t/** JUDO REST API client */\n\tapi: JudoRestApi;\n}\n\nconst ApiContext = createContext<ApiContextType | null>(null);\n\n/**\n * Hook to access the JUDO REST API client.\n *\n * @returns JudoRestApi\n * @throws Error if used outside ApiProvider\n */\nexport function useApi(): JudoRestApi {\n\tconst context = useContext(ApiContext);\n\tif (!context) {\n\t\tthrow new Error(\"useApi must be used within ApiProvider\");\n\t}\n\treturn context.api;\n}\n\n/**\n * Props for ApiProvider.\n */\nexport interface ApiProviderProps {\n\tchildren: ReactNode;\n\t/** JUDO REST API client instance */\n\tapi: JudoRestApi;\n}\n\n/**\n * Provider for JUDO REST API client.\n * Makes the API client available to action handlers via the useApi hook.\n */\nexport function ApiProvider({ children, api }: ApiProviderProps) {\n\tconst value: ApiContextType = { api };\n\treturn <ApiContext.Provider value={value}>{children}</ApiContext.Provider>;\n}\n","/**\n * Action lifecycle execution engine.\n *\n * Composes lifecycle overrides with built-in action handlers.\n * The lifecycle wraps the default handler with before/after/onError hooks\n * and allows full replacement of the execute phase.\n */\n\nimport type { ActionLifecycle, ActionLifecycleContext } from \"@judo/model-api\";\nimport type { ActionHandlerContext, ActionHandlerFn } from \"@judo/model-api\";\nimport type { Action } from \"../types\";\n\n/**\n * Execute an action with lifecycle overrides composed around a default handler.\n *\n * Lifecycle execution order:\n * 1. override.before() → return false to cancel\n * 2. override.execute() ?? defaultHandler() → core execution\n * 3. override.after() → post-processing\n * 4. override.onError() → error handling (return true to suppress)\n *\n * @param defaultHandler - The built-in action handler function\n * @param overrides - Partial lifecycle overrides from the developer\n * @param baseContext - The base action handler context\n * @param action - The Action model object\n * @param page - The PageDefinition\n * @returns Promise resolving to the action result\n */\nexport async function executeWithLifecycle(\n\tdefaultHandler: ActionHandlerFn,\n\toverrides: Partial<ActionLifecycle>,\n\tbaseContext: ActionHandlerContext,\n\taction: Action\n): Promise<unknown> {\n\t// Build lifecycle context with callDefault\n\tconst callDefault = () => defaultHandler(baseContext);\n\n\tconst lifecycleContext: ActionLifecycleContext = {\n\t\t...(baseContext as unknown as Record<string, unknown>),\n\t\taction,\n\t\tactionDefinition: action.actionDefinition,\n\t\tpage: (baseContext as unknown as Record<string, unknown>).page as ActionLifecycleContext[\"page\"],\n\t\tcallDefault,\n\t};\n\n\t// BEFORE phase\n\tif (overrides.before) {\n\t\tconst proceed = await overrides.before(lifecycleContext);\n\t\tif (proceed === false) return undefined; // cancelled\n\t}\n\n\ttry {\n\t\t// EXECUTE phase\n\t\tlet result: unknown;\n\t\tif (overrides.execute) {\n\t\t\t// Developer provided custom execution\n\t\t\t// callDefault is available on context for wrapping\n\t\t\tresult = await overrides.execute(lifecycleContext);\n\t\t} else {\n\t\t\t// Use built-in handler\n\t\t\tresult = await defaultHandler(baseContext);\n\t\t}\n\n\t\t// AFTER phase\n\t\tif (overrides.after) {\n\t\t\tawait overrides.after(lifecycleContext, result);\n\t\t}\n\n\t\treturn result;\n\t} catch (error) {\n\t\t// ERROR phase\n\t\tif (overrides.onError) {\n\t\t\tconst suppressed = await overrides.onError(lifecycleContext, error);\n\t\t\tif (suppressed === true) return undefined; // error handled by override\n\t\t}\n\t\tthrow error; // re-throw for default error handling\n\t}\n}\n","import type { Action, ActionHandlerHook } from \"../types\";\n\n// Import all built-in handlers\nimport {\n\tuseBackActionHandler,\n\tuseCancelActionHandler,\n\tuseOpenPageActionHandler,\n\tuseRowOpenPageActionHandler,\n} from \"../handlers/navigation\";\n\nimport {\n\tuseOpenCreateFormActionHandler,\n\tuseOpenFormActionHandler,\n\tuseOpenOperationInputFormActionHandler,\n} from \"../handlers/form\";\n\nimport {\n\tuseOpenAddSelectorActionHandler,\n\tuseOpenOperationInputSelectorActionHandler,\n\tuseOpenSelectorActionHandler,\n\tuseOpenSetSelectorActionHandler,\n\tuseSelectorRangeActionHandler,\n} from \"../handlers/selector\";\n\nimport {\n\tuseBulkDeleteActionHandler,\n\tuseCreateActionHandler,\n\tuseDeleteActionHandler,\n\tuseGetTemplateActionHandler,\n\tuseRefreshActionHandler,\n\tuseRowDeleteActionHandler,\n\tuseUpdateActionHandler,\n} from \"../handlers/crud\";\n\nimport {\n\tuseAddActionHandler,\n\tuseBulkRemoveActionHandler,\n\tuseClearActionHandler,\n\tuseFilterRelationActionHandler,\n\tuseRefreshRelationActionHandler,\n\tuseRemoveActionHandler,\n\tuseSetActionHandler,\n\tuseUnsetActionHandler,\n} from \"../handlers/relation\";\n\nimport { useExportActionHandler, useFilterActionHandler, useInlineCreateRowActionHandler } from \"../handlers/table\";\n\nimport {\n\tuseBulkCallOperationActionHandler,\n\tuseCallOperationActionHandler,\n\tuseInputFormCallOperationActionHandler,\n\tuseInputSelectorCallOperationActionHandler,\n\tuseParameterlessCallOperationActionHandler,\n} from \"../handlers/operation\";\n\nimport {\n\tuseAutocompleteAddActionHandler,\n\tuseAutocompleteRangeActionHandler,\n\tuseAutocompleteSetActionHandler,\n} from \"../handlers/autocomplete\";\n\nimport { useCustomActionHandler, usePreFetchActionHandler } from \"../handlers/other\";\n\n/**\n * Registry of all built-in action handlers.\n * Maps action type to handler hook.\n * Built-in handlers use TypedActionHandlerContext, cast to base type for compatibility.\n */\nconst BUILTIN_HANDLERS = new Map<string, ActionHandlerHook>([\n\t// Navigation (4)\n\t[\"BackActionDefinition\", useBackActionHandler as ActionHandlerHook],\n\t[\"OpenPageActionDefinition\", useOpenPageActionHandler as ActionHandlerHook],\n\t[\"RowOpenPageActionDefinition\", useRowOpenPageActionHandler as ActionHandlerHook],\n\t[\"CancelActionDefinition\", useCancelActionHandler as ActionHandlerHook],\n\n\t// Form (3)\n\t[\"OpenFormActionDefinition\", useOpenFormActionHandler as ActionHandlerHook],\n\t[\"OpenCreateFormActionDefinition\", useOpenCreateFormActionHandler as ActionHandlerHook],\n\t[\"OpenOperationInputFormActionDefinition\", useOpenOperationInputFormActionHandler as ActionHandlerHook],\n\n\t// Selector (5)\n\t[\"OpenSelectorActionDefinition\", useOpenSelectorActionHandler as ActionHandlerHook],\n\t[\"OpenAddSelectorActionDefinition\", useOpenAddSelectorActionHandler as ActionHandlerHook],\n\t[\"OpenSetSelectorActionDefinition\", useOpenSetSelectorActionHandler as ActionHandlerHook],\n\t[\"OpenOperationInputSelectorActionDefinition\", useOpenOperationInputSelectorActionHandler as ActionHandlerHook],\n\t[\"SelectorRangeActionDefinition\", useSelectorRangeActionHandler as ActionHandlerHook],\n\n\t// CRUD (7)\n\t[\"RefreshActionDefinition\", useRefreshActionHandler as ActionHandlerHook],\n\t[\"CreateActionDefinition\", useCreateActionHandler as ActionHandlerHook],\n\t[\"UpdateActionDefinition\", useUpdateActionHandler as ActionHandlerHook],\n\t[\"DeleteActionDefinition\", useDeleteActionHandler as ActionHandlerHook],\n\t[\"BulkDeleteActionDefinition\", useBulkDeleteActionHandler as ActionHandlerHook],\n\t[\"RowDeleteActionDefinition\", useRowDeleteActionHandler as ActionHandlerHook],\n\t[\"GetTemplateActionDefinition\", useGetTemplateActionHandler as ActionHandlerHook],\n\n\t// Relation (8)\n\t[\"SetActionDefinition\", useSetActionHandler as ActionHandlerHook],\n\t[\"UnsetActionDefinition\", useUnsetActionHandler as ActionHandlerHook],\n\t[\"AddActionDefinition\", useAddActionHandler as ActionHandlerHook],\n\t[\"RemoveActionDefinition\", useRemoveActionHandler as ActionHandlerHook],\n\t[\"BulkRemoveActionDefinition\", useBulkRemoveActionHandler as ActionHandlerHook],\n\t[\"ClearActionDefinition\", useClearActionHandler as ActionHandlerHook],\n\t[\"RefreshRelationActionDefinition\", useRefreshRelationActionHandler as ActionHandlerHook],\n\t[\"FilterRelationActionDefinition\", useFilterRelationActionHandler as ActionHandlerHook],\n\n\t// Table (3)\n\t[\"FilterActionDefinition\", useFilterActionHandler as ActionHandlerHook],\n\t[\"ExportActionDefinition\", useExportActionHandler as ActionHandlerHook],\n\t[\"InlineCreateRowActionDefinition\", useInlineCreateRowActionHandler as ActionHandlerHook],\n\n\t// Operation (5)\n\t[\"BulkCallOperationActionDefinition\", useBulkCallOperationActionHandler as ActionHandlerHook],\n\t[\"CallOperationActionDefinition\", useCallOperationActionHandler as ActionHandlerHook],\n\t[\"InputFormCallOperationActionDefinition\", useInputFormCallOperationActionHandler as ActionHandlerHook],\n\t[\"InputSelectorCallOperationActionDefinition\", useInputSelectorCallOperationActionHandler as ActionHandlerHook],\n\t[\"ParameterlessCallOperationActionDefinition\", useParameterlessCallOperationActionHandler as ActionHandlerHook],\n\n\t// Autocomplete (3)\n\t[\"AutocompleteAddActionDefinition\", useAutocompleteAddActionHandler as ActionHandlerHook],\n\t[\"AutocompleteRangeActionDefinition\", useAutocompleteRangeActionHandler as ActionHandlerHook],\n\t[\"AutocompleteSetActionDefinition\", useAutocompleteSetActionHandler as ActionHandlerHook],\n\n\t// Other (2)\n\t[\"PreFetchActionDefinition\", usePreFetchActionHandler as ActionHandlerHook],\n\t[\"CustomActionDefinition\", useCustomActionHandler as ActionHandlerHook],\n]);\n\n/**\n * Get the handler for an action.\n * Returns the handler hook if found, undefined otherwise.\n */\nexport function getActionHandler(action: Action): ActionHandlerHook | undefined {\n\tconst actionType = action.actionDefinition[\"@type\"];\n\treturn BUILTIN_HANDLERS.get(actionType);\n}\n\n/**\n * Check if a handler exists for the given action.\n */\nexport function hasActionHandler(action: Action): boolean {\n\treturn getActionHandler(action) !== undefined;\n}\n","import type { ActionHandlerContext } from \"@judo/model-api\";\nimport type { ActionLifecycle } from \"@judo/model-api\";\nimport { useCallback, useMemo } from \"react\";\nimport type { JudoRestApi } from \"../api/judo-rest-api\";\nimport { executeWithLifecycle } from \"../lifecycle/execute-with-lifecycle\";\nimport { hasActionHandler as checkHandler, getActionHandler } from \"../registry/action-handler-registry\";\nimport type { Action, DataStore, TransferData, ModelRegistry, NavigationContext, NotificationService } from \"../types\";\n\n/**\n * Options for useActionDispatcher hook.\n */\nexport interface UseActionDispatcherOptions {\n\t/** Navigation context */\n\tnavigation: NavigationContext;\n\t/** Data store */\n\tdata: DataStore;\n\t/** Model registry */\n\tregistry: ModelRegistry;\n\t/** JUDO REST API client (optional - enables API-mode handlers) */\n\tapi?: JudoRestApi | null;\n\t/** Current transfer data */\n\ttransfer?: TransferData;\n\t/** Selected rows for bulk operations */\n\tselectedRows?: TransferData[];\n\t/** Dialog closer for form actions */\n\tcloseDialog?: () => void;\n\t/** Notification service for showing toasts */\n\tnotifications?: NotificationService;\n\t/** Additional context properties */\n\tadditionalContext?: Record<string, unknown>;\n\t/**\n\t * Resolved action lifecycle overrides for the current page.\n\t * Key: action sourceId, Value: lifecycle overrides.\n\t * Typically provided by PageActionOverridesProvider via useResolvedPageActionOverrides().\n\t */\n\tactionOverrides?: Record<string, Partial<ActionLifecycle>> | null;\n}\n\n/**\n * Result of useActionDispatcher hook.\n */\nexport interface UseActionDispatcherResult {\n\t/** Dispatch an action, optionally with context overrides */\n\tdispatch: (action: Action, contextOverrides?: Record<string, unknown>) => Promise<void>;\n\t/** Check if an action can be handled */\n\tcanHandle: (action: Action) => boolean;\n}\n\n/**\n * Hook for dispatching actions to registered handlers.\n * Uses hook factory pattern - handlers are resolved and called as hooks.\n *\n * @example\n * ```tsx\n * const { dispatch } = useActionDispatcher({\n * navigation,\n * data,\n * registry,\n * transfer: currentTransfer,\n * });\n *\n * const handleClick = async () => {\n * await dispatch(saveAction);\n * };\n * ```\n */\nexport function useActionDispatcher(options: UseActionDispatcherOptions): UseActionDispatcherResult {\n\tconst {\n\t\tnavigation,\n\t\tdata,\n\t\tregistry,\n\t\tapi,\n\t\ttransfer,\n\t\tselectedRows,\n\t\tcloseDialog,\n\t\tnotifications,\n\t\tadditionalContext,\n\t\tactionOverrides,\n\t} = options;\n\n\tconst context: ActionHandlerContext = useMemo(\n\t\t() =>\n\t\t\t({\n\t\t\t\tnavigation,\n\t\t\t\tdata,\n\t\t\t\tregistry,\n\t\t\t\tapi,\n\t\t\t\ttransfer,\n\t\t\t\tselectedRows,\n\t\t\t\tcloseDialog,\n\t\t\t\tnotifications,\n\t\t\t\t...additionalContext,\n\t\t\t}) as unknown as ActionHandlerContext,\n\t\t[navigation, data, registry, api, transfer, selectedRows, closeDialog, notifications, additionalContext]\n\t);\n\n\tconst canHandle = useCallback((action: Action): boolean => {\n\t\treturn checkHandler(action);\n\t}, []);\n\n\tconst dispatch = useCallback(\n\t\tasync (action: Action, contextOverrides?: Record<string, unknown>): Promise<void> => {\n\t\t\tconst handlerHook = getActionHandler(action);\n\n\t\t\tif (!handlerHook) {\n\t\t\t\tconst actionType = action.actionDefinition[\"@type\"];\n\t\t\t\tthrow new Error(`No handler for action type: ${actionType}`);\n\t\t\t}\n\n\t\t\t// Call the hook to get the handler function\n\t\t\tconst handlerFn = handlerHook(action);\n\n\t\t\t// Merge context with overrides\n\t\t\tconst mergedContext = contextOverrides ? ({ ...context, ...contextOverrides } as ActionHandlerContext) : context;\n\n\t\t\t// Check for lifecycle overrides\n\t\t\tconst actionSourceId = action[\"xmi:id\"];\n\t\t\tconst lifecycle = actionSourceId ? actionOverrides?.[actionSourceId] : undefined;\n\n\t\t\tif (lifecycle && Object.keys(lifecycle).length > 0) {\n\t\t\t\t// Execute with lifecycle composition\n\t\t\t\tawait executeWithLifecycle(handlerFn, lifecycle, mergedContext, action);\n\t\t\t} else {\n\t\t\t\t// No overrides — run default handler directly\n\t\t\t\tawait handlerFn(mergedContext);\n\t\t\t}\n\t\t},\n\t\t[context, actionOverrides]\n\t);\n\n\treturn { dispatch, canHandle };\n}\n","import type { Action, ActionHandlerFn } from \"@judo/model-api\";\nimport { useMemo } from \"react\";\nimport { hasActionHandler as checkHandler, getActionHandler } from \"../registry/action-handler-registry\";\n\n/**\n * Hook to get the handler for an action.\n *\n * @param action - The Action to get handler for\n * @returns Handler function to execute the action\n *\n * @example\n * ```tsx\n * function ActionButton({ action }: { action: Action }) {\n * const handler = useActionHandler(action);\n *\n * const handleClick = async () => {\n * await handler({ transfer: currentTransfer });\n * };\n *\n * return <Button onClick={handleClick}>{action.label}</Button>;\n * }\n * ```\n */\nexport function useActionHandler(action: Action): ActionHandlerFn {\n\tconst handler = useMemo(() => {\n\t\tconst handlerHook = getActionHandler(action);\n\n\t\tif (!handlerHook) {\n\t\t\tconst actionType = action.actionDefinition[\"@type\"];\n\t\t\tthrow new Error(`No handler for action type: ${actionType}`);\n\t\t}\n\n\t\t// Call the hook with the action to get the handler function\n\t\treturn handlerHook(action);\n\t}, [action]);\n\n\treturn handler;\n}\n\n/**\n * Check if a handler exists for the given action.\n *\n * @param action - The Action to check\n * @returns True if a handler exists\n */\nexport function hasActionHandler(action: Action): boolean {\n\treturn checkHandler(action);\n}\n","/**\n * JUDO REST API constants.\n * Based on REST_REQUEST_MAPPING_SPECIFICATION.md\n */\n\n// Header names\nexport const HEADER_SIGNED_IDENTIFIER = \"X-Judo-SignedIdentifier\";\nexport const HEADER_MASK = \"X-Judo-Mask\";\nexport const HEADER_MARK_SELECTED_RANGE_ITEMS = \"X-Judo-Mark-Selected-Range-Items\";\nexport const HEADER_COUNT_RECORDS = \"X-Judo-CountRecords\";\nexport const HEADER_TOKEN = \"X-Token\";\n\n// Default values\nexport const DEFAULT_COMMAND_MASK = \"{}\";\n\n// Path suffixes\nexport const SUFFIX_TEMPLATE = \"/~template\";\nexport const SUFFIX_GET = \"/~get\";\nexport const SUFFIX_UPDATE = \"/~update\";\nexport const SUFFIX_VALIDATE = \"/~validate\";\nexport const SUFFIX_DELETE = \"/~delete\";\nexport const SUFFIX_LIST = \"/~list\";\nexport const SUFFIX_RANGE = \"/~range\";\nexport const SUFFIX_CREATE = \"/~create\";\nexport const SUFFIX_SET = \"/~set\";\nexport const SUFFIX_UNSET = \"/~unset\";\nexport const SUFFIX_ADD = \"/~add\";\nexport const SUFFIX_REMOVE = \"/~remove\";\nexport const SUFFIX_EXPORT = \"/~export\";\nexport const SUFFIX_UPLOAD_TOKEN = \"/~upload-token\";\nexport const SUFFIX_PRINCIPAL = \"/~principal\";\nexport const SUFFIX_META = \"/~meta\";\n","/**\n * Path building utilities for JUDO REST API.\n * Based on REST_REQUEST_MAPPING_SPECIFICATION.md\n */\n\nimport type { ClassType, RelationType } from \"@judo/model-api\";\nimport type { Application } from \"../types\";\n\nconst SPLITTER = \"::\";\nconst TRANSFER_SKIP_SEGMENT = \"_default_transferobjecttypes\";\n\n/**\n * Builds a REST path for a class type with optional prefix/suffix for relation or operation names.\n *\n * @param classType - The class type containing packageNameTokens and simpleName\n * @param first - Prefix to add before the name (e.g., \"/\" for relations)\n * @param name - The relation or operation name (may contain ::)\n * @param second - Optional suffix (e.g., \"/~list\")\n * @returns The constructed path\n */\nfunction restPath(classType: ClassType, first: string, name: string, second?: string): string {\n\tconst suffix = `${first}${name ? name.split(SPLITTER).join(\"/\") : \"\"}${second ?? \"\"}`;\n\tconst packages = classType.packageNameTokens?.length ? `${classType.packageNameTokens.join(\"/\")}/` : \"\";\n\tconst simplePath = (classType.simpleName ?? \"\")\n\t\t.split(SPLITTER)\n\t\t.filter((i) => !i.includes(TRANSFER_SKIP_SEGMENT))\n\t\t.join(\"/\");\n\treturn `/${packages}${simplePath}${suffix}`;\n}\n\n/**\n * Builds a path with the application's model name prefix.\n *\n * @param application - The application context\n * @param path - Optional path to append\n * @returns The path prefixed with the model name (with leading slash for URL construction)\n * @throws Error if application is not provided\n */\nfunction getPathForApp(application: Application, path?: string): string {\n\tif (!application) {\n\t\tthrow new Error(\n\t\t\t\"Application context is required for path building. Ensure the API is properly initialized with an Application.\"\n\t\t);\n\t}\n\tconst tmp = path ? path : \"\";\n\treturn `/${application.modelName}${tmp.length && !tmp.startsWith(\"/\") ? `/${tmp}` : tmp}`;\n}\n\n/**\n * Builds the root path for the actor from the application.\n *\n * @param app - The application context\n * @returns The actor root path (e.g., \"admin/Admin\")\n * @throws Error if application or actor is not provided\n */\nfunction rootPathForApp(app: Application): string {\n\tif (!app?.actor) {\n\t\tthrow new Error(\n\t\t\t\"Application.actor is required for path building. Ensure the Application has a valid actor ClassType.\"\n\t\t);\n\t}\n\tconst packagePath = app.actor.packageNameTokens?.length ? `${app.actor.packageNameTokens.join(\"/\")}/` : \"\";\n\treturn `${packagePath}${app.actor.simpleName ?? app.actor.name ?? \"Actor\"}`;\n}\n\n/**\n * Builds a path for the actor with optional additional path segments.\n *\n * @param application - The application context\n * @param path - Optional path to append after the actor path\n * @returns The full path including model name and actor path\n */\nexport function getPathForActor(application: Application, path = \"\"): string {\n\treturn getPathForApp(\n\t\tapplication,\n\t\trootPathForApp(application) + (path.length && !path.startsWith(\"/\") ? `/${path}` : path)\n\t);\n}\n\n/**\n * Builds the REST path for a relation with a given suffix.\n *\n * @param relation - The relation type\n * @param application - The application context\n * @param suffix - The operation suffix (e.g., \"/~list\", \"/~get\", \"/~range\")\n * @returns The full path for the relation endpoint\n */\nexport function getRelationPath(relation: RelationType, application: Application, suffix = \"/~list\"): string {\n\treturn getPathForActor(application, restPath(relation?.eContainer as ClassType, \"/\", relation!.name, suffix));\n}\n\n/**\n * Builds the REST path for a class type with a given suffix.\n *\n * @param classType - The class type\n * @param application - The application context\n * @param suffix - The operation suffix (e.g., \"/~template\", \"/~get\", \"/~update\")\n * @returns The full path for the class endpoint\n */\nexport function getClassPath(classType: ClassType, application: Application, suffix = \"\"): string {\n\treturn getPathForActor(application, restPath(classType, \"\", \"\", suffix));\n}\n\n/**\n * Builds the REST path for a mutation relation operation (create, set, unset, add, remove).\n * These use the /~update/ prefix for non-access relations.\n *\n * @param relation - The relation type\n * @param application - The application context\n * @param suffix - The operation suffix (e.g., \"/~create\", \"/~set\")\n * @param isAccess - Whether this is an access relation (skips /~update/ prefix)\n * @returns The full path for the mutation endpoint\n */\nexport function getMutationRelationPath(\n\trelation: RelationType,\n\tapplication: Application,\n\tsuffix: string,\n\tisAccess = false\n): string {\n\tconst classType = relation?.eContainer as ClassType;\n\tif (isAccess) {\n\t\t// Access relations don't use /~update/ prefix\n\t\treturn getPathForActor(application, restPath(classType, \"/\", relation!.name, suffix));\n\t}\n\t// Regular relations: /{classPath}/~update/{relationName}{suffix}\n\treturn getPathForActor(application, restPath(classType, \"/~update/\", relation!.name, suffix));\n}\n\n/**\n * Builds the REST path for an operation.\n *\n * @param classType - The class type containing the operation\n * @param operationName - The operation name\n * @param application - The application context\n * @param suffix - Optional suffix (e.g., \"/~validate\", \"/~range\")\n * @returns The full path for the operation endpoint\n */\nexport function getOperationPath(\n\tclassType: ClassType,\n\toperationName: string,\n\tapplication: Application,\n\tsuffix = \"\"\n): string {\n\treturn getPathForActor(application, restPath(classType, \"/\", operationName, suffix));\n}\n","/**\n * JUDO REST API client implementation.\n * Based on REST_REQUEST_MAPPING_SPECIFICATION.md\n *\n * This module provides a complete REST client for the JUDO backend,\n * implementing all operations defined in the specification:\n * - Transfer operations (get, template, update, delete)\n * - Relation operations (list, get, range, create, set, unset, add, remove)\n * - Operation invocations\n * - Access service operations (principal, metadata, file operations)\n */\n\nimport type { ClassType, RelationType } from \"@judo/model-api\";\nimport type { Application } from \"../types\";\nimport {\n\tDEFAULT_COMMAND_MASK,\n\tHEADER_COUNT_RECORDS,\n\tHEADER_MARK_SELECTED_RANGE_ITEMS,\n\tHEADER_MASK,\n\tHEADER_SIGNED_IDENTIFIER,\n\tHEADER_TOKEN,\n\tSUFFIX_ADD,\n\tSUFFIX_CREATE,\n\tSUFFIX_DELETE,\n\tSUFFIX_EXPORT,\n\tSUFFIX_GET,\n\tSUFFIX_LIST,\n\tSUFFIX_META,\n\tSUFFIX_PRINCIPAL,\n\tSUFFIX_RANGE,\n\tSUFFIX_REMOVE,\n\tSUFFIX_SET,\n\tSUFFIX_TEMPLATE,\n\tSUFFIX_UNSET,\n\tSUFFIX_UPDATE,\n\tSUFFIX_UPLOAD_TOKEN,\n\tSUFFIX_VALIDATE,\n} from \"./constants\";\nimport {\n\tgetClassPath,\n\tgetMutationRelationPath,\n\tgetOperationPath,\n\tgetPathForActor,\n\tgetRelationPath,\n} from \"./path-builder\";\nimport type {\n\tTransferData,\n\tTransferDeserializer,\n\tTransferSerializer,\n\tTransferStored,\n\tJudoRestResponse,\n\tQueryCustomizer,\n\tRangeRequestBody,\n} from \"./types\";\n\n/**\n * Configuration for JUDO REST API client.\n */\nexport interface JudoRestApiConfig {\n\t/** Base URL for the API (e.g., http://localhost:8080) */\n\tbaseUrl: string;\n\t/** The application context containing model name and actor info */\n\tapplication: Application;\n\t/** Request timeout in milliseconds */\n\ttimeout?: number;\n\t/** Default headers to include in all requests */\n\tdefaultHeaders?: Record<string, string>;\n\t/** Optional custom fetch implementation */\n\tfetch?: typeof fetch;\n\t/** Optional request interceptor */\n\tonRequest?: (request: RequestInit) => RequestInit | Promise<RequestInit>;\n\t/** Optional response interceptor */\n\tonResponse?: (response: Response) => Response | Promise<Response>;\n\t/** Optional error handler */\n\tonError?: (error: Error) => void;\n\t/** Optional transfer serializer for transforming transfers before sending */\n\ttransferSerializer?: TransferSerializer;\n\t/** Optional transfer deserializer for transforming responses */\n\ttransferDeserializer?: TransferDeserializer;\n}\n\n/**\n * Operation metadata for invoking operations.\n */\nexport interface OperationInfo {\n\t/** Operation name */\n\tname: string;\n\t/** Whether the operation is static */\n\tisStatic?: boolean;\n\t/** Whether the operation is mapped */\n\tisMapped?: boolean;\n\t/** Whether the operation has input */\n\thasInput?: boolean;\n\t/** Input class type (for templates) */\n\tinputType?: ClassType;\n}\n\n/**\n * JUDO REST API client.\n * Implements all REST operations according to the specification.\n */\nexport class JudoRestApi {\n\tprivate readonly config: JudoRestApiConfig;\n\tprivate readonly fetchImpl: typeof fetch;\n\tprivate _defaultHeaders: Record<string, string>;\n\n\tconstructor(config: JudoRestApiConfig) {\n\t\tif (!config.application) {\n\t\t\tthrow new Error(\n\t\t\t\t\"JudoRestApi requires 'application' in config. Ensure the API is created with a valid Application context.\"\n\t\t\t);\n\t\t}\n\t\tif (!config.application.actor) {\n\t\t\tthrow new Error(\n\t\t\t\t\"JudoRestApi requires 'application.actor' in config. Ensure the Application has a valid actor ClassType.\"\n\t\t\t);\n\t\t}\n\t\tthis.config = config;\n\t\tthis.fetchImpl = config.fetch ?? globalThis.fetch.bind(globalThis);\n\t\tthis._defaultHeaders = { ...config.defaultHeaders };\n\t}\n\n\t/**\n\t * Update the default headers applied to every request.\n\t * Use this to set or remove the Authorization header when the auth token changes.\n\t */\n\tsetDefaultHeaders(headers: Record<string, string>): void {\n\t\tthis._defaultHeaders = headers;\n\t}\n\n\t/**\n\t * Gets the full URL for a path.\n\t */\n\tprivate getUrl(path: string): string {\n\t\treturn `${this.config.baseUrl}${path}`;\n\t}\n\n\t/**\n\t * Serializes an transfer for sending in request body.\n\t * Uses the configured transferSerializer if provided, otherwise returns the transfer as-is.\n\t */\n\tprivate serializeTransfer<T>(transfer: T): unknown {\n\t\tif (this.config.transferSerializer) {\n\t\t\treturn this.config.transferSerializer.serialize(transfer);\n\t\t}\n\t\treturn transfer;\n\t}\n\n\t/**\n\t * Deserializes response data into an transfer.\n\t * Uses the configured transferDeserializer if provided, otherwise returns the data as-is.\n\t */\n\tprivate deserializeTransfer<T>(data: unknown): T {\n\t\tif (this.config.transferDeserializer) {\n\t\t\treturn this.config.transferDeserializer.deserialize(data) as T;\n\t\t}\n\t\treturn data as T;\n\t}\n\n\t/**\n\t * Deserializes an array of transfers from response data.\n\t */\n\tprivate deserializeArray<T>(data: unknown): T[] {\n\t\tif (!Array.isArray(data)) {\n\t\t\treturn [];\n\t\t}\n\t\tif (this.config.transferDeserializer) {\n\t\t\treturn data.map((item) => this.config.transferDeserializer!.deserialize(item) as T);\n\t\t}\n\t\treturn data as T[];\n\t}\n\n\t/**\n\t * Makes a request with optional interceptors.\n\t */\n\tprivate async request<T>(\n\t\tmethod: \"GET\" | \"POST\",\n\t\tpath: string,\n\t\toptions: {\n\t\t\tbody?: unknown;\n\t\t\theaders?: Record<string, string>;\n\t\t\tresponseType?: \"json\" | \"blob\";\n\t\t} = {}\n\t): Promise<JudoRestResponse<T>> {\n\t\tconst url = this.getUrl(path);\n\t\tconst headers: Record<string, string> = {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t...this._defaultHeaders,\n\t\t\t...options.headers,\n\t\t};\n\n\t\tlet init: RequestInit = {\n\t\t\tmethod,\n\t\t\theaders,\n\t\t\tbody: options.body !== undefined ? JSON.stringify(options.body) : undefined,\n\t\t};\n\n\t\t// Apply request interceptor\n\t\tif (this.config.onRequest) {\n\t\t\tinit = await this.config.onRequest(init);\n\t\t}\n\n\t\ttry {\n\t\t\tlet response = await this.fetchImpl(url, init);\n\n\t\t\t// Apply response interceptor\n\t\t\tif (this.config.onResponse) {\n\t\t\t\tresponse = await this.config.onResponse(response);\n\t\t\t}\n\n\t\t\tif (!response.ok) {\n\t\t\t\t// Try to parse error response as JSON for validation errors\n\t\t\t\tconst errorText = await response.text();\n\n\t\t\t\t// Handle validation errors (400 status)\n\t\t\t\tif (response.status === 400 && errorText.length > 0) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst errorData = JSON.parse(errorText);\n\t\t\t\t\t\t// Check if it's a FeedbackItem array\n\t\t\t\t\t\tif (Array.isArray(errorData)) {\n\t\t\t\t\t\t\tconst { ValidationError } = await import(\"./types\");\n\t\t\t\t\t\t\tthrow new ValidationError(errorData);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (parseError) {\n\t\t\t\t\t\t// If not valid JSON or not FeedbackItem, fall through to generic error\n\t\t\t\t\t\tif (parseError instanceof Error && parseError.name === \"ValidationError\") {\n\t\t\t\t\t\t\tthrow parseError;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthrow new Error(`HTTP ${response.status}: ${errorText}`);\n\t\t\t}\n\n\t\t\tlet data: T;\n\t\t\tif (options.responseType === \"blob\") {\n\t\t\t\tdata = (await response.blob()) as T;\n\t\t\t} else {\n\t\t\t\tconst text = await response.text();\n\t\t\t\tdata = text.length > 0 ? JSON.parse(text) : (undefined as T);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tdata,\n\t\t\t\tstatus: response.status,\n\t\t\t\theaders: response.headers,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tif (this.config.onError) {\n\t\t\t\tthis.config.onError(error as Error);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t// ============================================\n\t// ENTITY OPERATIONS\n\t// ============================================\n\n\t/**\n\t * Gets a template (default values) for creating a new transfer.\n\t *\n\t * GET /{classPath}/~template\n\t */\n\tasync getTemplate(classType: ClassType): Promise<JudoRestResponse<TransferData>> {\n\t\tconst path = getClassPath(classType, this.config.application, SUFFIX_TEMPLATE);\n\t\tconst response = await this.request<TransferData>(\"GET\", path);\n\t\treturn { ...response, data: this.deserializeTransfer<TransferData>(response.data) };\n\t}\n\n\t/**\n\t * Refreshes (retrieves) an transfer by its signed identifier.\n\t *\n\t * POST /{classPath}/~get\n\t * Headers: X-Judo-SignedIdentifier\n\t */\n\tasync refresh(\n\t\tclassType: ClassType,\n\t\ttarget: TransferStored,\n\t\tqueryCustomizer?: QueryCustomizer\n\t): Promise<JudoRestResponse<TransferStored>> {\n\t\tconst path = getClassPath(classType, this.config.application, SUFFIX_GET);\n\t\tconst response = await this.request<TransferStored>(\"POST\", path, {\n\t\t\tbody: queryCustomizer ?? {},\n\t\t\theaders: {\n\t\t\t\t[HEADER_SIGNED_IDENTIFIER]: target.__signedIdentifier!,\n\t\t\t},\n\t\t});\n\t\treturn { ...response, data: this.deserializeTransfer<TransferStored>(response.data) };\n\t}\n\n\t/**\n\t * Updates an existing transfer.\n\t *\n\t * POST /{classPath}/~update\n\t * Headers: X-Judo-SignedIdentifier, X-Judo-Mask\n\t */\n\tasync update(classType: ClassType, target: TransferStored, mask?: string): Promise<JudoRestResponse<TransferStored>> {\n\t\tconst path = getClassPath(classType, this.config.application, SUFFIX_UPDATE);\n\t\tconst response = await this.request<TransferStored>(\"POST\", path, {\n\t\t\tbody: this.serializeTransfer(target),\n\t\t\theaders: {\n\t\t\t\t[HEADER_SIGNED_IDENTIFIER]: target.__signedIdentifier!,\n\t\t\t\t[HEADER_MASK]: mask ?? DEFAULT_COMMAND_MASK,\n\t\t\t},\n\t\t});\n\t\treturn { ...response, data: this.deserializeTransfer<TransferStored>(response.data) };\n\t}\n\n\t/**\n\t * Validates an transfer update without persisting.\n\t *\n\t * POST /{classPath}/~validate\n\t * Headers: X-Judo-SignedIdentifier\n\t */\n\tasync validateUpdate(classType: ClassType, target: TransferStored): Promise<JudoRestResponse<TransferStored>> {\n\t\tconst path = getClassPath(classType, this.config.application, SUFFIX_VALIDATE);\n\t\tconst response = await this.request<TransferStored>(\"POST\", path, {\n\t\t\tbody: this.serializeTransfer(target),\n\t\t\theaders: {\n\t\t\t\t[HEADER_SIGNED_IDENTIFIER]: target.__signedIdentifier!,\n\t\t\t},\n\t\t});\n\t\treturn { ...response, data: this.deserializeTransfer<TransferStored>(response.data) };\n\t}\n\n\t/**\n\t * Deletes an existing transfer.\n\t *\n\t * POST /{classPath}/~delete\n\t * Headers: X-Judo-SignedIdentifier\n\t */\n\tasync delete(classType: ClassType, target: TransferStored): Promise<JudoRestResponse<void>> {\n\t\tconst path = getClassPath(classType, this.config.application, SUFFIX_DELETE);\n\t\treturn this.request<void>(\"POST\", path, {\n\t\t\theaders: {\n\t\t\t\t[HEADER_SIGNED_IDENTIFIER]: target.__signedIdentifier!,\n\t\t\t},\n\t\t});\n\t}\n\n\t// ============================================\n\t// RELATION OPERATIONS\n\t// ============================================\n\n\t/**\n\t * Lists transfers in a collection relation.\n\t *\n\t * POST /{ownerClassPath}/{relationName}/~list\n\t * Headers: X-Judo-SignedIdentifier (if owner provided), X-Judo-CountRecords (if countRecords true)\n\t */\n\tasync listRelation(\n\t\trelation: RelationType,\n\t\towner?: TransferStored,\n\t\tqueryCustomizer?: QueryCustomizer,\n\t\tcountRecords?: boolean\n\t): Promise<JudoRestResponse<TransferStored[]>> {\n\t\tconst path = getRelationPath(relation, this.config.application, SUFFIX_LIST);\n\t\tconst headers: Record<string, string> = {};\n\n\t\tif (owner?.__signedIdentifier) {\n\t\t\theaders[HEADER_SIGNED_IDENTIFIER] = owner.__signedIdentifier;\n\t\t}\n\n\t\tif (countRecords) {\n\t\t\theaders[HEADER_COUNT_RECORDS] = \"true\";\n\t\t}\n\n\t\tconst response = await this.request<TransferStored[]>(\"POST\", path, {\n\t\t\tbody: queryCustomizer ?? {},\n\t\t\theaders,\n\t\t});\n\t\treturn { ...response, data: this.deserializeArray<TransferStored>(response.data) };\n\t}\n\n\t/**\n\t * Gets a single transfer from a non-collection relation.\n\t *\n\t * POST /{ownerClassPath}/{relationName}/~get\n\t * Headers: X-Judo-SignedIdentifier\n\t */\n\tasync getRelation(\n\t\trelation: RelationType,\n\t\towner: TransferStored,\n\t\tqueryCustomizer?: QueryCustomizer\n\t): Promise<JudoRestResponse<TransferStored | null>> {\n\t\tconst path = getRelationPath(relation, this.config.application, SUFFIX_GET);\n\t\tconst response = await this.request<TransferStored | undefined>(\"POST\", path, {\n\t\t\tbody: queryCustomizer ?? {},\n\t\t\theaders: {\n\t\t\t\t[HEADER_SIGNED_IDENTIFIER]: owner.__signedIdentifier!,\n\t\t\t},\n\t\t});\n\n\t\t// Handle null/empty/undefined response (nullable deserialization)\n\t\tconst data =\n\t\t\tresponse.data === undefined || response.data === null\n\t\t\t\t? null\n\t\t\t\t: this.deserializeTransfer<TransferStored>(response.data);\n\n\t\treturn { ...response, data };\n\t}\n\n\t/**\n\t * Refreshes a non-collection access relation directly.\n\t *\n\t * POST /{ownerClassPath}/{relationName}/~get\n\t * No owner header (access relation)\n\t */\n\tasync refreshAccessRelation(\n\t\trelation: RelationType,\n\t\tqueryCustomizer?: QueryCustomizer\n\t): Promise<JudoRestResponse<TransferStored>> {\n\t\tconst path = getRelationPath(relation, this.config.application, SUFFIX_GET);\n\t\tconst response = await this.request<TransferStored>(\"POST\", path, {\n\t\t\tbody: queryCustomizer ?? {},\n\t\t});\n\t\treturn { ...response, data: this.deserializeTransfer<TransferStored>(response.data) };\n\t}\n\n\t/**\n\t * Gets the available range of transfers for a relation.\n\t *\n\t * POST /{ownerClassPath}/{relationName}/~range\n\t * Headers: X-Judo-Mark-Selected-Range-Items\n\t */\n\tasync getRelationRange(\n\t\trelation: RelationType,\n\t\towner?: TransferStored,\n\t\tqueryCustomizer?: QueryCustomizer,\n\t\tcountRecords?: boolean\n\t): Promise<JudoRestResponse<TransferStored[]>> {\n\t\tconst path = getRelationPath(relation, this.config.application, SUFFIX_RANGE);\n\t\tconst body: RangeRequestBody = {\n\t\t\towner: owner ?? {},\n\t\t\tqueryCustomizer: queryCustomizer ?? {},\n\t\t};\n\n\t\tconst headers: Record<string, string> = {\n\t\t\t[HEADER_MARK_SELECTED_RANGE_ITEMS]: \"true\",\n\t\t};\n\n\t\tif (countRecords) {\n\t\t\theaders[HEADER_COUNT_RECORDS] = \"true\";\n\t\t}\n\n\t\tconst response = await this.request<TransferStored[]>(\"POST\", path, {\n\t\t\tbody,\n\t\t\theaders,\n\t\t});\n\t\treturn { ...response, data: this.deserializeArray<TransferStored>(response.data) };\n\t}\n\n\t/**\n\t * Gets template for relation target.\n\t *\n\t * GET /{targetClassPath}/~template\n\t */\n\tasync getRelationTemplate(relation: RelationType): Promise<JudoRestResponse<TransferData>> {\n\t\tconst path = getClassPath(relation.target as ClassType, this.config.application, SUFFIX_TEMPLATE);\n\t\tconst response = await this.request<TransferData>(\"GET\", path);\n\t\treturn { ...response, data: this.deserializeTransfer<TransferData>(response.data) };\n\t}\n\n\t/**\n\t * Creates a new transfer through a relation.\n\t *\n\t * Non-access: POST /{ownerClassPath}/~update/{relationName}/~create\n\t * Access: POST /{ownerClassPath}/{relationName}/~create\n\t */\n\tasync createRelation(\n\t\trelation: RelationType,\n\t\towner: TransferStored | undefined,\n\t\tdata: TransferData,\n\t\tmask?: string\n\t): Promise<JudoRestResponse<TransferStored>> {\n\t\tconst isAccess = relation.isAccess;\n\t\tconst path = isAccess\n\t\t\t? getRelationPath(relation, this.config.application, SUFFIX_CREATE)\n\t\t\t: getMutationRelationPath(relation, this.config.application, SUFFIX_CREATE);\n\n\t\tconst headers: Record<string, string> = {\n\t\t\t[HEADER_MASK]: mask ?? DEFAULT_COMMAND_MASK,\n\t\t};\n\n\t\tif (!isAccess && owner?.__signedIdentifier) {\n\t\t\theaders[HEADER_SIGNED_IDENTIFIER] = owner.__signedIdentifier;\n\t\t}\n\n\t\tconst response = await this.request<TransferStored>(\"POST\", path, {\n\t\t\tbody: this.serializeTransfer(data),\n\t\t\theaders,\n\t\t});\n\t\treturn { ...response, data: this.deserializeTransfer<TransferStored>(response.data) };\n\t}\n\n\t/**\n\t * Validates creation through a relation.\n\t *\n\t * Non-access: POST /{ownerClassPath}/~update/{relationName}/~validate\n\t * Access: POST /{ownerClassPath}/{relationName}/~validate\n\t */\n\tasync validateCreateRelation(\n\t\trelation: RelationType,\n\t\towner: TransferStored | undefined,\n\t\tdata: TransferData\n\t): Promise<JudoRestResponse<TransferData>> {\n\t\tconst isAccess = relation.isAccess;\n\t\tconst path = isAccess\n\t\t\t? getRelationPath(relation, this.config.application, SUFFIX_VALIDATE)\n\t\t\t: getMutationRelationPath(relation, this.config.application, SUFFIX_VALIDATE);\n\n\t\tconst headers: Record<string, string> = {};\n\n\t\tif (!isAccess && owner?.__signedIdentifier) {\n\t\t\theaders[HEADER_SIGNED_IDENTIFIER] = owner.__signedIdentifier;\n\t\t}\n\n\t\tconst response = await this.request<TransferData>(\"POST\", path, {\n\t\t\tbody: this.serializeTransfer(data),\n\t\t\theaders,\n\t\t});\n\t\treturn { ...response, data: this.deserializeTransfer<TransferData>(response.data) };\n\t}\n\n\t/**\n\t * Sets a relation to point to specific transfer/transfers.\n\t *\n\t * POST /{ownerClassPath}/~update/{relationName}/~set\n\t * Headers: X-Judo-SignedIdentifier (non-access only)\n\t */\n\tasync setRelation(\n\t\trelation: RelationType,\n\t\towner: TransferStored,\n\t\tselected: TransferStored | TransferStored[]\n\t): Promise<JudoRestResponse<void>> {\n\t\tconst isAccess = relation.isAccess;\n\t\tconst path = getMutationRelationPath(relation, this.config.application, SUFFIX_SET, isAccess);\n\t\tconst headers: Record<string, string> = {};\n\n\t\tif (!isAccess) {\n\t\t\theaders[HEADER_SIGNED_IDENTIFIER] = owner.__signedIdentifier!;\n\t\t}\n\n\t\t// Serialize single or array based on what's passed\n\t\tconst body = Array.isArray(selected)\n\t\t\t? selected.map((s) => this.serializeTransfer(s))\n\t\t\t: this.serializeTransfer(selected);\n\n\t\treturn this.request<void>(\"POST\", path, {\n\t\t\tbody,\n\t\t\theaders,\n\t\t});\n\t}\n\n\t/**\n\t * Clears a relation (sets to null/empty).\n\t *\n\t * POST /{ownerClassPath}/~update/{relationName}/~unset\n\t * Headers: X-Judo-SignedIdentifier (non-access only)\n\t */\n\tasync unsetRelation(relation: RelationType, owner: TransferStored): Promise<JudoRestResponse<void>> {\n\t\tconst isAccess = relation.isAccess;\n\t\tconst path = getMutationRelationPath(relation, this.config.application, SUFFIX_UNSET, isAccess);\n\t\tconst headers: Record<string, string> = {};\n\n\t\tif (!isAccess) {\n\t\t\theaders[HEADER_SIGNED_IDENTIFIER] = owner.__signedIdentifier!;\n\t\t}\n\n\t\treturn this.request<void>(\"POST\", path, {\n\t\t\theaders,\n\t\t});\n\t}\n\n\t/**\n\t * Adds transfers to a collection relation.\n\t *\n\t * POST /{ownerClassPath}/~update/{relationName}/~add\n\t * Headers: X-Judo-SignedIdentifier (non-access only)\n\t */\n\tasync addToRelation(\n\t\trelation: RelationType,\n\t\towner: TransferStored,\n\t\tselected: TransferStored[]\n\t): Promise<JudoRestResponse<void>> {\n\t\tconst isAccess = relation.isAccess;\n\t\tconst path = getMutationRelationPath(relation, this.config.application, SUFFIX_ADD, isAccess);\n\t\tconst headers: Record<string, string> = {};\n\n\t\tif (!isAccess) {\n\t\t\theaders[HEADER_SIGNED_IDENTIFIER] = owner.__signedIdentifier!;\n\t\t}\n\n\t\treturn this.request<void>(\"POST\", path, {\n\t\t\tbody: selected.map((s) => this.serializeTransfer(s)),\n\t\t\theaders,\n\t\t});\n\t}\n\n\t/**\n\t * Removes transfers from a collection relation.\n\t *\n\t * POST /{ownerClassPath}/~update/{relationName}/~remove\n\t * Headers: X-Judo-SignedIdentifier (non-access only)\n\t */\n\tasync removeFromRelation(\n\t\trelation: RelationType,\n\t\towner: TransferStored,\n\t\tselected: TransferStored[]\n\t): Promise<JudoRestResponse<void>> {\n\t\tconst isAccess = relation.isAccess;\n\t\tconst path = getMutationRelationPath(relation, this.config.application, SUFFIX_REMOVE, isAccess);\n\t\tconst headers: Record<string, string> = {};\n\n\t\tif (!isAccess) {\n\t\t\theaders[HEADER_SIGNED_IDENTIFIER] = owner.__signedIdentifier!;\n\t\t}\n\n\t\treturn this.request<void>(\"POST\", path, {\n\t\t\tbody: selected.map((s) => this.serializeTransfer(s)),\n\t\t\theaders,\n\t\t});\n\t}\n\n\t/**\n\t * Exports relation data as a file (CSV/Excel).\n\t *\n\t * POST /{ownerClassPath}/{relationName}/~export\n\t * Headers: X-Judo-SignedIdentifier (if owner provided)\n\t */\n\tasync exportRelation(\n\t\trelation: RelationType,\n\t\towner?: TransferStored,\n\t\tqueryCustomizer?: QueryCustomizer\n\t): Promise<JudoRestResponse<Blob>> {\n\t\tconst path = getRelationPath(relation, this.config.application, SUFFIX_EXPORT);\n\t\tconst headers: Record<string, string> = {};\n\n\t\tif (owner?.__signedIdentifier) {\n\t\t\theaders[HEADER_SIGNED_IDENTIFIER] = owner.__signedIdentifier;\n\t\t}\n\n\t\treturn this.request<Blob>(\"POST\", path, {\n\t\t\tbody: queryCustomizer ?? {},\n\t\t\theaders,\n\t\t\tresponseType: \"blob\",\n\t\t});\n\t}\n\n\t// ============================================\n\t// OPERATION INVOCATIONS\n\t// ============================================\n\n\t/**\n\t * Invokes an operation on an transfer.\n\t *\n\t * POST /{classPath}/{operationName}\n\t * Headers: X-Judo-SignedIdentifier (if mapped/non-static)\n\t */\n\tasync invokeOperation<TInput = unknown, TOutput = unknown>(\n\t\tclassType: ClassType,\n\t\toperation: OperationInfo,\n\t\towner?: TransferStored,\n\t\tinput?: TInput\n\t): Promise<JudoRestResponse<TOutput | undefined>> {\n\t\tconst path = getOperationPath(classType, operation.name, this.config.application);\n\t\tconst headers: Record<string, string> = {};\n\n\t\tif (operation.isMapped && !operation.isStatic && owner?.__signedIdentifier) {\n\t\t\theaders[HEADER_SIGNED_IDENTIFIER] = owner.__signedIdentifier;\n\t\t}\n\n\t\tconst response = await this.request<TOutput | undefined>(\"POST\", path, {\n\t\t\tbody: operation.hasInput ? this.serializeTransfer(input) : undefined,\n\t\t\theaders,\n\t\t});\n\n\t\t// Deserialize output if present\n\t\tif (response.data !== undefined && response.data !== null) {\n\t\t\treturn { ...response, data: this.deserializeTransfer<TOutput>(response.data) };\n\t\t}\n\t\treturn response;\n\t}\n\n\t/**\n\t * Validates operation input without execution.\n\t *\n\t * POST /{classPath}/{operationName}/~validate\n\t * Headers: X-Judo-SignedIdentifier (if mapped/non-static)\n\t */\n\tasync validateOperationInput<TInput = unknown>(\n\t\tclassType: ClassType,\n\t\toperation: OperationInfo,\n\t\towner?: TransferStored,\n\t\tinput?: TInput\n\t): Promise<JudoRestResponse<TInput>> {\n\t\tconst path = getOperationPath(classType, operation.name, this.config.application, SUFFIX_VALIDATE);\n\t\tconst headers: Record<string, string> = {};\n\n\t\tif (operation.isMapped && !operation.isStatic && owner?.__signedIdentifier) {\n\t\t\theaders[HEADER_SIGNED_IDENTIFIER] = owner.__signedIdentifier;\n\t\t}\n\n\t\tconst response = await this.request<TInput>(\"POST\", path, {\n\t\t\tbody: this.serializeTransfer(input),\n\t\t\theaders,\n\t\t});\n\t\treturn { ...response, data: this.deserializeTransfer<TInput>(response.data) };\n\t}\n\n\t/**\n\t * Gets template for operation input.\n\t *\n\t * GET /{inputClassPath}/~template\n\t */\n\tasync getOperationInputTemplate(operation: OperationInfo): Promise<JudoRestResponse<TransferData>> {\n\t\tif (!operation.inputType) {\n\t\t\tthrow new Error(`Operation ${operation.name} has no input type`);\n\t\t}\n\t\tconst path = getClassPath(operation.inputType, this.config.application, SUFFIX_TEMPLATE);\n\t\tconst response = await this.request<TransferData>(\"GET\", path);\n\t\treturn { ...response, data: this.deserializeTransfer<TransferData>(response.data) };\n\t}\n\n\t/**\n\t * Gets range for operation input (selector operations).\n\t *\n\t * POST /{classPath}/{operationName}/~range\n\t * Headers: X-Judo-Mark-Selected-Range-Items\n\t */\n\tasync getOperationInputRange(\n\t\tclassType: ClassType,\n\t\toperation: OperationInfo,\n\t\towner?: TransferStored,\n\t\tqueryCustomizer?: QueryCustomizer,\n\t\tcountRecords?: boolean\n\t): Promise<JudoRestResponse<TransferStored[]>> {\n\t\tconst path = getOperationPath(classType, operation.name, this.config.application, SUFFIX_RANGE);\n\t\tconst body: RangeRequestBody = {\n\t\t\towner: owner ?? {},\n\t\t\tqueryCustomizer: queryCustomizer ?? {},\n\t\t};\n\n\t\tconst headers: Record<string, string> = {\n\t\t\t[HEADER_MARK_SELECTED_RANGE_ITEMS]: \"true\",\n\t\t};\n\n\t\tif (countRecords) {\n\t\t\theaders[HEADER_COUNT_RECORDS] = \"true\";\n\t\t}\n\n\t\tconst response = await this.request<TransferStored[]>(\"POST\", path, {\n\t\t\tbody,\n\t\t\theaders,\n\t\t});\n\t\treturn { ...response, data: this.deserializeArray<TransferStored>(response.data) };\n\t}\n\n\t// ============================================\n\t// ACCESS SERVICE OPERATIONS\n\t// ============================================\n\n\t/**\n\t * Gets the current authenticated user's principal data.\n\t *\n\t * GET /{actorPath}/~principal\n\t */\n\tasync getPrincipal(): Promise<JudoRestResponse<TransferStored>> {\n\t\tconst path = getPathForActor(this.config.application, SUFFIX_PRINCIPAL);\n\t\tconst response = await this.request<TransferStored>(\"GET\", path);\n\t\treturn { ...response, data: this.deserializeTransfer<TransferStored>(response.data) };\n\t}\n\n\t/**\n\t * Gets application metadata.\n\t *\n\t * GET /{actorPath}/~meta\n\t */\n\tasync getMetadata(): Promise<JudoRestResponse<unknown>> {\n\t\tconst path = getPathForActor(this.config.application, SUFFIX_META);\n\t\treturn this.request<unknown>(\"GET\", path);\n\t}\n\n\t/**\n\t * Uploads a file to a binary attribute.\n\t *\n\t * 1. POST {attributePath}/~upload-token to get token\n\t * 2. POST /upload with token and file\n\t */\n\tasync uploadFile(attributePath: string, file: File): Promise<JudoRestResponse<unknown>> {\n\t\t// Step 1: Get upload token\n\t\tconst tokenResponse = await this.request<{ token: string }>(\"POST\", `${attributePath}${SUFFIX_UPLOAD_TOKEN}`);\n\t\tconst token = tokenResponse.data.token;\n\n\t\t// Step 2: Upload file\n\t\tconst formData = new FormData();\n\t\tformData.append(\"file\", file);\n\n\t\tconst url = `${this.config.baseUrl}/upload`;\n\t\tconst response = await this.fetchImpl(url, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t...this._defaultHeaders,\n\t\t\t\t[HEADER_TOKEN]: token,\n\t\t\t},\n\t\t\tbody: formData,\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`Upload failed: HTTP ${response.status}`);\n\t\t}\n\n\t\treturn {\n\t\t\tdata: await response.json(),\n\t\t\tstatus: response.status,\n\t\t\theaders: response.headers,\n\t\t};\n\t}\n\n\t/**\n\t * Downloads a file from a binary attribute.\n\t *\n\t * GET /download?disposition={disposition}\n\t * Headers: X-Token\n\t */\n\tasync downloadFile(\n\t\tdownloadToken: string,\n\t\tdisposition: \"inline\" | \"attachment\" = \"attachment\"\n\t): Promise<JudoRestResponse<Blob>> {\n\t\tconst url = `${this.config.baseUrl}/download?disposition=${disposition}`;\n\t\tconst response = await this.fetchImpl(url, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: {\n\t\t\t\t...this._defaultHeaders,\n\t\t\t\t[HEADER_TOKEN]: downloadToken,\n\t\t\t},\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`Download failed: HTTP ${response.status}`);\n\t\t}\n\n\t\treturn {\n\t\t\tdata: await response.blob(),\n\t\t\tstatus: response.status,\n\t\t\theaders: response.headers,\n\t\t};\n\t}\n\n\t/**\n\t * Finds a specific transfer instance from an access relation by identifier.\n\t *\n\t * POST /{ownerClassPath}/{relationName}/~list\n\t * Body: { _identifier, _mask?, _seek: { limit: 1 } }\n\t */\n\tasync findInstance(\n\t\trelation: RelationType,\n\t\tidentifier: string,\n\t\tmask?: string\n\t): Promise<JudoRestResponse<TransferStored | null>> {\n\t\tconst path = getRelationPath(relation, this.config.application, SUFFIX_LIST);\n\t\tconst body: QueryCustomizer = {\n\t\t\t_identifier: identifier,\n\t\t\t_seek: { limit: 1 },\n\t\t};\n\n\t\tif (mask) {\n\t\t\tbody._mask = mask;\n\t\t}\n\n\t\tconst response = await this.request<TransferStored[]>(\"POST\", path, { body });\n\n\t\t// Return first item (deserialized) or null\n\t\tconst items = this.deserializeArray<TransferStored>(response.data);\n\t\tconst data = items.length > 0 ? items[0] : null;\n\t\treturn { ...response, data };\n\t}\n}\n\n/**\n * Factory function to create a JUDO REST API client.\n */\nexport function createJudoRestApi(config: JudoRestApiConfig): JudoRestApi {\n\treturn new JudoRestApi(config);\n}\n","/**\n * Default transfer serializer for JUDO REST API.\n *\n * Strips properties that should not be sent to the API:\n *\n * ## Backend-Provided Properties (read-only, never send back)\n * These properties are provided by the backend when retrieving transfers.\n * The frontend must NOT create or mutate these - they are server-managed:\n *\n * - `__identifier`: Backend-assigned transfer identifier\n * - `__signedIdentifier`: Signed token for transfer operations (exception: IS sent)\n * - `__entityType`: Backend type information\n * - `__deleteable`: Permission flag from backend\n * - `__updateable`: Permission flag from backend\n * - `__version`: Optimistic locking version\n *\n * ## Frontend-Only Properties (client-side state, never serialize)\n * These are created by the frontend for local state management:\n *\n * - `__isNew`: Marker for locally-created transfers not yet persisted\n * - `__items`: Array of related transfers for eager table state\n * - `__tempId`: Temporary client-side ID for tracking new transfers\n *\n * The only preserved `__*` property is `__signedIdentifier`, which is required\n * by the API for transfer operations.\n */\n\nimport type { TemporalFieldRegistry, TemporalFieldType, TransferData, TransferSerializer } from \"./types\";\n\n/**\n * Properties provided by the backend that should not be sent in requests.\n * These are read-only metadata assigned by the server.\n */\nexport const BACKEND_PROPERTIES = new Set<string>([\n\t\"__identifier\",\n\t\"__entityType\",\n\t\"__deleteable\",\n\t\"__updateable\",\n\t\"__version\",\n]);\n\n/**\n * Properties created by the frontend for local state management.\n * These should never be serialized to the API.\n */\nexport const FRONTEND_PROPERTIES = new Set<string>([\"__isNew\", \"__items\", \"__tempId\"]);\n\n/**\n * Combined set of all internal properties that should not be serialized.\n */\nexport const INTERNAL_PROPERTIES = new Set<string>([...BACKEND_PROPERTIES, ...FRONTEND_PROPERTIES]);\n\n/**\n * Check if a property is internal and should be stripped from serialization.\n * A property is internal if:\n * 1. It's in the INTERNAL_PROPERTIES set, OR\n * 2. It starts with `__` but is NOT `__signedIdentifier`\n *\n * @param key - Property name to check\n * @returns true if the property should be stripped\n */\nexport function isInternalProperty(key: string): boolean {\n\t// Always allow __signedIdentifier - it's required by the API\n\tif (key === \"__signedIdentifier\") {\n\t\treturn false;\n\t}\n\n\t// Check explicit internal properties\n\tif (INTERNAL_PROPERTIES.has(key)) {\n\t\treturn true;\n\t}\n\n\t// Any other double-underscore prefix is internal\n\treturn key.startsWith(\"__\");\n}\n\n/**\n * Strip internal properties from an transfer.\n * Creates a new object with only non-internal properties.\n *\n * @param transfer - Transfer to clean\n * @returns New object without internal properties\n */\nexport function stripInternalProperties<T extends TransferData>(transfer: T): Partial<T> {\n\tconst result: Partial<T> = {};\n\n\tfor (const [key, value] of Object.entries(transfer)) {\n\t\tif (!isInternalProperty(key)) {\n\t\t\t(result as TransferData)[key] = value;\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Default transfer serializer that strips internal properties.\n * Use this when configuring JudoRestApi to ensure internal metadata\n * is not sent to the server.\n *\n * @example\n * ```typescript\n * const api = new JudoRestApi({\n * baseUrl: 'http://localhost:8080',\n * basePath: '/api',\n * modelName: 'myapp',\n * actorPath: 'admin/Admin',\n * transferSerializer: defaultTransferSerializer,\n * });\n * ```\n */\nexport const defaultTransferSerializer: TransferSerializer = {\n\tserialize(transfer: unknown): unknown {\n\t\tif (transfer === null || transfer === undefined) {\n\t\t\treturn transfer;\n\t\t}\n\n\t\tif (typeof transfer !== \"object\") {\n\t\t\treturn transfer;\n\t\t}\n\n\t\tif (Array.isArray(transfer)) {\n\t\t\treturn transfer.map((item) => this.serialize(item));\n\t\t}\n\n\t\treturn stripInternalProperties(transfer as TransferData);\n\t},\n};\n\n// ============================================\n// Model-Aware Serializer\n// ============================================\n\n/**\n * Serialize a `Date` value to its wire format based on temporal field type.\n *\n * - `date` → `\"YYYY-MM-DD\"` using **local** date components (avoids timezone shift)\n * - `timestamp` → full ISO 8601 UTC string via `Date.toISOString()`\n * - `time` → `\"HH:mm:ss\"` using local time components\n *\n * @param date - The `Date` to serialize\n * @param fieldType - The temporal field classification\n * @returns Formatted string for the API wire format\n */\nexport function serializeTemporalValue(date: Date, fieldType: TemporalFieldType): string {\n\tswitch (fieldType) {\n\t\tcase \"date\": {\n\t\t\tconst y = date.getFullYear();\n\t\t\tconst m = String(date.getMonth() + 1).padStart(2, \"0\");\n\t\t\tconst d = String(date.getDate()).padStart(2, \"0\");\n\t\t\treturn `${y}-${m}-${d}`;\n\t\t}\n\t\tcase \"timestamp\":\n\t\t\treturn date.toISOString();\n\t\tcase \"time\": {\n\t\t\tconst h = String(date.getHours()).padStart(2, \"0\");\n\t\t\tconst mi = String(date.getMinutes()).padStart(2, \"0\");\n\t\t\tconst s = String(date.getSeconds()).padStart(2, \"0\");\n\t\t\treturn `${h}:${mi}:${s}`;\n\t\t}\n\t}\n}\n\n/**\n * Create a model-aware transfer serializer that converts `Date` objects to\n * the appropriate wire format **and** strips internal `__*` properties.\n *\n * Uses `__entityType` from the transfer (before stripping) to look up\n * the field type in the registry and format `Date` values accordingly.\n * Falls back to `Date.toISOString()` for `Date` values on unregistered fields.\n *\n * @param registry - Mapping of entity type FQNs to temporal field declarations\n * @returns `TransferSerializer` that handles Date→string conversion and property stripping\n *\n * @example\n * ```typescript\n * import { temporalFieldRegistry } from './generated/transfers/_registry';\n *\n * const api = createJudoRestApi({\n * // ...\n * transferSerializer: createModelAwareSerializer(temporalFieldRegistry),\n * });\n * ```\n */\nexport function createModelAwareSerializer(registry: TemporalFieldRegistry): TransferSerializer {\n\treturn {\n\t\tserialize(transfer: unknown): unknown {\n\t\t\tif (transfer == null) return transfer;\n\t\t\tif (typeof transfer !== \"object\") return transfer;\n\t\t\tif (Array.isArray(transfer)) return transfer.map((item) => this.serialize(item));\n\n\t\t\tconst obj = transfer as Record<string, unknown>;\n\t\t\tconst entityType = obj.__entityType as string | undefined;\n\t\t\tconst temporalFields = entityType ? registry[entityType] : undefined;\n\t\t\tconst result: Record<string, unknown> = {};\n\n\t\t\tfor (const [key, value] of Object.entries(obj)) {\n\t\t\t\tif (isInternalProperty(key)) continue;\n\n\t\t\t\tif (value instanceof Date) {\n\t\t\t\t\tconst fieldType = temporalFields?.[key];\n\t\t\t\t\tresult[key] = fieldType ? serializeTemporalValue(value, fieldType) : value.toISOString();\n\t\t\t\t} else if (value != null && typeof value === \"object\") {\n\t\t\t\t\tresult[key] = this.serialize(value);\n\t\t\t\t} else {\n\t\t\t\t\tresult[key] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t},\n\t};\n}\n","/**\n * Model-aware transfer deserializer for JUDO REST API.\n *\n * Converts temporal field values from their wire format (ISO strings) to\n * native JavaScript `Date` objects at the API boundary. This eliminates\n * the need for developers to handle date parsing, timezone conversion,\n * and format differences.\n *\n * ## Supported conversions\n *\n * | Field type | Wire format (string) | Runtime type |\n * | ------------- | -------------------------------- | ------------------------- |\n * | `date` | `\"YYYY-MM-DD\"` | `Date` (local midnight) |\n * | `timestamp` | `\"YYYY-MM-DDTHH:mm:ss[.SSS]Z\"` | `Date` (UTC) |\n * | `time` | `\"HH:mm[:ss]\"` | `string` (pass-through) |\n *\n * ## How it works\n *\n * The deserializer reads `__entityType` from each response payload to look up\n * the transfer type in the provided {@link TemporalFieldRegistry}. Fields\n * declared as `date` or `timestamp` are converted from ISO strings to `Date`\n * objects. Nested objects and arrays are processed recursively.\n */\n\nimport type { TemporalFieldRegistry, TemporalFieldType, TransferDeserializer } from \"./types\";\n\n/**\n * Parse a date-only string (`YYYY-MM-DD`) as a local-timezone `Date`.\n *\n * Avoids the timezone-shift problem of `new Date(\"YYYY-MM-DD\")` which creates\n * a UTC midnight `Date` — displaying as the previous day in negative-offset timezones.\n *\n * @param value - Date string in `YYYY-MM-DD` format\n * @returns `Date` at local midnight, or invalid `Date` if parsing fails\n */\nexport function parseLocalDate(value: string): Date {\n\tconst parts = value.split(\"-\");\n\tif (parts.length !== 3) return new Date(Number.NaN);\n\tconst [y, m, d] = parts.map(Number);\n\treturn new Date(y, m - 1, d);\n}\n\n/**\n * Deserialize a temporal string value to its runtime representation.\n *\n * - `date` → local-midnight `Date` via {@link parseLocalDate}\n * - `timestamp` → `Date` via `new Date(isoString)`\n * - `time` → original string (pass-through)\n *\n * @param value - The string value from the API response\n * @param fieldType - The temporal field type\n * @returns `Date` for `date`/`timestamp`, original string for `time`\n */\nexport function deserializeTemporalValue(value: string, fieldType: TemporalFieldType): Date | string {\n\tswitch (fieldType) {\n\t\tcase \"date\":\n\t\t\treturn parseLocalDate(value);\n\t\tcase \"timestamp\":\n\t\t\treturn new Date(value);\n\t\tcase \"time\":\n\t\t\treturn value;\n\t}\n}\n\n/**\n * Create a model-aware transfer deserializer that converts temporal fields\n * from ISO strings to native `Date` objects.\n *\n * Uses `__entityType` in the response payload to look up the transfer type\n * in the provided registry and convert matching fields. Nested objects and\n * arrays are processed recursively.\n *\n * @param registry - Mapping of entity type FQNs to temporal field declarations\n * @returns `TransferDeserializer` that converts `date`/`timestamp` strings to `Date`\n *\n * @example\n * ```typescript\n * import { temporalFieldRegistry } from './generated/transfers/_registry';\n *\n * const api = createJudoRestApi({\n * // ...\n * transferDeserializer: createModelAwareDeserializer(temporalFieldRegistry),\n * });\n * ```\n */\nexport function createModelAwareDeserializer(registry: TemporalFieldRegistry): TransferDeserializer {\n\treturn {\n\t\tdeserialize(data: unknown): unknown {\n\t\t\tif (data == null || typeof data !== \"object\") return data;\n\n\t\t\tif (Array.isArray(data)) {\n\t\t\t\treturn data.map((item) => this.deserialize(item));\n\t\t\t}\n\n\t\t\tconst obj = data as Record<string, unknown>;\n\t\t\tconst entityType = obj.__entityType as string | undefined;\n\t\t\tconst temporalFields = entityType ? registry[entityType] : undefined;\n\n\t\t\tconst result = { ...obj };\n\n\t\t\t// Recurse into nested objects and arrays\n\t\t\tfor (const [key, value] of Object.entries(result)) {\n\t\t\t\tif (value != null && typeof value === \"object\") {\n\t\t\t\t\tresult[key] = this.deserialize(value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Convert temporal fields for this object\n\t\t\tif (temporalFields) {\n\t\t\t\tfor (const [field, fieldType] of Object.entries(temporalFields)) {\n\t\t\t\t\tconst value = result[field];\n\t\t\t\t\tif (typeof value === \"string\") {\n\t\t\t\t\t\tresult[field] = deserializeTemporalValue(value, fieldType);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t},\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ActionLifecycle, ActionHandlerContext, ActionHandlerFn } from '@judo/model-api';
|
|
2
|
+
import { Action } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Execute an action with lifecycle overrides composed around a default handler.
|
|
5
|
+
*
|
|
6
|
+
* Lifecycle execution order:
|
|
7
|
+
* 1. override.before() → return false to cancel
|
|
8
|
+
* 2. override.execute() ?? defaultHandler() → core execution
|
|
9
|
+
* 3. override.after() → post-processing
|
|
10
|
+
* 4. override.onError() → error handling (return true to suppress)
|
|
11
|
+
*
|
|
12
|
+
* @param defaultHandler - The built-in action handler function
|
|
13
|
+
* @param overrides - Partial lifecycle overrides from the developer
|
|
14
|
+
* @param baseContext - The base action handler context
|
|
15
|
+
* @param action - The Action model object
|
|
16
|
+
* @param page - The PageDefinition
|
|
17
|
+
* @returns Promise resolving to the action result
|
|
18
|
+
*/
|
|
19
|
+
export declare function executeWithLifecycle(defaultHandler: ActionHandlerFn, overrides: Partial<ActionLifecycle>, baseContext: ActionHandlerContext, action: Action): Promise<unknown>;
|
|
20
|
+
//# sourceMappingURL=execute-with-lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute-with-lifecycle.d.ts","sourceRoot":"","sources":["../../src/lifecycle/execute-with-lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,eAAe,EAA0B,MAAM,iBAAiB,CAAC;AAC/E,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC7E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,oBAAoB,CACzC,cAAc,EAAE,eAAe,EAC/B,SAAS,EAAE,OAAO,CAAC,eAAe,CAAC,EACnC,WAAW,EAAE,oBAAoB,EACjC,MAAM,EAAE,MAAM,GACZ,OAAO,CAAC,OAAO,CAAC,CA4ClB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lifecycle/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC"}
|