@context-action/core 0.3.1 → 0.5.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/README.md CHANGED
@@ -1,33 +1,18 @@
1
1
  # @context-action/core
2
2
 
3
- Type-safe action pipeline management library for JavaScript/TypeScript applications.
3
+ Type-safe action pipeline management library for JavaScript/TypeScript applications with advanced filtering, performance optimizations, and React integration support.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
- npm install @context-action/core dotenv
8
+ npm install @context-action/core
9
+ # or
10
+ pnpm install @context-action/core
9
11
  ```
10
12
 
11
13
  ## Quick Start
12
14
 
13
- ### 1. Setup Environment Configuration
14
-
15
- ```bash
16
- # Copy sample configuration
17
- cp .env.sample .env
18
-
19
- # Quick setup for maximum debugging detail
20
- echo "NODE_ENV=development" >> .env
21
- echo "CONTEXT_ACTION_TRACE=true" >> .env
22
- echo "CONTEXT_ACTION_DEBUG=true" >> .env
23
- echo "CONTEXT_ACTION_LOGGER_NAME=MyApp" >> .env
24
- ```
25
-
26
- ### 2. Basic Usage
27
-
28
15
  ```typescript
29
- // Load environment variables first
30
- import 'dotenv/config';
31
16
  import { ActionRegister } from '@context-action/core';
32
17
 
33
18
  // Define your action types
@@ -38,235 +23,468 @@ interface MyActions {
38
23
  }
39
24
 
40
25
  // Create action register
41
- const actions = new ActionRegister<MyActions>();
26
+ const actions = new ActionRegister<MyActions>({
27
+ name: 'MyApp',
28
+ registry: { debug: true }
29
+ });
42
30
 
43
- // Register handlers
44
- actions.register('increment', (_, controller) => {
31
+ // Register handlers with priorities
32
+ actions.register('increment', () => {
45
33
  console.log('Increment called');
46
- // Handler automatically continues to next handler
47
- });
34
+ }, { priority: 10 });
48
35
 
49
- actions.register('setCount', (count, controller) => {
36
+ actions.register('setCount', (count) => {
50
37
  console.log(`Setting count to: ${count}`);
51
- // Handler automatically continues to next handler
52
- });
38
+ }, { priority: 5 });
53
39
 
54
40
  // Dispatch actions
55
41
  await actions.dispatch('increment');
56
42
  await actions.dispatch('setCount', 42);
57
43
  ```
58
44
 
59
- ## Environment Variables
45
+ ### Memory Management
60
46
 
61
- | Variable | Description | Default | Max Detail |
62
- |----------|-------------|---------|------------|
63
- | `CONTEXT_ACTION_TRACE` | Enable detailed trace logging | `false` | `true` |
64
- | `CONTEXT_ACTION_DEBUG` | Enable debug mode | `false` | `true` |
65
- | `CONTEXT_ACTION_LOG_LEVEL` | Set specific log level (`TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `NONE`) | `ERROR` | `TRACE` |
66
- | `CONTEXT_ACTION_LOGGER_NAME` | Custom logger name | `ActionRegister` | `YourAppName` |
67
- | `NODE_ENV` | Auto-configure logging (`development` = DEBUG, `production` = ERROR) | - | `development` |
47
+ ```typescript
48
+ // Configure handler limits for memory safety (v0.4.1+)
49
+ const actions = new ActionRegister<MyActions>({
50
+ registry: {
51
+ maxHandlersPerAction: 1000 // Default: 1000, prevents memory issues
52
+ // maxHandlersPerAction: 5000 // Higher limit for complex applications
53
+ // maxHandlersPerAction: Infinity // Disable limit (use with caution)
54
+ }
55
+ });
68
56
 
69
- **💡 Tip**: For maximum debugging detail, set all variables in the "Max Detail" column.
57
+ // Use cases for different limits:
58
+ // - 1000 (default): Most applications
59
+ // - 5000-10000: Large enterprise applications
60
+ // - Infinity: Only for controlled environments with trusted code
61
+ ```
70
62
 
71
- ## Features
63
+ ## 🚀 New Features (v0.4.0+)
72
64
 
73
- - **Type-safe actions** - Full TypeScript support with compile-time checking
74
- - **Priority-based execution** - Control handler execution order
75
- - **Pipeline control** - Abort, modify payloads, conditional execution
76
- - **Event system** - Listen to action lifecycle events
77
- - **Comprehensive logging** - Detailed trace logging for debugging
78
- - **Environment-based configuration** - Easy .env setup
65
+ ### Advanced Filtering System
79
66
 
80
- ## Advanced Usage
67
+ Filter handlers by priority, ID, or custom conditions:
68
+
69
+ ```typescript
70
+ // Filter by priority range
71
+ await actions.dispatch('updateUser', userData, {
72
+ filter: {
73
+ priority: { min: 10, max: 50 } // Only handlers with priority 10-50
74
+ }
75
+ });
76
+
77
+ // Filter by specific handler IDs
78
+ await actions.dispatch('processData', data, {
79
+ filter: {
80
+ handlerIds: ['validation', 'logging'], // Only these handlers
81
+ excludeHandlerIds: ['analytics'] // Exclude analytics handler
82
+ }
83
+ });
81
84
 
82
- ### Handler Configuration
85
+ // Custom filtering logic
86
+ await actions.dispatch('secureAction', data, {
87
+ filter: {
88
+ custom: (config) => config.blocking === true // Only blocking handlers
89
+ }
90
+ });
91
+
92
+ // Combined filtering
93
+ await actions.dispatch('complexAction', data, {
94
+ filter: {
95
+ priority: { min: 20 },
96
+ excludeHandlerIds: ['debug'],
97
+ custom: (config) => !config.id.includes('test')
98
+ }
99
+ });
100
+ ```
101
+
102
+ ### Enhanced Handler Configuration
83
103
 
84
104
  ```typescript
85
105
  actions.register('myAction', handler, {
86
- priority: 10, // Higher priority executes first
87
- blocking: true, // Wait for async handlers
88
- once: true, // Remove after first execution
89
- condition: () => shouldRun, // Conditional execution
90
- id: 'my-handler' // Custom handler ID
106
+ priority: 10,
107
+ id: 'my-handler',
108
+ blocking: true,
109
+ once: false,
110
+ debounce: 300,
111
+ throttle: 1000,
112
+ replaceExisting: true // 🆕 Replace handler with same ID (great for React HMR)
91
113
  });
92
114
  ```
93
115
 
94
- ### Pipeline Control
116
+ ### Immediate Execution & Queue Control
95
117
 
96
118
  ```typescript
97
- actions.register('validate', (data, controller) => {
98
- if (!data.isValid) {
99
- controller.abort('Validation failed');
100
- return;
101
- }
102
-
103
- // Modify data for next handlers
104
- controller.modifyPayload(data => ({ ...data, validated: true }));
105
- // Handler automatically continues to next handler
119
+ // Bypass queue for immediate execution
120
+ await actions.dispatch('urgentAction', data, {
121
+ immediate: true
122
+ });
123
+
124
+ // Queue with custom priority
125
+ await actions.dispatch('backgroundTask', data, {
126
+ queuePriority: 5
127
+ });
128
+
129
+ // Execution timeout
130
+ await actions.dispatch('timedAction', data, {
131
+ timeout: 5000
106
132
  });
107
133
  ```
108
134
 
109
- ### Event Listeners
135
+ ### Result Collection with Strategies
110
136
 
111
137
  ```typescript
112
- actions.on('action:start', ({ action, payload }) => {
113
- console.log(`Starting ${action}`, payload);
138
+ const result = await actions.dispatchWithResult('processData', data, {
139
+ result: {
140
+ collect: true,
141
+ strategy: 'all', // 'first' | 'last' | 'all' | 'merge' | 'custom'
142
+ maxResults: 10,
143
+ includeErrors: true
144
+ }
114
145
  });
115
146
 
116
- actions.on('action:complete', ({ action, metrics }) => {
117
- console.log(`Completed ${action} in ${metrics.executionTime}ms`);
118
- });
147
+ console.log('Results:', result.results);
148
+ console.log('Execution time:', result.execution.duration);
149
+ console.log('Success:', result.success);
119
150
  ```
120
151
 
121
- ## Debugging
152
+ ### React Integration Helpers
122
153
 
123
- ### Maximum Detail Logging
154
+ ```typescript
155
+ import {
156
+ useActionHandler,
157
+ createReactDispatcher,
158
+ ReactDevUtils
159
+ } from '@context-action/core';
160
+
161
+ // React hook pattern
162
+ function MyComponent() {
163
+ const registry = useActionRegister();
164
+
165
+ // Auto-cleanup on unmount, HMR support
166
+ const handlerConfig = useActionHandler(
167
+ registry,
168
+ 'userAction',
169
+ async (payload) => {
170
+ // Handler logic
171
+ },
172
+ { priority: 10 },
173
+ [] // dependencies
174
+ );
175
+
176
+ // React-optimized dispatcher
177
+ const dispatch = createReactDispatcher(registry, (error, action) => {
178
+ console.error(`Failed to dispatch ${action}:`, error);
179
+ });
180
+ }
124
181
 
125
- For the most comprehensive debugging experience, use this .env configuration:
182
+ // Development utilities
183
+ ReactDevUtils.enableDebugMode();
184
+ const stats = ReactDevUtils.getStats(registry);
185
+ ```
126
186
 
127
- ```bash
128
- # .env - Maximum detail logging configuration
129
- NODE_ENV=development
130
- CONTEXT_ACTION_TRACE=true
131
- CONTEXT_ACTION_DEBUG=true
132
- CONTEXT_ACTION_LOGGER_NAME=DetailedApp
133
-
134
- # This configuration will show:
135
- # - Every function call and return
136
- # - Handler registration and execution details
137
- # - Pipeline flow and state changes
138
- # - Payload modifications and conditions
139
- # - Performance metrics and timing
140
- # - Error details and stack traces
187
+ ## Core Features
188
+
189
+ ### 🎯 Type-Safe Action Pipeline
190
+ - **Full TypeScript support** with compile-time type checking
191
+ - **Priority-based execution** with configurable handler ordering
192
+ - **Pipeline control** - abort, modify payloads, conditional execution
193
+ - **Multiple execution modes** - sequential, parallel, race
194
+
195
+ ### Performance & Memory Optimizations
196
+ - **Cached environment checks** for better performance
197
+ - **Optimized handler ID generation** without random numbers
198
+ - **Smart array filtering** - only copies when needed
199
+ - **Automatic memory cleanup** with idle handler cleanup
200
+ - **Optional concurrency queues** for thread safety
201
+
202
+ ### 🔧 Advanced Configuration
203
+
204
+ ```typescript
205
+ const registry = new ActionRegister<MyActions>({
206
+ name: 'MyApp',
207
+ registry: {
208
+ debug: true,
209
+ autoCleanup: true,
210
+ defaultExecutionMode: 'sequential',
211
+ useConcurrencyQueue: true,
212
+ errorHandler: (error, context) => {
213
+ console.error('Unhandled action error:', error);
214
+ }
215
+ }
216
+ });
141
217
  ```
142
218
 
143
- ### Common Debug Configurations
219
+ ### 🎛️ Pipeline Controller
144
220
 
145
- ```bash
146
- # Development - Balanced detail
147
- NODE_ENV=development
148
- CONTEXT_ACTION_DEBUG=true
149
- CONTEXT_ACTION_LOGGER_NAME=DevApp
150
-
151
- # Production Debug - Errors only with context
152
- NODE_ENV=production
153
- CONTEXT_ACTION_LOG_LEVEL=ERROR
154
- CONTEXT_ACTION_DEBUG=true
155
- CONTEXT_ACTION_LOGGER_NAME=ProdApp
156
-
157
- # Issue Investigation - Specific level
158
- CONTEXT_ACTION_LOG_LEVEL=DEBUG
159
- CONTEXT_ACTION_DEBUG=true
160
- CONTEXT_ACTION_LOGGER_NAME=InvestigationSession
221
+ Full control over pipeline execution:
222
+
223
+ ```typescript
224
+ actions.register('validate', (data, controller) => {
225
+ // Abort pipeline
226
+ if (!data.isValid) {
227
+ controller.abort('Validation failed');
228
+ return;
229
+ }
230
+
231
+ // Modify payload for next handlers
232
+ controller.modifyPayload(data => ({
233
+ ...data,
234
+ validated: true,
235
+ timestamp: Date.now()
236
+ }));
237
+
238
+ // Jump to high-priority handlers
239
+ if (data.urgent) {
240
+ controller.jumpToPriority(100);
241
+ }
242
+
243
+ // Set result for collection
244
+ controller.setResult({ validation: 'passed' });
245
+
246
+ // Early return with result
247
+ if (data.fastPath) {
248
+ controller.return({ fastPath: true });
249
+ }
250
+ });
161
251
  ```
162
252
 
163
- ### Test Your Configuration
253
+ ## Advanced Usage
164
254
 
165
- After setting up your .env file, test that maximum detail logging is working:
255
+ ### Action Guard (Debounce/Throttle)
166
256
 
167
- ```bash
168
- # Create a quick test file
169
- echo "import 'dotenv/config';
170
- import { ActionRegister } from '@context-action/core';
257
+ ```typescript
258
+ // Built-in debounce/throttle support
259
+ actions.register('searchUsers', searchHandler, {
260
+ debounce: 300 // Wait 300ms after last call
261
+ });
171
262
 
172
- const actions = new ActionRegister();
173
- actions.register('test', (payload, controller) => {
174
- console.log('Handler executed:', payload);
175
- // Handler automatically continues to next handler
263
+ actions.register('scrollHandler', updateUI, {
264
+ throttle: 100 // Max once per 100ms
176
265
  });
177
- await actions.dispatch('test', { message: 'Hello!' });" > test-logging.js
178
266
 
179
- # Run the test
180
- node test-logging.js
267
+ // Via dispatch options
268
+ await actions.dispatch('search', query, {
269
+ debounce: 500
270
+ });
181
271
  ```
182
272
 
183
- You should see detailed TRACE and DEBUG output if configured correctly.
273
+ ### Execution Modes
274
+
275
+ ```typescript
276
+ // Set execution mode per action
277
+ actions.setActionExecutionMode('logEvent', 'parallel');
278
+ actions.setActionExecutionMode('fetchData', 'race');
279
+
280
+ // Override via dispatch options
281
+ await actions.dispatch('processFiles', files, {
282
+ executionMode: 'parallel'
283
+ });
284
+ ```
285
+
286
+ ### Error Handling & Recovery
287
+
288
+ ```typescript
289
+ actions.register('riskyOperation', async (data, controller) => {
290
+ try {
291
+ const result = await riskyAPI(data);
292
+ return result;
293
+ } catch (error) {
294
+ if (error.retryable) {
295
+ // Let other handlers try
296
+ return undefined;
297
+ } else {
298
+ // Abort pipeline for critical errors
299
+ controller.abort(`Critical error: ${error.message}`);
300
+ }
301
+ }
302
+ });
303
+
304
+ // With retry configuration
305
+ await actions.dispatch('apiCall', data, {
306
+ retryOnError: {
307
+ maxAttempts: 3,
308
+ delay: 1000
309
+ }
310
+ });
311
+ ```
184
312
 
185
- ### Troubleshooting
313
+ ### Statistics & Monitoring
186
314
 
187
- **Not seeing trace output?**
315
+ ```typescript
316
+ // Registry information
317
+ const info = actions.getRegistryInfo();
318
+ console.log(`Total actions: ${info.totalActions}`);
319
+ console.log(`Total handlers: ${info.totalHandlers}`);
320
+
321
+ // Action-specific statistics
322
+ const stats = actions.getActionStats('updateUser');
323
+ if (stats) {
324
+ console.log(`Handler count: ${stats.handlerCount}`);
325
+ console.log(`Success rate: ${stats.executionStats?.successRate}%`);
326
+ console.log(`Average duration: ${stats.executionStats?.averageDuration}ms`);
327
+ }
188
328
 
189
- 1. **Check dependencies**: Make sure `dotenv` is installed
190
- ```bash
191
- npm install dotenv
192
- # or
193
- pnpm install dotenv
194
- ```
329
+ // Clear statistics
330
+ actions.clearExecutionStats();
331
+ ```
195
332
 
196
- 2. **Verify .env file**: Confirm your .env file exists and has the correct settings
197
- ```bash
198
- cat .env
199
- # Should show: CONTEXT_ACTION_TRACE=true
200
- ```
333
+ ### Cleanup & Resource Management
201
334
 
202
- 3. **Check import order**: `dotenv/config` must be imported first
203
- ```typescript
204
- import 'dotenv/config'; // MUST be first
205
- import { ActionRegister } from '@context-action/core';
206
- ```
335
+ ```typescript
336
+ // Explicit cleanup when done
337
+ const registry = new ActionRegister({ name: 'MyApp' });
207
338
 
208
- 4. **Rebuild if needed**: After installing dotenv, rebuild the project if using a bundler
339
+ // Use the registry...
209
340
 
210
- For detailed debugging information, see [TRACE_LOGGING.md](./TRACE_LOGGING.md).
341
+ // Clean up all resources
342
+ registry.destroy(); // Cleans up pipelines, guards, queues, stats
343
+ ```
211
344
 
212
345
  ## API Reference
213
346
 
214
347
  ### ActionRegister<T>
215
348
 
216
- Main class for managing action pipelines.
217
-
349
+ #### Registration Methods
218
350
  - `register<K>(action, handler, config?)` - Register action handler
219
- - `dispatch<K>(action, payload?)` - Dispatch action through pipeline
220
- - `getHandlerCount(action)` - Get number of handlers for action
221
- - `hasHandlers(action)` - Check if action has handlers
222
- - `clearAction(action)` - Remove all handlers for action
351
+ - `clearAction(action)` - Remove all handlers for action
223
352
  - `clearAll()` - Remove all handlers
224
- - `on(event, handler)` - Add event listener
225
353
 
226
- ### Configuration Options
354
+ #### Dispatch Methods
355
+ - `dispatch<K>(action, payload?, options?)` - Dispatch action
356
+ - `dispatchWithResult<K>(action, payload?, options?)` - Dispatch with detailed results
357
+
358
+ #### Information Methods
359
+ - `getHandlerCount(action)` - Get handler count for action
360
+ - `hasHandlers(action)` - Check if action has handlers
361
+ - `getRegisteredActions()` - Get all registered action names
362
+ - `getRegistryInfo()` - Get comprehensive registry information
363
+ - `getActionStats(action)` - Get detailed action statistics
364
+
365
+ #### Execution Mode Methods
366
+ - `setActionExecutionMode(action, mode)` - Set execution mode for action
367
+ - `getActionExecutionMode(action)` - Get execution mode for action
368
+ - `removeActionExecutionMode(action)` - Reset to default execution mode
369
+
370
+ #### Utility Methods
371
+ - `getName()` - Get registry name
372
+ - `isDebugEnabled()` - Check if debug mode is enabled
373
+ - `destroy()` - Clean up all resources
374
+
375
+ ### Configuration Interfaces
227
376
 
228
377
  ```typescript
229
- interface ActionRegisterConfig {
230
- logger?: Logger; // Custom logger implementation
231
- logLevel?: LogLevel; // Log filtering level
232
- name?: string; // Logger name
233
- debug?: boolean; // Enable debug mode
378
+ interface HandlerConfig {
379
+ priority?: number; // Handler priority (higher = first)
380
+ id?: string; // Unique handler identifier
381
+ blocking?: boolean; // Wait for async completion
382
+ once?: boolean; // Remove after first execution
383
+ debounce?: number; // Debounce delay in ms
384
+ throttle?: number; // Throttle delay in ms
385
+ replaceExisting?: boolean; // Replace handler with same ID
386
+ }
387
+
388
+ interface DispatchOptions {
389
+ debounce?: number;
390
+ throttle?: number;
391
+ executionMode?: 'sequential' | 'parallel' | 'race';
392
+ signal?: AbortSignal;
393
+ immediate?: boolean; // Bypass queue
394
+ queuePriority?: number; // Queue priority
395
+ timeout?: number; // Execution timeout
396
+
397
+ retryOnError?: {
398
+ maxAttempts: number;
399
+ delay: number;
400
+ };
401
+
402
+ filter?: {
403
+ handlerIds?: string[];
404
+ excludeHandlerIds?: string[];
405
+ priority?: { min?: number; max?: number };
406
+ custom?: (config: HandlerConfig) => boolean;
407
+ };
408
+
409
+ result?: {
410
+ strategy?: 'first' | 'last' | 'all' | 'merge' | 'custom';
411
+ merger?: <R>(results: R[]) => R;
412
+ collect?: boolean;
413
+ maxResults?: number;
414
+ includeErrors?: boolean;
415
+ };
234
416
  }
235
417
  ```
236
418
 
237
419
  ## TypeScript Support
238
420
 
239
- Full TypeScript support with compile-time type checking:
421
+ Full type safety with excellent IntelliSense support:
240
422
 
241
423
  ```typescript
242
424
  interface AppActions {
243
- // Action without payload
425
+ // Void actions
244
426
  reset: void;
427
+ logout: void;
245
428
 
246
- // Action with payload
247
- setUser: { id: string; name: string };
429
+ // Actions with payloads
430
+ setUser: { id: string; name: string; email: string };
431
+ updatePreferences: { theme: 'light' | 'dark'; language: string };
248
432
 
249
- // Action with optional payload
250
- navigate: string | undefined;
433
+ // Union type payloads
434
+ navigate: { route: string } | { url: URL };
251
435
  }
252
436
 
253
437
  const actions = new ActionRegister<AppActions>();
254
438
 
255
- // ✅ Type-safe dispatch
439
+ // ✅ Type-safe - all good
256
440
  await actions.dispatch('reset');
257
- await actions.dispatch('setUser', { id: '1', name: 'John' });
441
+ await actions.dispatch('setUser', { id: '1', name: 'John', email: 'john@example.com' });
442
+
443
+ // ❌ TypeScript errors
444
+ await actions.dispatch('setUser'); // Missing required payload
445
+ await actions.dispatch('setUser', { id: '1' }); // Missing required fields
446
+ await actions.dispatch('invalidAction'); // Unknown action
447
+ ```
448
+
449
+ ## Migration from v0.3.x
450
+
451
+ Most existing code works without changes. New features are opt-in:
452
+
453
+ ```typescript
454
+ // v0.3.x code - still works
455
+ const actions = new ActionRegister();
456
+ actions.register('myAction', handler);
457
+ await actions.dispatch('myAction', payload);
258
458
 
259
- // TypeScript error - missing payload
260
- await actions.dispatch('setUser');
459
+ // v0.4.x - new features available
460
+ actions.register('myAction', handler, {
461
+ replaceExisting: true // New option
462
+ });
261
463
 
262
- // TypeScript error - wrong payload type
263
- await actions.dispatch('setUser', 'invalid');
464
+ await actions.dispatch('myAction', payload, {
465
+ filter: { priority: { min: 10 } } // New filtering
466
+ });
467
+
468
+ // Clean up when done (recommended)
469
+ actions.destroy();
264
470
  ```
265
471
 
472
+ ## Performance Tips
473
+
474
+ 1. **Use handler IDs** for better debugging and filtering
475
+ 2. **Enable replaceExisting** for React components to prevent duplicates
476
+ 3. **Use immediate: false** (default) to benefit from queue optimizations
477
+ 4. **Call destroy()** when registry is no longer needed
478
+ 5. **Use priority filtering** instead of excludeHandlerIds for better performance
479
+ 6. **Cache ActionRegister instances** - don't create new ones frequently
480
+
266
481
  ## License
267
482
 
268
483
  Apache-2.0
269
484
 
270
- ## Contributing
485
+ ## Links
271
486
 
272
- See the main [repository](https://github.com/mineclover/context-action) for contribution guidelines.
487
+ - [Main Repository](https://github.com/mineclover/context-action)
488
+ - [Documentation](https://mineclover.github.io/context-action/)
489
+ - [React Package](../react/README.md)
490
+ - [Examples](../../example/README.md)