@okyrychenko-dev/react-action-guard 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.d.cts CHANGED
@@ -1,17 +1,16 @@
1
- import * as zustand from 'zustand';
2
-
3
- type BlockingAction = "add" | "remove" | "update" | "cancel" | "timeout";
4
- type MiddlewareBlockerConfig = BlockerConfig;
5
- interface MiddlewareContext {
6
- action: BlockingAction;
7
- blockerId: string;
8
- config?: MiddlewareBlockerConfig;
9
- timestamp: number;
10
- prevState?: MiddlewareBlockerConfig;
11
- }
12
- type Middleware = (context: MiddlewareContext) => void | Promise<void>;
13
-
14
- declare const loggerMiddleware: Middleware;
1
+ /**
2
+ * Hook to wrap async functions with automatic blocking/unblocking
3
+ *
4
+ * Creates a wrapper function that automatically adds a blocker before executing
5
+ * the async function and removes it after completion (success or failure).
6
+ *
7
+ * @template T - The return type of the async function
8
+ * @param actionId - Unique identifier for the action (used in blocker ID and reason)
9
+ * @param scope - Scope(s) to block during execution (default: "global")
10
+ * @returns Function that wraps async functions with blocking behavior
11
+ *
12
+ */
13
+ declare const useAsyncAction: <T = unknown>(actionId: string, scope?: string | ReadonlyArray<string>) => ((asyncFn: () => Promise<T>) => Promise<T>);
15
14
 
16
15
  type AnalyticsEventData = Record<string, string | number | ReadonlyArray<string> | undefined>;
17
16
  type AnalyticsProvider = "ga" | "mixpanel" | "amplitude";
@@ -29,8 +28,21 @@ interface CustomAnalyticsConfig {
29
28
  }
30
29
  type AnalyticsConfig = GoogleAnalyticsConfig | MixpanelConfig | AmplitudeConfig | CustomAnalyticsConfig;
31
30
 
31
+ type BlockingAction = "add" | "remove" | "update" | "cancel" | "timeout";
32
+ type MiddlewareBlockerConfig = BlockerConfig;
33
+ interface MiddlewareContext {
34
+ action: BlockingAction;
35
+ blockerId: string;
36
+ config?: MiddlewareBlockerConfig;
37
+ timestamp: number;
38
+ prevState?: MiddlewareBlockerConfig;
39
+ }
40
+ type Middleware = (context: MiddlewareContext) => void | Promise<void>;
41
+
32
42
  declare const createAnalyticsMiddleware: (config: AnalyticsConfig) => Middleware;
33
43
 
44
+ declare const loggerMiddleware: Middleware;
45
+
34
46
  interface PerformanceConfig {
35
47
  slowBlockThreshold?: number;
36
48
  onSlowBlock?: (blockerId: string, duration: number) => void;
@@ -98,25 +110,10 @@ type UIBlockingStore = UIBlockingStoreState & UIBlockingStoreActions;
98
110
  * - Scope-based blocking (global, specific areas, or multiple scopes)
99
111
  * - Automatic cleanup on unmount (when using hooks)
100
112
  * - DevTools integration for debugging
113
+ * - Automatic shallow comparison for selectors
101
114
  *
102
115
  */
103
- declare const useUIBlockingStore: zustand.UseBoundStore<Omit<zustand.StoreApi<UIBlockingStore>, "setState" | "devtools"> & {
104
- setState(partial: UIBlockingStore | Partial<UIBlockingStore> | ((state: UIBlockingStore) => UIBlockingStore | Partial<UIBlockingStore>), replace?: false | undefined, action?: (string | {
105
- [x: string]: unknown;
106
- [x: number]: unknown;
107
- [x: symbol]: unknown;
108
- type: string;
109
- }) | undefined): void;
110
- setState(state: UIBlockingStore | ((state: UIBlockingStore) => UIBlockingStore), replace: true, action?: (string | {
111
- [x: string]: unknown;
112
- [x: number]: unknown;
113
- [x: symbol]: unknown;
114
- type: string;
115
- }) | undefined): void;
116
- devtools: {
117
- cleanup: () => void;
118
- };
119
- }>;
116
+ declare const useUIBlockingStore: <T>(selector: (state: UIBlockingStore) => T) => T;
120
117
 
121
118
  /**
122
119
  * Hook to automatically add and remove a blocker based on component lifecycle
@@ -131,32 +128,6 @@ declare const useUIBlockingStore: zustand.UseBoundStore<Omit<zustand.StoreApi<UI
131
128
  */
132
129
  declare const useBlocker: (blockerId: string, config: BlockerConfig, isActive?: boolean) => void;
133
130
 
134
- /**
135
- * Hook to check if a scope is currently blocked
136
- *
137
- * Returns a boolean indicating whether the specified scope(s) are blocked.
138
- * Automatically re-renders when the blocking state changes.
139
- *
140
- * @param scope - Scope or array of scopes to check (default: "global")
141
- * @returns True if any of the specified scopes are blocked
142
- *
143
- */
144
- declare const useIsBlocked: (scope?: string | ReadonlyArray<string>) => boolean;
145
-
146
- /**
147
- * Hook to wrap async functions with automatic blocking/unblocking
148
- *
149
- * Creates a wrapper function that automatically adds a blocker before executing
150
- * the async function and removes it after completion (success or failure).
151
- *
152
- * @template T - The return type of the async function
153
- * @param actionId - Unique identifier for the action (used in blocker ID and reason)
154
- * @param scope - Scope(s) to block during execution (default: "global")
155
- * @returns Function that wraps async functions with blocking behavior
156
- *
157
- */
158
- declare const useAsyncAction: <T = unknown>(actionId: string, scope?: string | ReadonlyArray<string>) => ((asyncFn: () => Promise<T>) => Promise<T>);
159
-
160
131
  /**
161
132
  * Configuration for conditional blocker hook.
162
133
  *
@@ -233,6 +204,18 @@ interface UseConfirmableBlockerReturn {
233
204
  */
234
205
  declare const useConfirmableBlocker: (blockerId: string, config: ConfirmableBlockerConfig) => UseConfirmableBlockerReturn;
235
206
 
207
+ /**
208
+ * Hook to check if a scope is currently blocked
209
+ *
210
+ * Returns a boolean indicating whether the specified scope(s) are blocked.
211
+ * Automatically re-renders when the blocking state changes.
212
+ *
213
+ * @param scope - Scope or array of scopes to check (default: "global")
214
+ * @returns True if any of the specified scopes are blocked
215
+ *
216
+ */
217
+ declare const useIsBlocked: (scope?: string | ReadonlyArray<string>) => boolean;
218
+
236
219
  /**
237
220
  * Schedule configuration for time-based blocking.
238
221
  *
package/dist/index.d.ts CHANGED
@@ -1,17 +1,16 @@
1
- import * as zustand from 'zustand';
2
-
3
- type BlockingAction = "add" | "remove" | "update" | "cancel" | "timeout";
4
- type MiddlewareBlockerConfig = BlockerConfig;
5
- interface MiddlewareContext {
6
- action: BlockingAction;
7
- blockerId: string;
8
- config?: MiddlewareBlockerConfig;
9
- timestamp: number;
10
- prevState?: MiddlewareBlockerConfig;
11
- }
12
- type Middleware = (context: MiddlewareContext) => void | Promise<void>;
13
-
14
- declare const loggerMiddleware: Middleware;
1
+ /**
2
+ * Hook to wrap async functions with automatic blocking/unblocking
3
+ *
4
+ * Creates a wrapper function that automatically adds a blocker before executing
5
+ * the async function and removes it after completion (success or failure).
6
+ *
7
+ * @template T - The return type of the async function
8
+ * @param actionId - Unique identifier for the action (used in blocker ID and reason)
9
+ * @param scope - Scope(s) to block during execution (default: "global")
10
+ * @returns Function that wraps async functions with blocking behavior
11
+ *
12
+ */
13
+ declare const useAsyncAction: <T = unknown>(actionId: string, scope?: string | ReadonlyArray<string>) => ((asyncFn: () => Promise<T>) => Promise<T>);
15
14
 
16
15
  type AnalyticsEventData = Record<string, string | number | ReadonlyArray<string> | undefined>;
17
16
  type AnalyticsProvider = "ga" | "mixpanel" | "amplitude";
@@ -29,8 +28,21 @@ interface CustomAnalyticsConfig {
29
28
  }
30
29
  type AnalyticsConfig = GoogleAnalyticsConfig | MixpanelConfig | AmplitudeConfig | CustomAnalyticsConfig;
31
30
 
31
+ type BlockingAction = "add" | "remove" | "update" | "cancel" | "timeout";
32
+ type MiddlewareBlockerConfig = BlockerConfig;
33
+ interface MiddlewareContext {
34
+ action: BlockingAction;
35
+ blockerId: string;
36
+ config?: MiddlewareBlockerConfig;
37
+ timestamp: number;
38
+ prevState?: MiddlewareBlockerConfig;
39
+ }
40
+ type Middleware = (context: MiddlewareContext) => void | Promise<void>;
41
+
32
42
  declare const createAnalyticsMiddleware: (config: AnalyticsConfig) => Middleware;
33
43
 
44
+ declare const loggerMiddleware: Middleware;
45
+
34
46
  interface PerformanceConfig {
35
47
  slowBlockThreshold?: number;
36
48
  onSlowBlock?: (blockerId: string, duration: number) => void;
@@ -98,25 +110,10 @@ type UIBlockingStore = UIBlockingStoreState & UIBlockingStoreActions;
98
110
  * - Scope-based blocking (global, specific areas, or multiple scopes)
99
111
  * - Automatic cleanup on unmount (when using hooks)
100
112
  * - DevTools integration for debugging
113
+ * - Automatic shallow comparison for selectors
101
114
  *
102
115
  */
103
- declare const useUIBlockingStore: zustand.UseBoundStore<Omit<zustand.StoreApi<UIBlockingStore>, "setState" | "devtools"> & {
104
- setState(partial: UIBlockingStore | Partial<UIBlockingStore> | ((state: UIBlockingStore) => UIBlockingStore | Partial<UIBlockingStore>), replace?: false | undefined, action?: (string | {
105
- [x: string]: unknown;
106
- [x: number]: unknown;
107
- [x: symbol]: unknown;
108
- type: string;
109
- }) | undefined): void;
110
- setState(state: UIBlockingStore | ((state: UIBlockingStore) => UIBlockingStore), replace: true, action?: (string | {
111
- [x: string]: unknown;
112
- [x: number]: unknown;
113
- [x: symbol]: unknown;
114
- type: string;
115
- }) | undefined): void;
116
- devtools: {
117
- cleanup: () => void;
118
- };
119
- }>;
116
+ declare const useUIBlockingStore: <T>(selector: (state: UIBlockingStore) => T) => T;
120
117
 
121
118
  /**
122
119
  * Hook to automatically add and remove a blocker based on component lifecycle
@@ -131,32 +128,6 @@ declare const useUIBlockingStore: zustand.UseBoundStore<Omit<zustand.StoreApi<UI
131
128
  */
132
129
  declare const useBlocker: (blockerId: string, config: BlockerConfig, isActive?: boolean) => void;
133
130
 
134
- /**
135
- * Hook to check if a scope is currently blocked
136
- *
137
- * Returns a boolean indicating whether the specified scope(s) are blocked.
138
- * Automatically re-renders when the blocking state changes.
139
- *
140
- * @param scope - Scope or array of scopes to check (default: "global")
141
- * @returns True if any of the specified scopes are blocked
142
- *
143
- */
144
- declare const useIsBlocked: (scope?: string | ReadonlyArray<string>) => boolean;
145
-
146
- /**
147
- * Hook to wrap async functions with automatic blocking/unblocking
148
- *
149
- * Creates a wrapper function that automatically adds a blocker before executing
150
- * the async function and removes it after completion (success or failure).
151
- *
152
- * @template T - The return type of the async function
153
- * @param actionId - Unique identifier for the action (used in blocker ID and reason)
154
- * @param scope - Scope(s) to block during execution (default: "global")
155
- * @returns Function that wraps async functions with blocking behavior
156
- *
157
- */
158
- declare const useAsyncAction: <T = unknown>(actionId: string, scope?: string | ReadonlyArray<string>) => ((asyncFn: () => Promise<T>) => Promise<T>);
159
-
160
131
  /**
161
132
  * Configuration for conditional blocker hook.
162
133
  *
@@ -233,6 +204,18 @@ interface UseConfirmableBlockerReturn {
233
204
  */
234
205
  declare const useConfirmableBlocker: (blockerId: string, config: ConfirmableBlockerConfig) => UseConfirmableBlockerReturn;
235
206
 
207
+ /**
208
+ * Hook to check if a scope is currently blocked
209
+ *
210
+ * Returns a boolean indicating whether the specified scope(s) are blocked.
211
+ * Automatically re-renders when the blocking state changes.
212
+ *
213
+ * @param scope - Scope or array of scopes to check (default: "global")
214
+ * @returns True if any of the specified scopes are blocked
215
+ *
216
+ */
217
+ declare const useIsBlocked: (scope?: string | ReadonlyArray<string>) => boolean;
218
+
236
219
  /**
237
220
  * Schedule configuration for time-based blocking.
238
221
  *
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
- import { useEffect, useCallback, useRef, useState } from 'react';
2
- import { create } from 'zustand';
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
3
2
  import { devtools } from 'zustand/middleware';
3
+ import { createStore, useStore } from 'zustand';
4
+ import { useShallow } from 'zustand/shallow';
4
5
 
5
- // src/hooks/useBlocker.ts
6
+ // src/hooks/useAsyncAction/useAsyncAction.ts
6
7
 
7
8
  // src/store/uiBlockingStore.constants.ts
8
9
  var DEFAULT_SCOPE = "global";
@@ -10,8 +11,13 @@ var DEFAULT_REASON = "Unknown";
10
11
  var DEFAULT_PRIORITY = 0;
11
12
  var ASYNC_ACTION_PRIORITY = 20;
12
13
  var DEVTOOLS_NAME = "UIBlocking";
13
-
14
- // src/store/uiBlockingStore.utils.ts
14
+ function createShallowStore(storeCreator) {
15
+ const storeApi = createStore(storeCreator);
16
+ const useScopedStore = (selector) => {
17
+ return useStore(storeApi, useShallow(selector));
18
+ };
19
+ return { useStore: useScopedStore, useStoreApi: storeApi };
20
+ }
15
21
  function normalizeScopeToArray(scope) {
16
22
  if (typeof scope === "string") {
17
23
  return [scope];
@@ -176,30 +182,14 @@ var devtoolsConfig = {
176
182
  };
177
183
 
178
184
  // src/store/uiBlockingStore.store.ts
179
- var useUIBlockingStore = create()(
180
- devtools(createUIBlockingActions, devtoolsConfig)
181
- );
182
-
183
- // src/hooks/useBlocker.ts
184
- var useBlocker = (blockerId, config, isActive = true) => {
185
- const { addBlocker, removeBlocker } = useUIBlockingStore();
186
- useEffect(() => {
187
- if (!isActive || !blockerId) {
188
- return;
189
- }
190
- addBlocker(blockerId, config);
191
- return () => {
192
- removeBlocker(blockerId);
193
- };
194
- }, [blockerId, isActive, addBlocker, removeBlocker]);
195
- };
185
+ var { useStore: useUIBlockingStore} = createShallowStore(devtools(createUIBlockingActions, devtoolsConfig));
196
186
 
197
- // src/hooks/useIsBlocked.ts
198
- var useIsBlocked = (scope) => {
199
- return useUIBlockingStore((state) => state.isBlocked(scope));
200
- };
187
+ // src/hooks/useAsyncAction/useAsyncAction.ts
201
188
  var useAsyncAction = (actionId, scope) => {
202
- const { addBlocker, removeBlocker } = useUIBlockingStore();
189
+ const { addBlocker, removeBlocker } = useUIBlockingStore((state) => ({
190
+ addBlocker: state.addBlocker,
191
+ removeBlocker: state.removeBlocker
192
+ }));
203
193
  const executeWithBlocking = useCallback(
204
194
  async (asyncFn) => {
205
195
  const blockerId = `${actionId}-${Date.now().toString()}`;
@@ -218,15 +208,23 @@ var useAsyncAction = (actionId, scope) => {
218
208
  );
219
209
  return executeWithBlocking;
220
210
  };
221
- function useConfigRef(config) {
222
- const configRef = useRef(config);
211
+ var useBlocker = (blockerId, config, isActive = true) => {
212
+ const { addBlocker, removeBlocker } = useUIBlockingStore((state) => ({
213
+ addBlocker: state.addBlocker,
214
+ removeBlocker: state.removeBlocker
215
+ }));
223
216
  useEffect(() => {
224
- configRef.current = config;
225
- }, [config]);
226
- return configRef;
227
- }
217
+ if (!isActive || !blockerId) {
218
+ return;
219
+ }
220
+ addBlocker(blockerId, config);
221
+ return () => {
222
+ removeBlocker(blockerId);
223
+ };
224
+ }, [blockerId, isActive, addBlocker, removeBlocker]);
225
+ };
228
226
 
229
- // src/hooks/useBlocker.utils.ts
227
+ // src/hooks/useBlocker/useBlocker.utils.ts
230
228
  function createBlockerConfig(config) {
231
229
  return {
232
230
  scope: config.scope,
@@ -234,10 +232,20 @@ function createBlockerConfig(config) {
234
232
  priority: config.priority
235
233
  };
236
234
  }
235
+ function useConfigRef(config) {
236
+ const configRef = useRef(config);
237
+ useEffect(() => {
238
+ configRef.current = config;
239
+ }, [config]);
240
+ return configRef;
241
+ }
237
242
 
238
- // src/hooks/useConditionalBlocker.ts
243
+ // src/hooks/useConditionalBlocker/useConditionalBlocker.ts
239
244
  var useConditionalBlocker = (blockerId, config) => {
240
- const { addBlocker, removeBlocker } = useUIBlockingStore();
245
+ const { addBlocker, removeBlocker } = useUIBlockingStore((state) => ({
246
+ addBlocker: state.addBlocker,
247
+ removeBlocker: state.removeBlocker
248
+ }));
241
249
  const intervalRef = useRef(null);
242
250
  const isBlockedRef = useRef(false);
243
251
  const configRef = useConfigRef(config);
@@ -249,11 +257,10 @@ var useConditionalBlocker = (blockerId, config) => {
249
257
  }
250
258
  if (shouldBlock) {
251
259
  addBlocker(blockerId, createBlockerConfig(currentConfig));
252
- isBlockedRef.current = true;
253
260
  } else {
254
261
  removeBlocker(blockerId);
255
- isBlockedRef.current = false;
256
262
  }
263
+ isBlockedRef.current = shouldBlock;
257
264
  }, [blockerId, addBlocker, removeBlocker, configRef]);
258
265
  useEffect(() => {
259
266
  checkCondition();
@@ -315,8 +322,55 @@ var useConfirmableBlocker = (blockerId, config) => {
315
322
  onCancel
316
323
  };
317
324
  };
325
+
326
+ // src/hooks/useIsBlocked/useIsBlocked.ts
327
+ var useIsBlocked = (scope) => {
328
+ return useUIBlockingStore((state) => state.isBlocked(scope));
329
+ };
330
+
331
+ // src/hooks/useScheduledBlocker/useScheduledBlocker.utils.ts
332
+ var MAX_TIMEOUT_MS = 2147483647;
333
+ function parseDate(date) {
334
+ return new Date(date).getTime();
335
+ }
336
+ function isValidTimestamp(timestamp) {
337
+ return !Number.isNaN(timestamp);
338
+ }
339
+ function calculateEndTime(schedule, startTime) {
340
+ if (schedule.duration) {
341
+ return startTime + schedule.duration;
342
+ }
343
+ if (schedule.end) {
344
+ const endTime = parseDate(schedule.end);
345
+ return isValidTimestamp(endTime) ? endTime : void 0;
346
+ }
347
+ return void 0;
348
+ }
349
+ function isSafeTimeout(delay) {
350
+ return delay > 0 && delay <= MAX_TIMEOUT_MS;
351
+ }
352
+ function isInBlockingPeriod(startTime, endTime, now) {
353
+ if (startTime > now) {
354
+ return false;
355
+ }
356
+ if (!endTime) {
357
+ return true;
358
+ }
359
+ return endTime > now;
360
+ }
361
+ function isScheduleInPast(startTime, endTime, now) {
362
+ if (!endTime) {
363
+ return false;
364
+ }
365
+ return endTime <= now && startTime <= now;
366
+ }
367
+
368
+ // src/hooks/useScheduledBlocker/useScheduledBlocker.ts
318
369
  var useScheduledBlocker = (blockerId, config) => {
319
- const { addBlocker, removeBlocker } = useUIBlockingStore();
370
+ const { addBlocker, removeBlocker } = useUIBlockingStore((state) => ({
371
+ addBlocker: state.addBlocker,
372
+ removeBlocker: state.removeBlocker
373
+ }));
320
374
  const timeoutsRef = useRef({});
321
375
  const configRef = useConfigRef(config);
322
376
  const cleanup = useCallback(() => {
@@ -331,41 +385,47 @@ var useScheduledBlocker = (blockerId, config) => {
331
385
  }, []);
332
386
  useEffect(() => {
333
387
  const currentConfig = configRef.current;
334
- const startTime = new Date(currentConfig.schedule.start).getTime();
388
+ const startTime = parseDate(currentConfig.schedule.start);
335
389
  const now = Date.now();
336
- let endTime;
337
- if (currentConfig.schedule.duration) {
338
- endTime = startTime + currentConfig.schedule.duration;
339
- } else if (currentConfig.schedule.end) {
340
- endTime = new Date(currentConfig.schedule.end).getTime();
390
+ if (!isValidTimestamp(startTime)) {
391
+ console.error(`[UIBlocking] Invalid start time for blocker "${blockerId}"`);
392
+ return;
341
393
  }
342
- const scheduleEnd = (end) => {
343
- const remainingTime = end - Date.now();
394
+ const scheduleEnd = () => {
395
+ const endTime = calculateEndTime(currentConfig.schedule, startTime);
396
+ if (!endTime) {
397
+ return;
398
+ }
399
+ const remainingTime = endTime - Date.now();
344
400
  if (remainingTime > 0) {
345
401
  timeoutsRef.current.end = setTimeout(() => {
346
- removeBlocker(blockerId);
347
402
  configRef.current.onScheduleEnd?.();
403
+ removeBlocker(blockerId);
348
404
  }, remainingTime);
349
405
  }
350
406
  };
407
+ const startBlocking = () => {
408
+ const cfg = configRef.current;
409
+ addBlocker(blockerId, createBlockerConfig(cfg));
410
+ cfg.onScheduleStart?.();
411
+ scheduleEnd();
412
+ };
351
413
  if (startTime > now) {
352
- timeoutsRef.current.start = setTimeout(() => {
353
- const cfg = configRef.current;
354
- addBlocker(blockerId, createBlockerConfig(cfg));
355
- cfg.onScheduleStart?.();
356
- if (endTime) {
357
- scheduleEnd(endTime);
358
- }
359
- }, startTime - now);
360
- } else if (endTime && endTime > now) {
361
- addBlocker(blockerId, createBlockerConfig(currentConfig));
362
- currentConfig.onScheduleStart?.();
363
- scheduleEnd(endTime);
364
- } else if (!endTime && startTime <= now) {
365
- addBlocker(blockerId, createBlockerConfig(currentConfig));
366
- currentConfig.onScheduleStart?.();
414
+ const delay = startTime - now;
415
+ if (!isSafeTimeout(delay)) {
416
+ console.warn(
417
+ `[UIBlocking] Schedule delay exceeds maximum timeout (${MAX_TIMEOUT_MS.toString()}ms) for blocker "${blockerId}"`
418
+ );
419
+ return;
420
+ }
421
+ timeoutsRef.current.start = setTimeout(startBlocking, delay);
367
422
  } else {
368
- console.warn(`[UIBlocking] Schedule is in the past for blocker "${blockerId}"`);
423
+ const endTime = calculateEndTime(currentConfig.schedule, startTime);
424
+ if (isInBlockingPeriod(startTime, endTime, now)) {
425
+ startBlocking();
426
+ } else if (isScheduleInPast(startTime, endTime, now)) {
427
+ console.warn(`[UIBlocking] Schedule is in the past for blocker "${blockerId}"`);
428
+ }
369
429
  }
370
430
  return () => {
371
431
  cleanup();
@@ -374,56 +434,6 @@ var useScheduledBlocker = (blockerId, config) => {
374
434
  }, [blockerId, addBlocker, removeBlocker, cleanup]);
375
435
  };
376
436
 
377
- // src/middleware/loggerMiddleware.utils.ts
378
- var getActionEmoji = (action) => {
379
- switch (action) {
380
- case "add":
381
- return "\u2795";
382
- case "remove":
383
- return "\u2796";
384
- case "update":
385
- return "\u{1F504}";
386
- case "cancel":
387
- return "\u274C";
388
- case "timeout":
389
- return "\u23F1\uFE0F";
390
- default:
391
- return "\u2753";
392
- }
393
- };
394
- var extractConfigDetails = (config) => {
395
- if (!config) {
396
- return {};
397
- }
398
- const { scope, reason, priority } = config;
399
- const details = {
400
- scope,
401
- reason
402
- };
403
- if (priority !== void 0) {
404
- details.priority = priority;
405
- }
406
- return details;
407
- };
408
- var formatLogData = (context) => {
409
- const configDetails = extractConfigDetails(context.config);
410
- if (context.prevState) {
411
- return {
412
- config: configDetails,
413
- prevState: extractConfigDetails(context.prevState)
414
- };
415
- }
416
- return configDetails;
417
- };
418
-
419
- // src/middleware/loggerMiddleware.ts
420
- var LOG_PREFIX = "[UIBlocking]";
421
- var loggerMiddleware = (context) => {
422
- const emoji = getActionEmoji(context.action);
423
- const logData = formatLogData(context);
424
- console.log(LOG_PREFIX, emoji, context.blockerId, logData);
425
- };
426
-
427
437
  // src/middleware/analyticsMiddleware.utils.ts
428
438
  var capitalizeFirst = (str) => {
429
439
  return str.charAt(0).toUpperCase() + str.slice(1);
@@ -494,6 +504,56 @@ var createAnalyticsMiddleware = (config) => {
494
504
  };
495
505
  };
496
506
 
507
+ // src/middleware/loggerMiddleware.utils.ts
508
+ var getActionEmoji = (action) => {
509
+ switch (action) {
510
+ case "add":
511
+ return "\u2795";
512
+ case "remove":
513
+ return "\u2796";
514
+ case "update":
515
+ return "\u{1F504}";
516
+ case "cancel":
517
+ return "\u274C";
518
+ case "timeout":
519
+ return "\u23F1\uFE0F";
520
+ default:
521
+ return "\u2753";
522
+ }
523
+ };
524
+ var extractConfigDetails = (config) => {
525
+ if (!config) {
526
+ return {};
527
+ }
528
+ const { scope, reason, priority } = config;
529
+ const details = {
530
+ scope,
531
+ reason
532
+ };
533
+ if (priority !== void 0) {
534
+ details.priority = priority;
535
+ }
536
+ return details;
537
+ };
538
+ var formatLogData = (context) => {
539
+ const configDetails = extractConfigDetails(context.config);
540
+ if (context.prevState) {
541
+ return {
542
+ config: configDetails,
543
+ prevState: extractConfigDetails(context.prevState)
544
+ };
545
+ }
546
+ return configDetails;
547
+ };
548
+
549
+ // src/middleware/loggerMiddleware.ts
550
+ var LOG_PREFIX = "[UIBlocking]";
551
+ var loggerMiddleware = (context) => {
552
+ const emoji = getActionEmoji(context.action);
553
+ const logData = formatLogData(context);
554
+ console.log(LOG_PREFIX, emoji, context.blockerId, logData);
555
+ };
556
+
497
557
  // src/middleware/performanceMiddleware.utils.ts
498
558
  var handleAddAction = (blockerId, timestamp, blockStartTimes) => {
499
559
  blockStartTimes.set(blockerId, timestamp);
@@ -511,7 +571,9 @@ var handleRemoveAction = (context, blockStartTimes, slowBlockThreshold, onSlowBl
511
571
  const duration = context.timestamp - startTime;
512
572
  blockStartTimes.delete(context.blockerId);
513
573
  if (duration >= slowBlockThreshold) {
514
- console.warn(`[UIBlocking] Slow block detected: "${context.blockerId}" took ${duration.toString()}ms`);
574
+ console.warn(
575
+ `[UIBlocking] Slow block detected: "${context.blockerId}" took ${duration.toString()}ms`
576
+ );
515
577
  onSlowBlock?.(context.blockerId, duration);
516
578
  }
517
579
  };