@context-action/core 0.9.0 → 1.0.0-rc.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 +41 -38
- package/dist/index.cjs +1468 -946
- package/dist/index.d.cts +187 -72
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +187 -72
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1469 -943
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -161,19 +161,16 @@ console.log('Result:', result.successResults);
|
|
|
161
161
|
### Memory Management
|
|
162
162
|
|
|
163
163
|
```typescript
|
|
164
|
-
//
|
|
164
|
+
// A finite limit is opt-in and fails registration explicitly on overflow.
|
|
165
165
|
const actions = new ActionRegister<MyActions>({
|
|
166
166
|
registry: {
|
|
167
|
-
maxHandlersPerAction: 1000
|
|
168
|
-
// maxHandlersPerAction: 5000 // Higher limit for complex applications
|
|
169
|
-
// maxHandlersPerAction: Infinity // Disable limit (use with caution)
|
|
167
|
+
maxHandlersPerAction: 1000
|
|
170
168
|
}
|
|
171
169
|
});
|
|
172
170
|
|
|
173
|
-
//
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
// - Infinity: Only for controlled environments with trusted code
|
|
171
|
+
// Omit maxHandlersPerAction for the default unbounded registry.
|
|
172
|
+
// Use a finite limit only where registration ownership is bounded and overflow
|
|
173
|
+
// should be treated as a programming error.
|
|
177
174
|
```
|
|
178
175
|
|
|
179
176
|
## 🚀 New Features (v0.4.0+)
|
|
@@ -232,31 +229,39 @@ actions.register('myAction', handler, {
|
|
|
232
229
|
### Immediate Execution & Queue Control
|
|
233
230
|
|
|
234
231
|
```typescript
|
|
235
|
-
//
|
|
236
|
-
|
|
232
|
+
// Queueing is opt-in for shared mutable state or explicit ordering.
|
|
233
|
+
const queuedActions = new ActionRegister<MyActions>({
|
|
234
|
+
registry: { useConcurrencyQueue: true }
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// Bypass an enabled queue for immediate execution.
|
|
238
|
+
await queuedActions.dispatch('urgentAction', data, {
|
|
237
239
|
immediate: true
|
|
238
240
|
});
|
|
239
241
|
|
|
240
|
-
//
|
|
241
|
-
await
|
|
242
|
+
// Prioritize work within an enabled queue.
|
|
243
|
+
await queuedActions.dispatch('backgroundTask', data, {
|
|
242
244
|
queuePriority: 5
|
|
243
245
|
});
|
|
244
246
|
|
|
245
|
-
// Wall-clock timeout (queue wait
|
|
247
|
+
// Wall-clock timeout (including enabled-queue wait and retry delay).
|
|
246
248
|
// Rejects with ActionTimeoutError while the internal operation drains safely.
|
|
247
249
|
await actions.dispatch('timedAction', data, { timeout: 5000 });
|
|
248
250
|
```
|
|
249
251
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
`queuePriority` on an awaited nested `dispatchWithResult` call.
|
|
254
|
-
top-level dispatches should keep the queue defaults.
|
|
252
|
+
Dispatches run independently by default. When queueing is enabled, it is
|
|
253
|
+
single-slot. A handler that awaits another dispatch on the **same** register
|
|
254
|
+
must make that nested call explicit with `{ immediate: true }`; likewise, do
|
|
255
|
+
not set `queuePriority` on an awaited nested `dispatchWithResult` call.
|
|
255
256
|
|
|
256
257
|
Handlers that perform cancellable I/O can observe `controller.signal`. It is
|
|
257
258
|
aborted for caller cancellation, timeout, provider teardown, and register
|
|
258
259
|
shutdown.
|
|
259
260
|
|
|
261
|
+
A timeout is a caller boundary, not a rollback. A handler that ignores its
|
|
262
|
+
signal can continue while the register drains it for lifecycle cleanup; do not
|
|
263
|
+
retry a mutation after timeout unless its operation is idempotent.
|
|
264
|
+
|
|
260
265
|
### Result Collection with Strategies
|
|
261
266
|
|
|
262
267
|
```typescript
|
|
@@ -277,28 +282,31 @@ console.log('Success:', result.success);
|
|
|
277
282
|
### React Integration Helpers
|
|
278
283
|
|
|
279
284
|
```typescript
|
|
280
|
-
import {
|
|
281
|
-
|
|
282
|
-
ReactDevUtils
|
|
283
|
-
} from '@context-action/
|
|
285
|
+
import {
|
|
286
|
+
createActionContext,
|
|
287
|
+
ReactDevUtils,
|
|
288
|
+
} from '@context-action/react';
|
|
289
|
+
|
|
290
|
+
// `useActionHandler` and `useActionRegister` are returned by the action
|
|
291
|
+
// context factory from `@context-action/react`; the core package is framework-agnostic.
|
|
292
|
+
const { useActionHandler, useActionRegister } = createActionContext<MyActions>('MyActions');
|
|
284
293
|
|
|
285
294
|
// React hook pattern
|
|
286
295
|
function MyComponent() {
|
|
287
296
|
const registry = useActionRegister();
|
|
288
297
|
|
|
289
298
|
// Auto-cleanup on unmount, HMR support
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
'userAction',
|
|
299
|
+
useActionHandler(
|
|
300
|
+
'userAction',
|
|
293
301
|
async (payload) => {
|
|
294
302
|
// Handler logic
|
|
295
303
|
},
|
|
296
|
-
{ priority: 10 }
|
|
297
|
-
[] // dependencies
|
|
304
|
+
{ priority: 10 }
|
|
298
305
|
);
|
|
299
306
|
|
|
300
307
|
// Direct registry dispatch with error handling
|
|
301
308
|
const handleDispatch = useCallback(async (action, payload) => {
|
|
309
|
+
if (!registry) return;
|
|
302
310
|
try {
|
|
303
311
|
await registry.dispatch(action, payload);
|
|
304
312
|
} catch (error) {
|
|
@@ -321,11 +329,11 @@ const stats = ReactDevUtils.getStats(registry);
|
|
|
321
329
|
- **Multiple execution modes** - sequential, parallel, race
|
|
322
330
|
|
|
323
331
|
### ⚡ Performance & Memory Optimizations
|
|
324
|
-
- **
|
|
332
|
+
- **Explicit debug mode** — logs are emitted only with `registry.debug: true`
|
|
325
333
|
- **Optimized handler ID generation** without random numbers
|
|
326
334
|
- **Smart array filtering** - only copies when needed
|
|
327
335
|
- **Automatic memory cleanup** with idle handler cleanup
|
|
328
|
-
- **
|
|
336
|
+
- **Opt-in concurrency queue** for explicit ordering
|
|
329
337
|
|
|
330
338
|
### 🔧 Advanced Configuration
|
|
331
339
|
|
|
@@ -450,12 +458,7 @@ console.log(`Total handlers: ${info.totalHandlers}`);
|
|
|
450
458
|
const stats = actions.getActionStats('updateUser');
|
|
451
459
|
if (stats) {
|
|
452
460
|
console.log(`Handler count: ${stats.handlerCount}`);
|
|
453
|
-
console.log(`Success rate: ${stats.executionStats?.successRate}%`);
|
|
454
|
-
console.log(`Average duration: ${stats.executionStats?.averageDuration}ms`);
|
|
455
461
|
}
|
|
456
|
-
|
|
457
|
-
// Clear statistics
|
|
458
|
-
actions.clearExecutionStats();
|
|
459
462
|
```
|
|
460
463
|
|
|
461
464
|
### Cleanup & Resource Management
|
|
@@ -522,9 +525,9 @@ interface DispatchOptions {
|
|
|
522
525
|
throttle?: number;
|
|
523
526
|
executionMode?: 'sequential' | 'parallel' | 'race';
|
|
524
527
|
signal?: AbortSignal;
|
|
525
|
-
immediate?: boolean; // Bypass queue
|
|
526
|
-
queuePriority?: number; //
|
|
527
|
-
timeout?: number; //
|
|
528
|
+
immediate?: boolean; // Bypass an enabled queue
|
|
529
|
+
queuePriority?: number; // Priority within an enabled queue
|
|
530
|
+
timeout?: number; // Non-negative finite wall-clock timeout
|
|
528
531
|
|
|
529
532
|
retryOnError?: {
|
|
530
533
|
maxAttempts: number;
|
|
@@ -605,7 +608,7 @@ actions.destroy();
|
|
|
605
608
|
|
|
606
609
|
1. **Use handler IDs** for better debugging and filtering
|
|
607
610
|
2. **Enable replaceExisting** for React components to prevent duplicates
|
|
608
|
-
3. **
|
|
611
|
+
3. **Enable `useConcurrencyQueue` only** when independent dispatches must be ordered
|
|
609
612
|
4. **Await destroyAsync()** when shutdown completion must be guaranteed
|
|
610
613
|
5. **Use priority filtering** instead of excludeHandlerIds for better performance
|
|
611
614
|
6. **Cache ActionRegister instances** - don't create new ones frequently
|