@context-action/core 0.2.2 → 0.3.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/dist/index.cjs CHANGED
@@ -28,9 +28,42 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  //#region src/execution-modes.ts
29
29
  /**
30
30
  * Execute handlers in sequential mode (one after another)
31
+ *
32
+ * Executes action handlers one at a time in priority order (highest first).
33
+ * Supports both blocking and non-blocking handlers, with proper abort and
34
+ * termination handling. Handlers can modify payload for subsequent handlers
35
+ * and jump to different priority levels.
36
+ *
37
+ * @template T - The payload type for the action
38
+ * @template R - The result type for handlers
39
+ *
40
+ * @param context - Pipeline execution context containing handlers and state
41
+ * @param createController - Factory function for creating pipeline controllers
42
+ *
43
+ * @throws {Error} When a blocking handler fails or validation errors occur
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * // This is called internally by ActionRegister.dispatch()
48
+ * // when executionMode is 'sequential'
49
+ *
50
+ * // Handlers execute in this order (by priority):
51
+ * // 1. Priority 100: Validation handler
52
+ * // 2. Priority 50: Business logic handler
53
+ * // 3. Priority 10: Logging handler
54
+ *
55
+ * await executeSequential(context, (registration, index) => ({
56
+ * abort: (reason) => { context.aborted = true; context.abortReason = reason },
57
+ * modifyPayload: (modifier) => { context.payload = modifier(context.payload) },
58
+ * // ... other controller methods
59
+ * }))
60
+ * ```
61
+ *
62
+ * @public
31
63
  */
32
64
  async function executeSequential(context, createController) {
33
65
  let i = 0;
66
+ const nonBlockingPromises = [];
34
67
  while (i < context.handlers.length) {
35
68
  if (context.aborted || context.terminated) break;
36
69
  const registration = context.handlers[i];
@@ -56,10 +89,15 @@ async function executeSequential(context, createController) {
56
89
  if (handlerResult !== void 0 && !context.terminated) context.results.push(handlerResult);
57
90
  } else if (result !== void 0 && !context.terminated)
58
91
  /** Collect synchronous result */
59
- if (result instanceof Promise) result.then((asyncResult) => {
60
- if (asyncResult !== void 0 && !context.terminated) context.results.push(asyncResult);
61
- }).catch(() => {});
62
- else context.results.push(result);
92
+ if (result instanceof Promise) {
93
+ const promiseWithHandling = result.then((asyncResult) => {
94
+ if (asyncResult !== void 0 && !context.terminated) context.results.push(asyncResult);
95
+ return asyncResult;
96
+ }).catch((error) => {
97
+ throw error;
98
+ });
99
+ nonBlockingPromises.push(promiseWithHandling);
100
+ } else context.results.push(result);
63
101
  /** Check if pipeline was terminated by controller.return() */
64
102
  if (context.terminated) break;
65
103
  /** Handle jump to priority AFTER handler execution */
@@ -76,12 +114,56 @@ async function executeSequential(context, createController) {
76
114
  } else i++;
77
115
  } catch (error) {
78
116
  if (registration.config.blocking) throw error;
79
- i++;
117
+ throw error;
80
118
  }
81
119
  }
120
+ if (nonBlockingPromises.length > 0) await Promise.all(nonBlockingPromises);
82
121
  }
83
122
  /**
84
123
  * Execute handlers in parallel mode (all at once)
124
+ *
125
+ * Executes all qualifying action handlers simultaneously using Promise.allSettled.
126
+ * Supports both blocking and non-blocking handlers. Blocking handlers can still
127
+ * fail the entire pipeline if they throw errors.
128
+ *
129
+ * @template T - The payload type for the action
130
+ * @template R - The result type for handlers
131
+ *
132
+ * @param context - Pipeline execution context containing handlers and state
133
+ * @param createController - Factory function for creating pipeline controllers
134
+ *
135
+ * @throws {Error} When any blocking handler fails
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * // This is called internally by ActionRegister.dispatch()
140
+ * // when executionMode is 'parallel'
141
+ *
142
+ * // All handlers execute simultaneously:
143
+ * // - Analytics handler (non-blocking)
144
+ * // - Validation handler (blocking)
145
+ * // - Update handler (blocking)
146
+ * // - Notification handler (non-blocking)
147
+ *
148
+ * await executeParallel(context, (registration, index) => ({
149
+ * abort: (reason) => { context.aborted = true },
150
+ * setResult: (result) => { context.results.push(result) },
151
+ * // ... other controller methods
152
+ * }))
153
+ * ```
154
+ *
155
+ * @example Use Case
156
+ * ```typescript
157
+ * // Perfect for independent operations
158
+ * register.setActionExecutionMode('logEvent', 'parallel')
159
+ *
160
+ * // These can all run simultaneously:
161
+ * register.register('logEvent', analyticsHandler, { blocking: false })
162
+ * register.register('logEvent', metricsHandler, { blocking: false })
163
+ * register.register('logEvent', auditHandler, { blocking: true })
164
+ * ```
165
+ *
166
+ * @public
85
167
  */
86
168
  async function executeParallel(context, createController) {
87
169
  /** Filter handlers that should run */
@@ -98,8 +180,10 @@ async function executeParallel(context, createController) {
98
180
  try {
99
181
  const result = registration.handler(context.payload, controller);
100
182
  let handlerResult;
101
- if (result instanceof Promise) handlerResult = await result;
102
- else handlerResult = result;
183
+ if (result instanceof Promise) {
184
+ const resolved = await result;
185
+ handlerResult = resolved;
186
+ } else handlerResult = result;
103
187
  /** Collect result if handler returned something and pipeline wasn't terminated */
104
188
  if (handlerResult !== void 0 && !context.terminated) context.results.push(handlerResult);
105
189
  return {
@@ -141,6 +225,56 @@ async function executeParallel(context, createController) {
141
225
  }
142
226
  /**
143
227
  * Execute handlers in race mode (first to complete wins)
228
+ *
229
+ * Executes all qualifying handlers simultaneously using Promise.race, where
230
+ * the first handler to complete determines the pipeline result. Other handlers
231
+ * are effectively cancelled. Useful for scenarios where you want the fastest
232
+ * response from multiple equivalent handlers.
233
+ *
234
+ * @template T - The payload type for the action
235
+ * @template R - The result type for handlers
236
+ *
237
+ * @param context - Pipeline execution context containing handlers and state
238
+ * @param createController - Factory function for creating pipeline controllers
239
+ *
240
+ * @throws {Error} When the winning handler fails and is blocking
241
+ *
242
+ * @example
243
+ * ```typescript
244
+ * // This is called internally by ActionRegister.dispatch()
245
+ * // when executionMode is 'race'
246
+ *
247
+ * // Multiple data sources racing for fastest response:
248
+ * // - Database handler (might be slow)
249
+ * // - Cache handler (usually fast)
250
+ * // - API handler (variable speed)
251
+ * //
252
+ * // Whichever completes first wins
253
+ *
254
+ * await executeRace(context, (registration, index) => ({
255
+ * return: (result) => {
256
+ * context.terminated = true
257
+ * context.terminationResult = result
258
+ * },
259
+ * // ... other controller methods
260
+ * }))
261
+ * ```
262
+ *
263
+ * @example Use Case
264
+ * ```typescript
265
+ * // Race between multiple data sources
266
+ * register.setActionExecutionMode('fetchUserData', 'race')
267
+ *
268
+ * // These handlers race for fastest response:
269
+ * register.register('fetchUserData', cacheHandler) // Usually fastest
270
+ * register.register('fetchUserData', databaseHandler) // Reliable fallback
271
+ * register.register('fetchUserData', apiHandler) // External source
272
+ *
273
+ * // First to complete wins, others are ignored
274
+ * const result = await register.dispatchWithResult('fetchUserData', { id: '123' })
275
+ * ```
276
+ *
277
+ * @public
144
278
  */
145
279
  async function executeRace(context, createController) {
146
280
  /** Filter handlers that should run */
@@ -158,8 +292,10 @@ async function executeRace(context, createController) {
158
292
  try {
159
293
  const result = registration.handler(context.payload, controller);
160
294
  let handlerResult;
161
- if (result instanceof Promise) handlerResult = await result;
162
- else handlerResult = result;
295
+ if (result instanceof Promise) {
296
+ const resolved = await result;
297
+ handlerResult = resolved;
298
+ } else handlerResult = result;
163
299
  return {
164
300
  success: true,
165
301
  handlerId: registration.id,
@@ -190,8 +326,8 @@ async function executeRace(context, createController) {
190
326
  }
191
327
 
192
328
  //#endregion
193
- //#region ../../node_modules/.pnpm/@oxc-project+runtime@0.81.0/node_modules/@oxc-project/runtime/src/helpers/typeof.js
194
- var require_typeof = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm/@oxc-project+runtime@0.81.0/node_modules/@oxc-project/runtime/src/helpers/typeof.js": ((exports, module) => {
329
+ //#region ../../node_modules/.pnpm/@oxc-project+runtime@0.82.2/node_modules/@oxc-project/runtime/src/helpers/typeof.js
330
+ var require_typeof = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm/@oxc-project+runtime@0.82.2/node_modules/@oxc-project/runtime/src/helpers/typeof.js": ((exports, module) => {
195
331
  function _typeof$2(o) {
196
332
  "@babel/helpers - typeof";
197
333
  return module.exports = _typeof$2 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o$1) {
@@ -204,8 +340,8 @@ var require_typeof = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm/@oxc
204
340
  }) });
205
341
 
206
342
  //#endregion
207
- //#region ../../node_modules/.pnpm/@oxc-project+runtime@0.81.0/node_modules/@oxc-project/runtime/src/helpers/toPrimitive.js
208
- var require_toPrimitive = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm/@oxc-project+runtime@0.81.0/node_modules/@oxc-project/runtime/src/helpers/toPrimitive.js": ((exports, module) => {
343
+ //#region ../../node_modules/.pnpm/@oxc-project+runtime@0.82.2/node_modules/@oxc-project/runtime/src/helpers/toPrimitive.js
344
+ var require_toPrimitive = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm/@oxc-project+runtime@0.82.2/node_modules/@oxc-project/runtime/src/helpers/toPrimitive.js": ((exports, module) => {
209
345
  var _typeof$1 = require_typeof()["default"];
210
346
  function toPrimitive$1(t, r) {
211
347
  if ("object" != _typeof$1(t) || !t) return t;
@@ -221,8 +357,8 @@ var require_toPrimitive = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm
221
357
  }) });
222
358
 
223
359
  //#endregion
224
- //#region ../../node_modules/.pnpm/@oxc-project+runtime@0.81.0/node_modules/@oxc-project/runtime/src/helpers/toPropertyKey.js
225
- var require_toPropertyKey = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm/@oxc-project+runtime@0.81.0/node_modules/@oxc-project/runtime/src/helpers/toPropertyKey.js": ((exports, module) => {
360
+ //#region ../../node_modules/.pnpm/@oxc-project+runtime@0.82.2/node_modules/@oxc-project/runtime/src/helpers/toPropertyKey.js
361
+ var require_toPropertyKey = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm/@oxc-project+runtime@0.82.2/node_modules/@oxc-project/runtime/src/helpers/toPropertyKey.js": ((exports, module) => {
226
362
  var _typeof = require_typeof()["default"];
227
363
  var toPrimitive = require_toPrimitive();
228
364
  function toPropertyKey$1(t) {
@@ -233,8 +369,8 @@ var require_toPropertyKey = /* @__PURE__ */ __commonJS({ "../../node_modules/.pn
233
369
  }) });
234
370
 
235
371
  //#endregion
236
- //#region ../../node_modules/.pnpm/@oxc-project+runtime@0.81.0/node_modules/@oxc-project/runtime/src/helpers/defineProperty.js
237
- var require_defineProperty = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm/@oxc-project+runtime@0.81.0/node_modules/@oxc-project/runtime/src/helpers/defineProperty.js": ((exports, module) => {
372
+ //#region ../../node_modules/.pnpm/@oxc-project+runtime@0.82.2/node_modules/@oxc-project/runtime/src/helpers/defineProperty.js
373
+ var require_defineProperty = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm/@oxc-project+runtime@0.82.2/node_modules/@oxc-project/runtime/src/helpers/defineProperty.js": ((exports, module) => {
238
374
  var toPropertyKey = require_toPropertyKey();
239
375
  function _defineProperty$3(e, r, t) {
240
376
  return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
@@ -252,41 +388,81 @@ var require_defineProperty = /* @__PURE__ */ __commonJS({ "../../node_modules/.p
252
388
  var import_defineProperty$2 = /* @__PURE__ */ __toESM(require_defineProperty(), 1);
253
389
  /**
254
390
  * Action Guard system for managing action execution timing
255
- * @implements action-guard
256
- * @implements performance-optimization
257
- * @implements user-experience-optimization
258
- * @implements class-naming
259
- * @memberof core-concepts
260
- * @internal
261
- * @since 1.0.0
262
391
  *
263
- * Manages action execution timing through debouncing and throttling
264
- * @implements performance-optimization
392
+ * Provides performance optimization and user experience enhancement through
393
+ * debouncing and throttling mechanisms. Debouncing waits for a pause in calls
394
+ * before executing, while throttling limits execution frequency.
265
395
  *
266
- * @example
396
+ * @example Debouncing Search Input
267
397
  * ```typescript
268
- * const guard = new ActionGuard(logger);
398
+ * const guard = new ActionGuard()
399
+ *
400
+ * // Wait 300ms after user stops typing before searching
401
+ * register.register('searchUsers', async (payload, controller) => {
402
+ * const query = payload.query
403
+ * if (query.length < 2) return
404
+ *
405
+ * const results = await userService.search(query)
406
+ * controller.setResult(results)
407
+ * }, {
408
+ * debounce: 300, // Built into ActionRegister via ActionGuard
409
+ * tags: ['search', 'user-input']
410
+ * })
411
+ * ```
269
412
  *
270
- * // Debounce search input (wait 300ms after typing stops)
413
+ * @example Throttling High-Frequency Events
414
+ * ```typescript
415
+ * // Limit scroll position updates to once per 100ms
416
+ * register.register('updateScrollPosition', (payload, controller) => {
417
+ * scrollState.setValue(payload.position)
418
+ * }, {
419
+ * throttle: 100, // Built into ActionRegister via ActionGuard
420
+ * tags: ['scroll', 'performance']
421
+ * })
422
+ * ```
423
+ *
424
+ * @example Manual Usage (Advanced)
425
+ * ```typescript
426
+ * const guard = new ActionGuard()
427
+ *
428
+ * // Manual debouncing
271
429
  * if (await guard.debounce('search', 300)) {
272
- * executeSearch();
430
+ * performSearch() // Only executes after 300ms pause
273
431
  * }
274
432
  *
275
- * // Throttle scroll handler (max once per 100ms)
433
+ * // Manual throttling
276
434
  * if (guard.throttle('scroll', 100)) {
277
- * updateScrollPosition();
435
+ * updateUI() // Max once per 100ms
278
436
  * }
279
437
  * ```
438
+ *
439
+ * @internal
280
440
  */
281
441
  var ActionGuard = class {
282
442
  constructor() {
283
443
  (0, import_defineProperty$2.default)(this, "guards", /* @__PURE__ */ new Map());
284
444
  }
285
445
  /**
286
- * Check if action should be debounced
287
- * @param actionKey - Unique key for the action
288
- * @param debounceMs - Debounce delay in milliseconds
289
- * @returns Promise that resolves when debounce period is complete
446
+ * Apply debouncing to an action
447
+ *
448
+ * Debouncing waits for a specified delay after the last call before allowing
449
+ * execution. Each new call resets the timer. Useful for search inputs, resize
450
+ * handlers, and other high-frequency user interactions.
451
+ *
452
+ * @param actionKey - Unique identifier for the action being debounced
453
+ * @param debounceMs - Delay in milliseconds to wait after the last call
454
+ *
455
+ * @returns Promise resolving to true if execution should proceed, false if cancelled
456
+ *
457
+ * @example Search Input Debouncing
458
+ * ```typescript
459
+ * // Only search after user stops typing for 300ms
460
+ * if (await guard.debounce('userSearch', 300)) {
461
+ * performSearch(query)
462
+ * }
463
+ * ```
464
+ *
465
+ * @internal
290
466
  */
291
467
  async debounce(actionKey, debounceMs) {
292
468
  /** Get or create guard state for this action */
@@ -321,10 +497,26 @@ var ActionGuard = class {
321
497
  });
322
498
  }
323
499
  /**
324
- * Check if action should be throttled
325
- * @param actionKey - Unique key for the action
326
- * @param throttleMs - Throttle delay in milliseconds
327
- * @returns True if action should proceed, false if throttled
500
+ * Apply throttling to an action
501
+ *
502
+ * Throttling limits execution frequency by ensuring a minimum interval between
503
+ * calls. Unlike debouncing, throttling executes immediately on the first call
504
+ * and then blocks subsequent calls until the interval expires.
505
+ *
506
+ * @param actionKey - Unique identifier for the action being throttled
507
+ * @param throttleMs - Minimum interval in milliseconds between executions
508
+ *
509
+ * @returns True if execution should proceed, false if currently throttled
510
+ *
511
+ * @example Scroll Handler Throttling
512
+ * ```typescript
513
+ * // Update scroll position max once per 100ms
514
+ * if (guard.throttle('scrollUpdate', 100)) {
515
+ * updateScrollPosition()
516
+ * }
517
+ * ```
518
+ *
519
+ * @internal
328
520
  */
329
521
  throttle(actionKey, throttleMs) {
330
522
  /** Get or create guard state for this action */
@@ -363,8 +555,14 @@ var ActionGuard = class {
363
555
  return false;
364
556
  }
365
557
  /**
366
- * Clear all guards for an action
367
- * @param actionKey - Action key to clear
558
+ * Clear all guard state for a specific action
559
+ *
560
+ * Removes debounce and throttle timers for the specified action,
561
+ * preventing memory leaks and allowing immediate re-execution.
562
+ *
563
+ * @param actionKey - Action identifier to clear guards for
564
+ *
565
+ * @internal
368
566
  */
369
567
  clearGuards(actionKey) {
370
568
  const state = this.guards.get(actionKey);
@@ -381,7 +579,12 @@ var ActionGuard = class {
381
579
  }
382
580
  }
383
581
  /**
384
- * Clear all guards
582
+ * Clear all guard states for all actions
583
+ *
584
+ * Removes all active debounce and throttle timers, useful for cleanup
585
+ * when shutting down the action system or resetting state.
586
+ *
587
+ * @internal
385
588
  */
386
589
  clearAll() {
387
590
  /** Iterate through all guard states and clear their timers */
@@ -399,14 +602,28 @@ var ActionGuard = class {
399
602
  this.guards.clear();
400
603
  }
401
604
  /**
402
- * Get current guard state for debugging
403
- * @param actionKey - Action key to inspect
605
+ * Get current guard state for debugging purposes
606
+ *
607
+ * Returns the internal state for a specific action, including timer
608
+ * information and execution timestamps.
609
+ *
610
+ * @param actionKey - Action identifier to inspect
611
+ * @returns Guard state or undefined if no state exists
612
+ *
613
+ * @internal
404
614
  */
405
615
  getGuardState(actionKey) {
406
616
  return this.guards.get(actionKey);
407
617
  }
408
618
  /**
409
- * Get all active guards for debugging
619
+ * Get all active guard states for debugging purposes
620
+ *
621
+ * Returns a copy of all current guard states, useful for monitoring
622
+ * and debugging rate limiting behavior across all actions.
623
+ *
624
+ * @returns Map of action keys to their guard states
625
+ *
626
+ * @internal
410
627
  */
411
628
  getAllGuardStates() {
412
629
  return new Map(this.guards);
@@ -523,33 +740,84 @@ var OperationQueue = class {
523
740
  //#region src/ActionRegister.ts
524
741
  var import_defineProperty = /* @__PURE__ */ __toESM(require_defineProperty(), 1);
525
742
  /**
526
- * 중앙화된 액션 등록 디스패치 시스템으로, 타입 안전한 액션 파이프라인 관리를 제공하는 핵심 클래스입니다.
743
+ * Action Register for managing action handlers with priority-based execution
527
744
  *
528
- * @implements {ActionRegister}
529
- * @implements {Action Pipeline System}
530
- * @memberof core-concepts
745
+ * Central action registration and dispatch system providing type-safe action pipeline management.
746
+ * Supports sequential, parallel, and race execution modes with advanced handler filtering,
747
+ * throttling, debouncing, and comprehensive result collection.
531
748
  *
532
- * @example
749
+ * @template TActionMap - Action payload mapping interface extending ActionPayloadMap
750
+ *
751
+ * @example Basic Usage
533
752
  * ```typescript
534
753
  * interface AppActions extends ActionPayloadMap {
535
- * updateUser: { id: string; name: string };
536
- * calculateTotal: void;
754
+ * updateUser: { id: string; name: string; email: string }
755
+ * deleteUser: { id: string }
756
+ * resetUser: void
537
757
  * }
538
758
  *
539
759
  * const register = new ActionRegister<AppActions>({
540
760
  * name: 'AppRegister',
541
- * logLevel: LogLevel.DEBUG
542
- * });
761
+ * registry: { debug: true, maxHandlers: 10 }
762
+ * })
763
+ *
764
+ * // Register handler with priority
765
+ * register.register('updateUser', async (payload, controller) => {
766
+ * await userService.update(payload.id, payload)
767
+ * controller.setResult({ success: true, userId: payload.id })
768
+ * }, { priority: 10, tags: ['user', 'crud'] })
769
+ *
770
+ * // Dispatch action
771
+ * await register.dispatch('updateUser', {
772
+ * id: '123',
773
+ * name: 'John Doe',
774
+ * email: 'john@example.com'
775
+ * })
776
+ * ```
543
777
  *
544
- * // 핸들러 등록
545
- * register.register('updateUser', ({ id, name }, controller) => {
546
- * userStore.setValue({ id, name });
547
- * // 핸들러가 자동으로 다음 핸들러로 진행
548
- * }, { priority: 10 });
778
+ * @example With Multiple Handlers
779
+ * ```typescript
780
+ * // High priority validation handler
781
+ * register.register('updateUser', async (payload, controller) => {
782
+ * if (!payload.email.includes('@')) {
783
+ * controller.abort('Invalid email format')
784
+ * return
785
+ * }
786
+ * }, { priority: 100, category: 'validation' })
549
787
  *
550
- * // 액션 디스패치
551
- * await register.dispatch('updateUser', { id: '1', name: 'John' });
788
+ * // Lower priority update handler
789
+ * register.register('updateUser', async (payload, controller) => {
790
+ * const user = await userService.update(payload.id, payload)
791
+ * controller.setResult(user)
792
+ * }, { priority: 50, category: 'business-logic' })
552
793
  * ```
794
+ *
795
+ * @example Advanced Configuration
796
+ * ```typescript
797
+ * const register = new ActionRegister<AppActions>({
798
+ * name: 'AdvancedRegister',
799
+ * registry: {
800
+ * debug: true,
801
+ * maxHandlers: 20,
802
+ * defaultExecutionMode: 'parallel',
803
+ * autoCleanup: true
804
+ * }
805
+ * })
806
+ *
807
+ * // Handler with debouncing and tags
808
+ * register.register('searchUsers', async (payload, controller) => {
809
+ * const results = await userService.search(payload.query)
810
+ * controller.setResult(results)
811
+ * }, {
812
+ * priority: 10,
813
+ * debounce: 300,
814
+ * tags: ['search', 'user'],
815
+ * category: 'query',
816
+ * once: false
817
+ * })
818
+ * ```
819
+ *
820
+ * @public
553
821
  */
554
822
  var ActionRegister = class {
555
823
  constructor(config = {}) {
@@ -576,6 +844,43 @@ var ActionRegister = class {
576
844
  concurrencyProtection: true
577
845
  });
578
846
  }
847
+ /**
848
+ * Register an action handler with optional configuration
849
+ *
850
+ * @param action - The action type to register handler for
851
+ * @param handler - The handler function to execute
852
+ * @param config - Optional handler configuration including priority, tags, etc.
853
+ *
854
+ * @returns Unregister function to remove this handler
855
+ *
856
+ * @throws {Error} When maximum handlers limit is reached
857
+ *
858
+ * @example Basic Registration
859
+ * ```typescript
860
+ * const unregister = register.register('updateUser', async (payload, controller) => {
861
+ * await userService.update(payload.id, payload)
862
+ * })
863
+ *
864
+ * // Later remove the handler
865
+ * unregister()
866
+ * ```
867
+ *
868
+ * @example With Priority and Configuration
869
+ * ```typescript
870
+ * register.register('validateUser', async (payload, controller) => {
871
+ * if (!payload.email) {
872
+ * controller.abort('Email is required')
873
+ * }
874
+ * }, {
875
+ * priority: 100,
876
+ * tags: ['validation'],
877
+ * category: 'security',
878
+ * once: false
879
+ * })
880
+ * ```
881
+ *
882
+ * @public
883
+ */
579
884
  register(action, handler, config = {}) {
580
885
  const handlerId = config.id || `handler_${++this.handlerCounter}_${Math.random().toString(36).substr(2, 5)}`;
581
886
  const unregisterFn = this._performRegistrationSync(action, handler, config, handlerId);
@@ -708,6 +1013,48 @@ var ActionRegister = class {
708
1013
  }
709
1014
  };
710
1015
  }
1016
+ /**
1017
+ * Dispatch an action with optional execution options
1018
+ *
1019
+ * @param action - The action type to dispatch
1020
+ * @param payload - The action payload data
1021
+ * @param options - Optional dispatch options (execution mode, filters, etc.)
1022
+ *
1023
+ * @returns Promise that resolves when all handlers complete
1024
+ *
1025
+ * @throws {Error} When action dispatching fails
1026
+ *
1027
+ * @example Basic Dispatch
1028
+ * ```typescript
1029
+ * await register.dispatch('updateUser', {
1030
+ * id: '123',
1031
+ * name: 'John Doe',
1032
+ * email: 'john@example.com'
1033
+ * })
1034
+ * ```
1035
+ *
1036
+ * @example With Options
1037
+ * ```typescript
1038
+ * await register.dispatch('updateUser', payload, {
1039
+ * executionMode: 'parallel',
1040
+ * timeout: 5000,
1041
+ * filter: {
1042
+ * tags: ['validation', 'business-logic'],
1043
+ * excludeCategory: 'analytics'
1044
+ * }
1045
+ * })
1046
+ * ```
1047
+ *
1048
+ * @example With Throttling
1049
+ * ```typescript
1050
+ * await register.dispatch('searchUsers', { query: 'john' }, {
1051
+ * throttle: 300,
1052
+ * debounce: 100
1053
+ * })
1054
+ * ```
1055
+ *
1056
+ * @public
1057
+ */
711
1058
  async dispatch(action, payload, options) {
712
1059
  return this.dispatchQueue.enqueue(async () => {
713
1060
  return this._performDispatch(action, payload, options);
@@ -717,6 +1064,28 @@ var ActionRegister = class {
717
1064
  * 🆕 실제 디스패치 작업 수행 (큐에서 호출됨)
718
1065
  */
719
1066
  async _performDispatch(action, payload, options) {
1067
+ if (payload && typeof payload === "object" && payload !== null && typeof process !== "undefined" && process.env?.NODE_ENV === "development") {
1068
+ payload instanceof Event;
1069
+ payload instanceof Element;
1070
+ payload.preventDefault;
1071
+ payload.stopPropagation;
1072
+ payload.currentTarget;
1073
+ const hasTarget = payload.target !== void 0;
1074
+ hasTarget && payload.target;
1075
+ hasTarget && payload.target instanceof Element;
1076
+ if (typeof process !== "undefined" && process.env?.DEBUG_CONTEXT_ACTION || typeof process !== "undefined" && process.env?.NODE_ENV === "development") {
1077
+ const nestedDOMProperties = [];
1078
+ Object.keys(payload).forEach((key) => {
1079
+ const prop = payload[key];
1080
+ if (prop instanceof Element || prop instanceof Event) nestedDOMProperties.push(`${key}: ${prop instanceof Element ? "Element" : "Event"}`);
1081
+ });
1082
+ if (nestedDOMProperties.length > 0) console.debug(`[Context-Action] 📋 Nested DOM objects in action "${String(action)}":`, {
1083
+ registry: this.name,
1084
+ nestedDOMProperties,
1085
+ note: "This is informational - usually not a problem"
1086
+ });
1087
+ }
1088
+ }
720
1089
  let autoAbortController;
721
1090
  let effectiveSignal = options?.signal;
722
1091
  if (options?.autoAbort?.enabled) {
@@ -784,7 +1153,9 @@ var ActionRegister = class {
784
1153
  if (effectiveSignal && abortHandler) effectiveSignal.addEventListener("abort", abortHandler);
785
1154
  try {
786
1155
  await this.executePipeline(context, autoAbortController, options?.autoAbort);
1156
+ console.log(`[ActionRegister] Pipeline execution succeeded for ${String(action)}`);
787
1157
  } catch (error) {
1158
+ console.log(`[ActionRegister] Pipeline execution failed for ${String(action)}:`, error);
788
1159
  executionSuccess = false;
789
1160
  throw error;
790
1161
  } finally {
@@ -793,6 +1164,43 @@ var ActionRegister = class {
793
1164
  this.updateExecutionStats(action, executionSuccess, duration);
794
1165
  }
795
1166
  }
1167
+ /**
1168
+ * Dispatch an action and return detailed execution results
1169
+ *
1170
+ * @param action - The action type to dispatch
1171
+ * @param payload - The action payload data
1172
+ * @param options - Optional dispatch options including result collection strategy
1173
+ *
1174
+ * @returns Promise resolving to comprehensive execution results
1175
+ *
1176
+ * @example Basic Result Collection
1177
+ * ```typescript
1178
+ * const result = await register.dispatchWithResult('updateUser', payload)
1179
+ *
1180
+ * if (result.success) {
1181
+ * console.log(`Executed ${result.execution.handlersExecuted} handlers`)
1182
+ * console.log(`Duration: ${result.execution.duration}ms`)
1183
+ * }
1184
+ * ```
1185
+ *
1186
+ * @example Advanced Result Processing
1187
+ * ```typescript
1188
+ * const result = await register.dispatchWithResult('processOrder', order, {
1189
+ * result: {
1190
+ * collect: true,
1191
+ * strategy: 'merge',
1192
+ * maxResults: 5,
1193
+ * merger: (results) => results.reduce((acc, curr) => ({ ...acc, ...curr }), {})
1194
+ * }
1195
+ * })
1196
+ *
1197
+ * if (result.terminated) {
1198
+ * console.log('Handler returned early:', result.result)
1199
+ * }
1200
+ * ```
1201
+ *
1202
+ * @public
1203
+ */
796
1204
  async dispatchWithResult(action, payload, options) {
797
1205
  const startTime = Date.now();
798
1206
  let autoAbortController;
@@ -1095,22 +1503,105 @@ var ActionRegister = class {
1095
1503
  if (success) stats.successCount++;
1096
1504
  else stats.errorCount++;
1097
1505
  }
1506
+ /**
1507
+ * Get the number of registered handlers for an action
1508
+ *
1509
+ * @param action - The action type to count handlers for
1510
+ *
1511
+ * @returns Number of registered handlers
1512
+ *
1513
+ * @example
1514
+ * ```typescript
1515
+ * register.register('updateUser', handler1)
1516
+ * register.register('updateUser', handler2)
1517
+ *
1518
+ * console.log(register.getHandlerCount('updateUser')) // 2
1519
+ * ```
1520
+ *
1521
+ * @public
1522
+ */
1098
1523
  getHandlerCount(action) {
1099
1524
  const pipeline = this.pipelines.get(action);
1100
1525
  return pipeline ? pipeline.length : 0;
1101
1526
  }
1527
+ /**
1528
+ * Check if an action has any registered handlers
1529
+ *
1530
+ * @param action - The action type to check
1531
+ *
1532
+ * @returns True if action has handlers, false otherwise
1533
+ *
1534
+ * @example
1535
+ * ```typescript
1536
+ * if (register.hasHandlers('updateUser')) {
1537
+ * await register.dispatch('updateUser', userData)
1538
+ * }
1539
+ * ```
1540
+ *
1541
+ * @public
1542
+ */
1102
1543
  hasHandlers(action) {
1103
1544
  return this.getHandlerCount(action) > 0;
1104
1545
  }
1546
+ /**
1547
+ * Get all registered action types
1548
+ *
1549
+ * @returns Array of all registered action types
1550
+ *
1551
+ * @example
1552
+ * ```typescript
1553
+ * const actions = register.getRegisteredActions()
1554
+ * console.log('Registered actions:', actions) // ['updateUser', 'deleteUser', 'resetUser']
1555
+ * ```
1556
+ *
1557
+ * @public
1558
+ */
1105
1559
  getRegisteredActions() {
1106
1560
  return Array.from(this.pipelines.keys());
1107
1561
  }
1562
+ /**
1563
+ * Remove all handlers for a specific action
1564
+ *
1565
+ * @param action - The action type to clear handlers for
1566
+ *
1567
+ * @example
1568
+ * ```typescript
1569
+ * register.clearAction('updateUser')
1570
+ * console.log(register.hasHandlers('updateUser')) // false
1571
+ * ```
1572
+ *
1573
+ * @public
1574
+ */
1108
1575
  clearAction(action) {
1109
1576
  this.pipelines.delete(action);
1110
1577
  }
1578
+ /**
1579
+ * Remove all handlers for all actions
1580
+ *
1581
+ * @example
1582
+ * ```typescript
1583
+ * register.clearAll()
1584
+ * console.log(register.getRegisteredActions().length) // 0
1585
+ * ```
1586
+ *
1587
+ * @public
1588
+ */
1111
1589
  clearAll() {
1112
1590
  this.pipelines.clear();
1113
1591
  }
1592
+ /**
1593
+ * Get the name of this action register
1594
+ *
1595
+ * @returns The register name
1596
+ *
1597
+ * @example
1598
+ * ```typescript
1599
+ * const register = new ActionRegister({ name: 'UserRegister' })
1600
+ * console.log(register.getName()) // 'UserRegister'
1601
+ * ```
1602
+ *
1603
+ * @public
1604
+ */
1114
1605
  getName() {
1115
1606
  return this.name;
1116
1607
  }
@@ -1164,6 +1655,7 @@ var ActionRegister = class {
1164
1655
  return {
1165
1656
  action,
1166
1657
  handlerCount: pipeline.length,
1658
+ totalHandlers: pipeline.length,
1167
1659
  handlersByPriority,
1168
1660
  executionStats
1169
1661
  };