@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.
Files changed (84) hide show
  1. package/LICENSE +277 -0
  2. package/README.md +257 -0
  3. package/dist/api/constants.d.ts +27 -0
  4. package/dist/api/constants.d.ts.map +1 -0
  5. package/dist/api/index.d.ts +9 -0
  6. package/dist/api/index.d.ts.map +1 -0
  7. package/dist/api/judo-rest-api.d.ts +262 -0
  8. package/dist/api/judo-rest-api.d.ts.map +1 -0
  9. package/dist/api/model-converters.d.ts +29 -0
  10. package/dist/api/model-converters.d.ts.map +1 -0
  11. package/dist/api/path-builder.d.ts +50 -0
  12. package/dist/api/path-builder.d.ts.map +1 -0
  13. package/dist/api/transfer-deserializer.d.ts +46 -0
  14. package/dist/api/transfer-deserializer.d.ts.map +1 -0
  15. package/dist/api/transfer-serializer.d.ts +85 -0
  16. package/dist/api/transfer-serializer.d.ts.map +1 -0
  17. package/dist/api/types.d.ts +278 -0
  18. package/dist/api/types.d.ts.map +1 -0
  19. package/dist/handlers/autocomplete/autocomplete-handlers.d.ts +20 -0
  20. package/dist/handlers/autocomplete/autocomplete-handlers.d.ts.map +1 -0
  21. package/dist/handlers/autocomplete/index.d.ts +2 -0
  22. package/dist/handlers/autocomplete/index.d.ts.map +1 -0
  23. package/dist/handlers/crud/crud-handlers.d.ts +76 -0
  24. package/dist/handlers/crud/crud-handlers.d.ts.map +1 -0
  25. package/dist/handlers/crud/index.d.ts +2 -0
  26. package/dist/handlers/crud/index.d.ts.map +1 -0
  27. package/dist/handlers/form/form-handlers.d.ts +28 -0
  28. package/dist/handlers/form/form-handlers.d.ts.map +1 -0
  29. package/dist/handlers/form/index.d.ts +2 -0
  30. package/dist/handlers/form/index.d.ts.map +1 -0
  31. package/dist/handlers/index.d.ts +10 -0
  32. package/dist/handlers/index.d.ts.map +1 -0
  33. package/dist/handlers/navigation/index.d.ts +2 -0
  34. package/dist/handlers/navigation/index.d.ts.map +1 -0
  35. package/dist/handlers/navigation/navigation-handlers.d.ts +23 -0
  36. package/dist/handlers/navigation/navigation-handlers.d.ts.map +1 -0
  37. package/dist/handlers/operation/index.d.ts +2 -0
  38. package/dist/handlers/operation/index.d.ts.map +1 -0
  39. package/dist/handlers/operation/operation-handlers.d.ts +43 -0
  40. package/dist/handlers/operation/operation-handlers.d.ts.map +1 -0
  41. package/dist/handlers/other/index.d.ts +2 -0
  42. package/dist/handlers/other/index.d.ts.map +1 -0
  43. package/dist/handlers/other/other-handlers.d.ts +10 -0
  44. package/dist/handlers/other/other-handlers.d.ts.map +1 -0
  45. package/dist/handlers/relation/index.d.ts +2 -0
  46. package/dist/handlers/relation/index.d.ts.map +1 -0
  47. package/dist/handlers/relation/relation-handlers.d.ts +49 -0
  48. package/dist/handlers/relation/relation-handlers.d.ts.map +1 -0
  49. package/dist/handlers/selector/index.d.ts +2 -0
  50. package/dist/handlers/selector/index.d.ts.map +1 -0
  51. package/dist/handlers/selector/selector-handlers.d.ts +30 -0
  52. package/dist/handlers/selector/selector-handlers.d.ts.map +1 -0
  53. package/dist/handlers/table/index.d.ts +2 -0
  54. package/dist/handlers/table/index.d.ts.map +1 -0
  55. package/dist/handlers/table/table-handlers.d.ts +18 -0
  56. package/dist/handlers/table/table-handlers.d.ts.map +1 -0
  57. package/dist/hooks/index.d.ts +3 -0
  58. package/dist/hooks/index.d.ts.map +1 -0
  59. package/dist/hooks/use-action-dispatcher.d.ts +61 -0
  60. package/dist/hooks/use-action-dispatcher.d.ts.map +1 -0
  61. package/dist/hooks/use-action-handler.d.ts +29 -0
  62. package/dist/hooks/use-action-handler.d.ts.map +1 -0
  63. package/dist/index.d.ts +13 -0
  64. package/dist/index.d.ts.map +1 -0
  65. package/dist/index.js +1427 -0
  66. package/dist/index.js.map +1 -0
  67. package/dist/lifecycle/execute-with-lifecycle.d.ts +20 -0
  68. package/dist/lifecycle/execute-with-lifecycle.d.ts.map +1 -0
  69. package/dist/lifecycle/index.d.ts +2 -0
  70. package/dist/lifecycle/index.d.ts.map +1 -0
  71. package/dist/provider/api-context.d.ts +30 -0
  72. package/dist/provider/api-context.d.ts.map +1 -0
  73. package/dist/provider/index.d.ts +2 -0
  74. package/dist/provider/index.d.ts.map +1 -0
  75. package/dist/registry/action-handler-registry.d.ts +11 -0
  76. package/dist/registry/action-handler-registry.d.ts.map +1 -0
  77. package/dist/registry/index.d.ts +2 -0
  78. package/dist/registry/index.d.ts.map +1 -0
  79. package/dist/types-BsQmyhQI.js +14 -0
  80. package/dist/types-BsQmyhQI.js.map +1 -0
  81. package/dist/types-CbA9-fcJ.js +2 -0
  82. package/dist/types.d.ts +260 -0
  83. package/dist/types.d.ts.map +1 -0
  84. package/package.json +45 -0
@@ -0,0 +1,30 @@
1
+ import { ReactNode } from 'react';
2
+ import { JudoRestApi } from '../api/judo-rest-api';
3
+ /**
4
+ * API context type.
5
+ */
6
+ export interface ApiContextType {
7
+ /** JUDO REST API client */
8
+ api: JudoRestApi;
9
+ }
10
+ /**
11
+ * Hook to access the JUDO REST API client.
12
+ *
13
+ * @returns JudoRestApi
14
+ * @throws Error if used outside ApiProvider
15
+ */
16
+ export declare function useApi(): JudoRestApi;
17
+ /**
18
+ * Props for ApiProvider.
19
+ */
20
+ export interface ApiProviderProps {
21
+ children: ReactNode;
22
+ /** JUDO REST API client instance */
23
+ api: JudoRestApi;
24
+ }
25
+ /**
26
+ * Provider for JUDO REST API client.
27
+ * Makes the API client available to action handlers via the useApi hook.
28
+ */
29
+ export declare function ApiProvider({ children, api }: ApiProviderProps): import("react/jsx-runtime").JSX.Element;
30
+ //# sourceMappingURL=api-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-context.d.ts","sourceRoot":"","sources":["../../src/provider/api-context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAA6B,MAAM,OAAO,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B,2BAA2B;IAC3B,GAAG,EAAE,WAAW,CAAC;CACjB;AAID;;;;;GAKG;AACH,wBAAgB,MAAM,IAAI,WAAW,CAMpC;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,QAAQ,EAAE,SAAS,CAAC;IACpB,oCAAoC;IACpC,GAAG,EAAE,WAAW,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,gBAAgB,2CAG9D"}
@@ -0,0 +1,2 @@
1
+ export { ApiProvider, useApi, type ApiContextType, type ApiProviderProps } from './api-context';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/provider/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,cAAc,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { Action, ActionHandlerHook } from '../types';
2
+ /**
3
+ * Get the handler for an action.
4
+ * Returns the handler hook if found, undefined otherwise.
5
+ */
6
+ export declare function getActionHandler(action: Action): ActionHandlerHook | undefined;
7
+ /**
8
+ * Check if a handler exists for the given action.
9
+ */
10
+ export declare function hasActionHandler(action: Action): boolean;
11
+ //# sourceMappingURL=action-handler-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-handler-registry.d.ts","sourceRoot":"","sources":["../../src/registry/action-handler-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAgI1D;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAG9E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAExD"}
@@ -0,0 +1,2 @@
1
+ export { getActionHandler, hasActionHandler } from './action-handler-registry';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/registry/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC"}
@@ -0,0 +1,14 @@
1
+ var ValidationError = class extends Error {
2
+ feedbackItems;
3
+ status = 400;
4
+ constructor(e) {
5
+ let t = e.find((e) => e.level === "ERROR");
6
+ super(t?.message ?? "Validation failed"), this.name = "ValidationError", this.feedbackItems = e;
7
+ }
8
+ toFieldErrors() {
9
+ let e = {};
10
+ for (let t of this.feedbackItems) t.level === "ERROR" && t.location && (e[t.location] = t.message ?? t.code);
11
+ return e;
12
+ }
13
+ };
14
+ export { ValidationError as t };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-BsQmyhQI.js","names":["errors: Record<string, string>"],"sources":["../src/api/types.ts"],"sourcesContent":["/**\n * JUDO REST API types.\n * Based on REST_REQUEST_MAPPING_SPECIFICATION.md\n */\n\n// ============================================\n// HTTP/Response Types\n// ============================================\n\n/**\n * HTTP method types used in the REST layer.\n * GET is used for template retrieval, file downloads, metadata, principal.\n * POST is used for all other operations (CRUD, list, range, operations, validation).\n */\nexport type HttpMethod = \"GET\" | \"POST\";\n\n/**\n * Response type indicating how to handle the response body.\n */\nexport type ResponseType = \"json\" | \"blob\";\n\n/**\n * How to deserialize the response.\n * - single: Deserialize as a single transfer\n * - array: Deserialize as an array of transfers\n * - void: No deserialization needed (response is empty)\n * - nullable: Deserialize as single transfer or null\n */\nexport type DeserializationType = \"single\" | \"array\" | \"void\" | \"nullable\";\n\n/**\n * Service type categories.\n */\nexport type ServiceType = \"class\" | \"relation\" | \"access\";\n\n// ============================================\n// Serialization/Deserialization\n// ============================================\n\n/**\n * Configuration for deserializing the response.\n */\nexport interface ResponseDeserializerConfig {\n\t/** Type of deserialization to apply */\n\ttype: DeserializationType;\n\t/** Target class FQName for deserialization (if applicable) */\n\ttargetClassFqName?: string;\n\t/** Whether the target is a stored (persisted) transfer */\n\tisStored: boolean;\n}\n\n/**\n * Transfer serializer interface for transforming transfers before sending.\n * The input type is unknown to support any transfer type.\n */\nexport interface TransferSerializer {\n\t/** Serialize an transfer for sending in request body */\n\tserialize(transfer: unknown): unknown;\n}\n\n/**\n * Transfer deserializer interface for transforming responses.\n * The output type is unknown to support any transfer type.\n */\nexport interface TransferDeserializer {\n\t/** Deserialize a response into an transfer */\n\tdeserialize(data: unknown): unknown;\n}\n\n// ============================================\n// Temporal Field Types\n// ============================================\n\n/**\n * Classification of temporal (date/time) field types.\n *\n * - `date`: Date-only value (`YYYY-MM-DD`) — converted to `Date` at local midnight\n * - `time`: Time-only value (`HH:mm[:ss]`) — kept as `string` (no `Date` conversion)\n * - `timestamp`: Full datetime with timezone (`YYYY-MM-DDTHH:mm:ss[.SSS]Z`) — converted to `Date`\n */\nexport type TemporalFieldType = \"date\" | \"time\" | \"timestamp\";\n\n/**\n * Registry mapping transfer type FQNs to their temporal field declarations.\n *\n * Keys match `__entityType` values from API responses (e.g., `\"Demo::OrderDTO\"`).\n * Values map field names to their temporal type for serialization/deserialization.\n *\n * @example\n * ```typescript\n * const registry: TemporalFieldRegistry = {\n * \"Demo::OrderDTO\": { orderDate: \"date\", createdAt: \"timestamp\" },\n * \"Demo::MissionDTO\": { startDate: \"date\", endDate: \"date\" },\n * };\n * ```\n */\nexport type TemporalFieldRegistry = Record<string, Record<string, TemporalFieldType>>;\n\n// ============================================\n// API Configuration\n// ============================================\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/** Application base path (e.g., /api) */\n\tbasePath: string;\n\t/** Application model name (e.g., edemokracia) */\n\tmodelName: string;\n\t/** Actor path (e.g., admin/Admin) */\n\tactorPath: string;\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/**\n\t * Optional transfer serializer for transforming transfers before sending.\n\t * If not provided, transfers are sent as-is (JSON.stringify).\n\t */\n\ttransferSerializer?: TransferSerializer;\n\t/**\n\t * Optional transfer deserializer for transforming responses.\n\t * If not provided, responses are used as-is (JSON.parse result).\n\t */\n\ttransferDeserializer?: TransferDeserializer;\n}\n\n/**\n * Query customizer for list/get operations.\n */\nexport interface QueryCustomizer {\n\t_mask?: string;\n\t_orderBy?: Array<{ attribute: string; descending?: boolean }>;\n\t_seek?: { limit?: number; lastItem?: unknown };\n\t_filter?: unknown;\n\t_identifier?: string;\n}\n\n/**\n * Base transfer data interface.\n *\n */\nexport interface TransferData {\n\t[key: string]: unknown;\n}\n\n/**\n * Strict transfer data — a TransferData whose *own* properties conform to `T`.\n *\n * Use in generated code and userland APIs where the exact field set is known.\n *\n * @typeParam T - Strict field definitions (e.g. `{ name: string; age: number }`)\n */\nexport type StrictTransferData<T extends Record<string, unknown> = Record<string, unknown>> = TransferData & T;\n\n/**\n * Stored transfer with identifiers.\n */\nexport interface TransferStored extends TransferData {\n\t__identifier?: string;\n\t__signedIdentifier?: string;\n\t__typename?: string;\n\t__entityType?: string;\n}\n\n/**\n * Strict stored transfer — a TransferStored with compile-time field types from `T`.\n *\n * @typeParam T - Strict field definitions\n */\nexport type StrictTransferStored<T extends Record<string, unknown> = Record<string, unknown>> = TransferStored & T;\n\n/**\n * Response wrapper for JUDO REST responses.\n */\nexport interface JudoRestResponse<T> {\n\tdata: T;\n\tstatus: number;\n\theaders: Headers;\n}\n\n/**\n * Path context for building REST paths.\n */\nexport interface PathContext {\n\t/** Package name tokens (e.g., [\"admin\"]) */\n\tpackageNameTokens: string[];\n\t/** Simple name (e.g., \"Issue\") */\n\tsimpleName: string;\n}\n\n/**\n * Class type metadata for path building.\n */\nexport interface ClassTypeMetadata extends PathContext {\n\t/** Fully qualified name */\n\tfqName?: string;\n\t/** Whether the class is mapped */\n\tisMapped?: boolean;\n}\n\n/**\n * Relation type metadata for path building.\n */\nexport interface RelationMetadata {\n\t/** Relation name */\n\tname: string;\n\t/** Owner class metadata */\n\towner: ClassTypeMetadata;\n\t/** Target class metadata */\n\ttarget: ClassTypeMetadata;\n\t/** Whether this is an access relation */\n\tisAccess?: boolean;\n\t/** Whether this is a collection relation */\n\tisCollection?: boolean;\n}\n\n/**\n * Operation type metadata.\n */\nexport interface OperationMetadata {\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/** Whether the operation has output */\n\thasOutput?: boolean;\n\t/** Input type metadata */\n\tinputType?: ClassTypeMetadata;\n\t/** Output type metadata */\n\toutputType?: ClassTypeMetadata;\n}\n\n/**\n * Range request body structure.\n */\nexport interface RangeRequestBody {\n\towner?: TransferStored;\n\tqueryCustomizer?: QueryCustomizer;\n}\n\n// ============================================\n// Validation & Error Types\n// ============================================\n\n/**\n * Validation feedback item from REST API.\n * Returned in response body for 400 validation errors.\n */\nexport interface FeedbackItem {\n\t/** Error code identifier */\n\tcode: string;\n\t/** Severity level of the feedback */\n\tlevel: \"ERROR\" | \"WARNING\" | \"INFO\";\n\t/**\n\t * Location of the error - typically the attribute path.\n\t * For nested properties, format is: \"relationName.attributeName\"\n\t * For simple attributes, format is: \"attributeName\"\n\t */\n\tlocation: string;\n\t/** Human-readable error message */\n\tmessage?: string;\n}\n\n/**\n * Validation error thrown when API returns 400 status.\n * Contains array of FeedbackItem with field-level error details.\n */\nexport class ValidationError extends Error {\n\treadonly feedbackItems: FeedbackItem[];\n\treadonly status: number = 400;\n\n\tconstructor(feedbackItems: FeedbackItem[]) {\n\t\tconst firstError = feedbackItems.find((f) => f.level === \"ERROR\");\n\t\tsuper(firstError?.message ?? \"Validation failed\");\n\t\tthis.name = \"ValidationError\";\n\t\tthis.feedbackItems = feedbackItems;\n\t}\n\n\t/**\n\t * Get errors as a map of field location to error message.\n\t * Useful for setting form field errors.\n\t */\n\ttoFieldErrors(): Record<string, string> {\n\t\tconst errors: Record<string, string> = {};\n\t\tfor (const item of this.feedbackItems) {\n\t\t\tif (item.level === \"ERROR\" && item.location) {\n\t\t\t\terrors[item.location] = item.message ?? item.code;\n\t\t\t}\n\t\t}\n\t\treturn errors;\n\t}\n}\n\n// ============================================\n// Dialog Response Types\n// ============================================\n\n/**\n * Result type for dialog submission.\n * Used for create dialogs opened from eager/lazy components.\n */\nexport type DialogResult<T = TransferData> = { outcome: \"cancel\" } | { outcome: \"submit\"; data: T };\n\n/**\n * Callback for dialog submission.\n * Called when user submits the create form.\n */\nexport type OnDialogSubmit<T = TransferData> = (data: T) => Promise<void>;\n\n/**\n * Callback for dialog validation.\n * Called before submission to validate form data.\n * Returns field errors or null if valid.\n */\nexport type OnDialogValidate<T = TransferData> = (data: T) => Promise<Record<string, string> | null>;\n"],"mappings":"AA2RA,IAAa,kBAAb,cAAqC,MAAM;CAC1C;CACA,SAA0B;CAE1B,YAAY,GAA+B;EAC1C,IAAM,IAAa,EAAc,MAAM,MAAM,EAAE,UAAU,QAAQ;AAGjE,EAFA,MAAM,GAAY,WAAW,oBAAoB,EACjD,KAAK,OAAO,mBACZ,KAAK,gBAAgB;;CAOtB,gBAAwC;EACvC,IAAMA,IAAiC,EAAE;AACzC,OAAK,IAAM,KAAQ,KAAK,cACvB,CAAI,EAAK,UAAU,WAAW,EAAK,aAClC,EAAO,EAAK,YAAY,EAAK,WAAW,EAAK;AAG/C,SAAO"}
@@ -0,0 +1,2 @@
1
+ import { t as ValidationError } from "./types-BsQmyhQI.js";
2
+ export { ValidationError };
@@ -0,0 +1,260 @@
1
+ import { Action, Application } from '@judo/model-api';
2
+ /**
3
+ * @judo/actions - Type definitions
4
+ *
5
+ * Defines action-specific types for the built-in handlers.
6
+ * All action handlers use the hook factory pattern for React hooks compatibility.
7
+ *
8
+ * NOTE: This package defines its own ActionHandlerHook type with typed context
9
+ * because model-api uses `unknown` for maximum flexibility, but built-in handlers
10
+ * need typed access to navigation, data store, and registry services.
11
+ */
12
+ export type { Action, ActionDefinition, Application } from '@judo/model-api';
13
+ export { ACTION_HANDLER_FACTORY } from '@judo/model-api';
14
+ /**
15
+ * Action types supported by the action handlers.
16
+ */
17
+ export type ActionType = "BackActionDefinition" | "OpenPageActionDefinition" | "RowOpenPageActionDefinition" | "CancelActionDefinition" | "OpenFormActionDefinition" | "OpenCreateFormActionDefinition" | "OpenOperationInputFormActionDefinition" | "OpenSelectorActionDefinition" | "OpenAddSelectorActionDefinition" | "OpenSetSelectorActionDefinition" | "OpenOperationInputSelectorActionDefinition" | "SelectorRangeActionDefinition" | "RefreshActionDefinition" | "CreateActionDefinition" | "UpdateActionDefinition" | "DeleteActionDefinition" | "BulkDeleteActionDefinition" | "RowDeleteActionDefinition" | "GetTemplateActionDefinition" | "SetActionDefinition" | "UnsetActionDefinition" | "AddActionDefinition" | "RemoveActionDefinition" | "BulkRemoveActionDefinition" | "ClearActionDefinition" | "RefreshRelationActionDefinition" | "FilterRelationActionDefinition" | "FilterActionDefinition" | "ExportActionDefinition" | "InlineCreateRowActionDefinition" | "CallOperationActionDefinition" | "BulkCallOperationActionDefinition" | "InputFormCallOperationActionDefinition" | "InputSelectorCallOperationActionDefinition" | "ParameterlessCallOperationActionDefinition" | "AutocompleteRangeActionDefinition" | "AutocompleteSetActionDefinition" | "AutocompleteAddActionDefinition" | "PreFetchActionDefinition" | "CustomActionDefinition";
18
+ /**
19
+ * Transfer data with identifier.
20
+ *
21
+ */
22
+ export interface TransferData {
23
+ __identifier?: string;
24
+ [key: string]: unknown;
25
+ }
26
+ /**
27
+ * Strict transfer data — a TransferData whose *own* properties conform to `T`.
28
+ *
29
+ * @typeParam T - Strict field definitions
30
+ */
31
+ export type StrictTransferData<T extends Record<string, unknown> = Record<string, unknown>> = TransferData & T;
32
+ /**
33
+ * Dialog close result types.
34
+ */
35
+ export type DialogCloseResultType = "cancelled" | "created" | "updated" | "deleted" | "selected" | "submitted";
36
+ /**
37
+ * Result returned when dialog closes.
38
+ * Uses discriminated union for type-safe handling of different outcomes.
39
+ */
40
+ export type DialogCloseResult = {
41
+ type: "cancelled";
42
+ } | {
43
+ type: "created";
44
+ isEager: boolean;
45
+ data?: unknown;
46
+ } | {
47
+ type: "updated";
48
+ data?: unknown;
49
+ } | {
50
+ type: "deleted";
51
+ data?: unknown;
52
+ } | {
53
+ type: "selected";
54
+ data?: unknown;
55
+ } | {
56
+ type: "submitted";
57
+ data?: unknown;
58
+ };
59
+ /**
60
+ * Navigation context interface.
61
+ */
62
+ export interface NavigationContext {
63
+ goBack(): void;
64
+ navigateTo(page: unknown, params?: Record<string, unknown>): void;
65
+ replacePage(page: unknown, params?: Record<string, unknown>): void;
66
+ openDialog(page: unknown, params?: Record<string, unknown>, onClose?: (result?: DialogCloseResult) => void): void;
67
+ }
68
+ /**
69
+ * Data store interface for transfer operations.
70
+ */
71
+ export interface DataStore {
72
+ setTransferLoading(id: string, loading: boolean): void;
73
+ setTransferData<T extends Record<string, unknown> = Record<string, unknown>>(id: string, data: TransferData & T): void;
74
+ setTransferError(id: string, error: Error): void;
75
+ clearTransfer(id: string): void;
76
+ resetTransfer(id: string): void;
77
+ getSnapshot<T>(selector: (state: unknown) => T): T;
78
+ updateTransferFields<T extends Record<string, unknown> = Record<string, unknown>>(id: string, updates: Partial<T>): void;
79
+ }
80
+ /**
81
+ * Model registry interface for handler lookups.
82
+ * Note: In most cases, handlers should use resolved properties from Action/ActionDefinition
83
+ * directly rather than calling these methods.
84
+ *
85
+ * At runtime, this is typically the ApplicationContextType from @judo/core,
86
+ * which provides access to the current application and its actor.
87
+ */
88
+ export interface ModelRegistry {
89
+ resolvePageDefinition?(ref: string): unknown;
90
+ resolveClassType?(ref: string): unknown;
91
+ resolveById?(id: string): unknown;
92
+ /** Current active application (contains the actor ClassType). */
93
+ application?: Application;
94
+ }
95
+ /**
96
+ * Validation context interface for setting field errors from API responses.
97
+ */
98
+ export interface ValidationContext {
99
+ /** Set error for a specific field */
100
+ setError(fieldId: string, error: string | null): void;
101
+ /** Set multiple errors at once (typically from API validation response) */
102
+ setErrors(errors: Record<string, string>): void;
103
+ /** Clear all validation errors */
104
+ clearErrors(): void;
105
+ /** Clear error for a specific field */
106
+ clearError(fieldId: string): void;
107
+ /** Touch all fields (mark as visited/modified) */
108
+ touchAll?(): void;
109
+ }
110
+ /**
111
+ * Notification service interface for showing toast notifications.
112
+ * Used by action handlers to provide user feedback.
113
+ */
114
+ export interface NotificationService {
115
+ /** Show success notification */
116
+ success(message: string): void;
117
+ /** Show error notification */
118
+ error(message: string): void;
119
+ /** Show warning notification */
120
+ warning(message: string): void;
121
+ /** Show info notification */
122
+ info(message: string): void;
123
+ }
124
+ /**
125
+ * Dialog context for create form submissions.
126
+ * Provides callbacks for validation and submission.
127
+ */
128
+ export interface CreateDialogContext {
129
+ /**
130
+ * Whether this is a create dialog for an eager (aggregated) component.
131
+ * Eager dialogs return data to the caller instead of persisting via API.
132
+ */
133
+ isEager?: boolean;
134
+ /**
135
+ * Owner transfer for the relation being created.
136
+ * Required for non-access relations to build the correct API path.
137
+ */
138
+ ownerTransfer?: TransferData;
139
+ /**
140
+ * Relation type for the create operation.
141
+ * Used to determine API endpoints and validation paths.
142
+ */
143
+ relation?: unknown;
144
+ /**
145
+ * Parent transfer ID in the data store where created transfer should be added.
146
+ * For eager tables embedded in VIEW pages, this is the VIEW page's transfer ID.
147
+ */
148
+ parentTransferId?: string;
149
+ /**
150
+ * Relation name (property name) on the parent transfer where created transfer should be added.
151
+ * For eager tables, this is the relation property (e.g., "addresses" on a customer transfer).
152
+ */
153
+ relationName?: string;
154
+ /**
155
+ * Callback to submit created transfer data.
156
+ * For eager components: returns data to caller (table/link adds to local state)
157
+ * For lazy components: persists via API then refreshes parent data
158
+ */
159
+ onSubmitCreate?: (data: TransferData) => Promise<void>;
160
+ /**
161
+ * Callback for dialog cancellation.
162
+ */
163
+ onCancel?: () => void;
164
+ }
165
+ /**
166
+ * Action handler context for built-in handlers.
167
+ * This is the concrete typed version used by built-in action handlers.
168
+ * It provides specific types for navigation, data store, and registry.
169
+ *
170
+ * Note: This has the same shape as ActionHandlerContext from model-api but with specific types.
171
+ * Properties are optional to maintain compatibility with base type, but built-in handlers
172
+ * expect them to be provided at runtime.
173
+ */
174
+ export interface TypedActionHandlerContext {
175
+ /** The transfer being acted upon */
176
+ transfer?: TransferData;
177
+ /** Selected rows for bulk/table operations */
178
+ selectedRows?: TransferData[];
179
+ /** Dialog closer if action is in a dialog, with optional result */
180
+ closeDialog?: (result?: DialogCloseResult) => void;
181
+ /** Navigation context for page transitions (typed, expected to be present) */
182
+ navigation?: NavigationContext;
183
+ /** Data store for transfer operations (typed, expected to be present) */
184
+ data?: DataStore;
185
+ /** Model registry for lookups (typed, expected to be present) */
186
+ registry?: ModelRegistry;
187
+ /** Validation context for setting field errors */
188
+ validation?: ValidationContext;
189
+ /** Notification service for showing toast messages */
190
+ notifications?: NotificationService;
191
+ /**
192
+ * Whether the initiating component is eager (aggregated).
193
+ * Eager components manage their own data locally without REST calls.
194
+ */
195
+ isEager?: boolean;
196
+ /**
197
+ * Current page container type (TABLE, FORM, VIEW).
198
+ * Used to determine context-specific behavior.
199
+ */
200
+ pageType?: "TABLE" | "FORM" | "VIEW";
201
+ /**
202
+ * Whether the current view page is in edit mode (has unsaved changes).
203
+ * Only relevant when pageType is VIEW.
204
+ */
205
+ isEditMode?: boolean;
206
+ /**
207
+ * Whether this action was triggered from a page-level button (dialog footer).
208
+ * Page actions bypass certain restrictions that apply to nested operations.
209
+ */
210
+ isPageAction?: boolean;
211
+ /**
212
+ * Create dialog context for form submissions.
213
+ * Present when the action is triggered from a create dialog.
214
+ */
215
+ createDialog?: CreateDialogContext;
216
+ /**
217
+ * Callback to be invoked when a dialog opened by this action closes.
218
+ * Used by callers (e.g., TableRenderer) to refresh data after successful creates.
219
+ */
220
+ onDialogClose?: (result?: DialogCloseResult) => void;
221
+ }
222
+ export type { ActionHandlerFn, ActionHandlerHook } from '@judo/model-api';
223
+ /**
224
+ * Typed handler function for built-in handlers.
225
+ * Uses TypedActionHandlerContext instead of base ActionHandlerContext.
226
+ */
227
+ export type TypedActionHandlerFn = (context: TypedActionHandlerContext) => Promise<unknown>;
228
+ /**
229
+ * Typed handler hook for built-in handlers.
230
+ * Returns a handler that uses TypedActionHandlerContext.
231
+ */
232
+ export type TypedActionHandlerHook = (action: Action) => TypedActionHandlerFn;
233
+ /**
234
+ * Action handler hook with actionType metadata for built-in handler registration.
235
+ * Uses typed context for built-in handlers.
236
+ */
237
+ export interface ActionHandlerHookWithMeta extends TypedActionHandlerHook {
238
+ /** The action type this handler handles (e.g., 'BackActionDefinition') */
239
+ actionType: ActionType;
240
+ }
241
+ /**
242
+ * @internal Framework-internal service properties for custom action handler registration.
243
+ *
244
+ * **Do not use directly.** Developers should use the generated `createCustomizations()`
245
+ * factory with human-readable page and action names instead.
246
+ */
247
+ export interface ActionHandlerFactoryProperties {
248
+ /** @internal The action's xmi:id — resolved automatically by the factory */
249
+ sourceId: string;
250
+ }
251
+ /**
252
+ * Service properties for built-in action handler registration (internal).
253
+ */
254
+ export interface BuiltInActionHandlerFactoryProperties {
255
+ /** The action type this built-in handles (e.g., 'BackActionDefinition') */
256
+ actionType: string;
257
+ /** Marker for built-in handlers */
258
+ builtin: true;
259
+ }
260
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@judo/actions",
3
+ "version": "0.1.0",
4
+ "license": "EPL-2.0",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/BlackBeltTechnology/judo-frontend-runtime.git",
8
+ "directory": "packages/actions"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "LICENSE",
13
+ "README.md"
14
+ ],
15
+ "type": "module",
16
+ "sideEffects": false,
17
+ "main": "./dist/index.js",
18
+ "types": "./dist/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "import": "./dist/index.js"
23
+ }
24
+ },
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "dependencies": {
29
+ "@judo/model-api": "0.1.0"
30
+ },
31
+ "devDependencies": {
32
+ "@testing-library/react": "^16.3.2",
33
+ "@types/react": "^19.2.14",
34
+ "typescript": "^5.9.3",
35
+ "vitest": "^4.0.18"
36
+ },
37
+ "peerDependencies": {
38
+ "react": "^19.0.0"
39
+ },
40
+ "scripts": {
41
+ "build": "vite build",
42
+ "test": "vitest run",
43
+ "test:coverage": "vitest run --coverage"
44
+ }
45
+ }