@okyrychenko-dev/react-action-guard 0.2.2 → 0.2.3
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 +15 -19
- package/dist/index.cjs +151 -105
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -38
- package/dist/index.d.ts +38 -38
- package/dist/index.js +152 -106
- package/dist/index.js.map +1 -1
- package/package.json +14 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import * as zustand from 'zustand';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Hook to wrap async functions with automatic blocking/unblocking
|
|
5
|
+
*
|
|
6
|
+
* Creates a wrapper function that automatically adds a blocker before executing
|
|
7
|
+
* the async function and removes it after completion (success or failure).
|
|
8
|
+
*
|
|
9
|
+
* @template T - The return type of the async function
|
|
10
|
+
* @param actionId - Unique identifier for the action (used in blocker ID and reason)
|
|
11
|
+
* @param scope - Scope(s) to block during execution (default: "global")
|
|
12
|
+
* @returns Function that wraps async functions with blocking behavior
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
15
|
+
declare const useAsyncAction: <T = unknown>(actionId: string, scope?: string | ReadonlyArray<string>) => ((asyncFn: () => Promise<T>) => Promise<T>);
|
|
15
16
|
|
|
16
17
|
type AnalyticsEventData = Record<string, string | number | ReadonlyArray<string> | undefined>;
|
|
17
18
|
type AnalyticsProvider = "ga" | "mixpanel" | "amplitude";
|
|
@@ -29,8 +30,21 @@ interface CustomAnalyticsConfig {
|
|
|
29
30
|
}
|
|
30
31
|
type AnalyticsConfig = GoogleAnalyticsConfig | MixpanelConfig | AmplitudeConfig | CustomAnalyticsConfig;
|
|
31
32
|
|
|
33
|
+
type BlockingAction = "add" | "remove" | "update" | "cancel" | "timeout";
|
|
34
|
+
type MiddlewareBlockerConfig = BlockerConfig;
|
|
35
|
+
interface MiddlewareContext {
|
|
36
|
+
action: BlockingAction;
|
|
37
|
+
blockerId: string;
|
|
38
|
+
config?: MiddlewareBlockerConfig;
|
|
39
|
+
timestamp: number;
|
|
40
|
+
prevState?: MiddlewareBlockerConfig;
|
|
41
|
+
}
|
|
42
|
+
type Middleware = (context: MiddlewareContext) => void | Promise<void>;
|
|
43
|
+
|
|
32
44
|
declare const createAnalyticsMiddleware: (config: AnalyticsConfig) => Middleware;
|
|
33
45
|
|
|
46
|
+
declare const loggerMiddleware: Middleware;
|
|
47
|
+
|
|
34
48
|
interface PerformanceConfig {
|
|
35
49
|
slowBlockThreshold?: number;
|
|
36
50
|
onSlowBlock?: (blockerId: string, duration: number) => void;
|
|
@@ -131,32 +145,6 @@ declare const useUIBlockingStore: zustand.UseBoundStore<Omit<zustand.StoreApi<UI
|
|
|
131
145
|
*/
|
|
132
146
|
declare const useBlocker: (blockerId: string, config: BlockerConfig, isActive?: boolean) => void;
|
|
133
147
|
|
|
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
148
|
/**
|
|
161
149
|
* Configuration for conditional blocker hook.
|
|
162
150
|
*
|
|
@@ -233,6 +221,18 @@ interface UseConfirmableBlockerReturn {
|
|
|
233
221
|
*/
|
|
234
222
|
declare const useConfirmableBlocker: (blockerId: string, config: ConfirmableBlockerConfig) => UseConfirmableBlockerReturn;
|
|
235
223
|
|
|
224
|
+
/**
|
|
225
|
+
* Hook to check if a scope is currently blocked
|
|
226
|
+
*
|
|
227
|
+
* Returns a boolean indicating whether the specified scope(s) are blocked.
|
|
228
|
+
* Automatically re-renders when the blocking state changes.
|
|
229
|
+
*
|
|
230
|
+
* @param scope - Scope or array of scopes to check (default: "global")
|
|
231
|
+
* @returns True if any of the specified scopes are blocked
|
|
232
|
+
*
|
|
233
|
+
*/
|
|
234
|
+
declare const useIsBlocked: (scope?: string | ReadonlyArray<string>) => boolean;
|
|
235
|
+
|
|
236
236
|
/**
|
|
237
237
|
* Schedule configuration for time-based blocking.
|
|
238
238
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import * as zustand from 'zustand';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Hook to wrap async functions with automatic blocking/unblocking
|
|
5
|
+
*
|
|
6
|
+
* Creates a wrapper function that automatically adds a blocker before executing
|
|
7
|
+
* the async function and removes it after completion (success or failure).
|
|
8
|
+
*
|
|
9
|
+
* @template T - The return type of the async function
|
|
10
|
+
* @param actionId - Unique identifier for the action (used in blocker ID and reason)
|
|
11
|
+
* @param scope - Scope(s) to block during execution (default: "global")
|
|
12
|
+
* @returns Function that wraps async functions with blocking behavior
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
15
|
+
declare const useAsyncAction: <T = unknown>(actionId: string, scope?: string | ReadonlyArray<string>) => ((asyncFn: () => Promise<T>) => Promise<T>);
|
|
15
16
|
|
|
16
17
|
type AnalyticsEventData = Record<string, string | number | ReadonlyArray<string> | undefined>;
|
|
17
18
|
type AnalyticsProvider = "ga" | "mixpanel" | "amplitude";
|
|
@@ -29,8 +30,21 @@ interface CustomAnalyticsConfig {
|
|
|
29
30
|
}
|
|
30
31
|
type AnalyticsConfig = GoogleAnalyticsConfig | MixpanelConfig | AmplitudeConfig | CustomAnalyticsConfig;
|
|
31
32
|
|
|
33
|
+
type BlockingAction = "add" | "remove" | "update" | "cancel" | "timeout";
|
|
34
|
+
type MiddlewareBlockerConfig = BlockerConfig;
|
|
35
|
+
interface MiddlewareContext {
|
|
36
|
+
action: BlockingAction;
|
|
37
|
+
blockerId: string;
|
|
38
|
+
config?: MiddlewareBlockerConfig;
|
|
39
|
+
timestamp: number;
|
|
40
|
+
prevState?: MiddlewareBlockerConfig;
|
|
41
|
+
}
|
|
42
|
+
type Middleware = (context: MiddlewareContext) => void | Promise<void>;
|
|
43
|
+
|
|
32
44
|
declare const createAnalyticsMiddleware: (config: AnalyticsConfig) => Middleware;
|
|
33
45
|
|
|
46
|
+
declare const loggerMiddleware: Middleware;
|
|
47
|
+
|
|
34
48
|
interface PerformanceConfig {
|
|
35
49
|
slowBlockThreshold?: number;
|
|
36
50
|
onSlowBlock?: (blockerId: string, duration: number) => void;
|
|
@@ -131,32 +145,6 @@ declare const useUIBlockingStore: zustand.UseBoundStore<Omit<zustand.StoreApi<UI
|
|
|
131
145
|
*/
|
|
132
146
|
declare const useBlocker: (blockerId: string, config: BlockerConfig, isActive?: boolean) => void;
|
|
133
147
|
|
|
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
148
|
/**
|
|
161
149
|
* Configuration for conditional blocker hook.
|
|
162
150
|
*
|
|
@@ -233,6 +221,18 @@ interface UseConfirmableBlockerReturn {
|
|
|
233
221
|
*/
|
|
234
222
|
declare const useConfirmableBlocker: (blockerId: string, config: ConfirmableBlockerConfig) => UseConfirmableBlockerReturn;
|
|
235
223
|
|
|
224
|
+
/**
|
|
225
|
+
* Hook to check if a scope is currently blocked
|
|
226
|
+
*
|
|
227
|
+
* Returns a boolean indicating whether the specified scope(s) are blocked.
|
|
228
|
+
* Automatically re-renders when the blocking state changes.
|
|
229
|
+
*
|
|
230
|
+
* @param scope - Scope or array of scopes to check (default: "global")
|
|
231
|
+
* @returns True if any of the specified scopes are blocked
|
|
232
|
+
*
|
|
233
|
+
*/
|
|
234
|
+
declare const useIsBlocked: (scope?: string | ReadonlyArray<string>) => boolean;
|
|
235
|
+
|
|
236
236
|
/**
|
|
237
237
|
* Schedule configuration for time-based blocking.
|
|
238
238
|
*
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
2
|
import { create } from 'zustand';
|
|
3
3
|
import { devtools } from 'zustand/middleware';
|
|
4
4
|
|
|
5
|
-
// src/hooks/
|
|
5
|
+
// src/hooks/useAsyncAction/useAsyncAction.ts
|
|
6
6
|
|
|
7
7
|
// src/store/uiBlockingStore.constants.ts
|
|
8
8
|
var DEFAULT_SCOPE = "global";
|
|
@@ -180,24 +180,7 @@ var useUIBlockingStore = create()(
|
|
|
180
180
|
devtools(createUIBlockingActions, devtoolsConfig)
|
|
181
181
|
);
|
|
182
182
|
|
|
183
|
-
// src/hooks/
|
|
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
|
-
};
|
|
196
|
-
|
|
197
|
-
// src/hooks/useIsBlocked.ts
|
|
198
|
-
var useIsBlocked = (scope) => {
|
|
199
|
-
return useUIBlockingStore((state) => state.isBlocked(scope));
|
|
200
|
-
};
|
|
183
|
+
// src/hooks/useAsyncAction/useAsyncAction.ts
|
|
201
184
|
var useAsyncAction = (actionId, scope) => {
|
|
202
185
|
const { addBlocker, removeBlocker } = useUIBlockingStore();
|
|
203
186
|
const executeWithBlocking = useCallback(
|
|
@@ -218,15 +201,20 @@ var useAsyncAction = (actionId, scope) => {
|
|
|
218
201
|
);
|
|
219
202
|
return executeWithBlocking;
|
|
220
203
|
};
|
|
221
|
-
|
|
222
|
-
const
|
|
204
|
+
var useBlocker = (blockerId, config, isActive = true) => {
|
|
205
|
+
const { addBlocker, removeBlocker } = useUIBlockingStore();
|
|
223
206
|
useEffect(() => {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
207
|
+
if (!isActive || !blockerId) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
addBlocker(blockerId, config);
|
|
211
|
+
return () => {
|
|
212
|
+
removeBlocker(blockerId);
|
|
213
|
+
};
|
|
214
|
+
}, [blockerId, isActive, addBlocker, removeBlocker]);
|
|
215
|
+
};
|
|
228
216
|
|
|
229
|
-
// src/hooks/useBlocker.utils.ts
|
|
217
|
+
// src/hooks/useBlocker/useBlocker.utils.ts
|
|
230
218
|
function createBlockerConfig(config) {
|
|
231
219
|
return {
|
|
232
220
|
scope: config.scope,
|
|
@@ -234,8 +222,15 @@ function createBlockerConfig(config) {
|
|
|
234
222
|
priority: config.priority
|
|
235
223
|
};
|
|
236
224
|
}
|
|
225
|
+
function useConfigRef(config) {
|
|
226
|
+
const configRef = useRef(config);
|
|
227
|
+
useEffect(() => {
|
|
228
|
+
configRef.current = config;
|
|
229
|
+
}, [config]);
|
|
230
|
+
return configRef;
|
|
231
|
+
}
|
|
237
232
|
|
|
238
|
-
// src/hooks/useConditionalBlocker.ts
|
|
233
|
+
// src/hooks/useConditionalBlocker/useConditionalBlocker.ts
|
|
239
234
|
var useConditionalBlocker = (blockerId, config) => {
|
|
240
235
|
const { addBlocker, removeBlocker } = useUIBlockingStore();
|
|
241
236
|
const intervalRef = useRef(null);
|
|
@@ -249,11 +244,10 @@ var useConditionalBlocker = (blockerId, config) => {
|
|
|
249
244
|
}
|
|
250
245
|
if (shouldBlock) {
|
|
251
246
|
addBlocker(blockerId, createBlockerConfig(currentConfig));
|
|
252
|
-
isBlockedRef.current = true;
|
|
253
247
|
} else {
|
|
254
248
|
removeBlocker(blockerId);
|
|
255
|
-
isBlockedRef.current = false;
|
|
256
249
|
}
|
|
250
|
+
isBlockedRef.current = shouldBlock;
|
|
257
251
|
}, [blockerId, addBlocker, removeBlocker, configRef]);
|
|
258
252
|
useEffect(() => {
|
|
259
253
|
checkCondition();
|
|
@@ -315,6 +309,50 @@ var useConfirmableBlocker = (blockerId, config) => {
|
|
|
315
309
|
onCancel
|
|
316
310
|
};
|
|
317
311
|
};
|
|
312
|
+
|
|
313
|
+
// src/hooks/useIsBlocked/useIsBlocked.ts
|
|
314
|
+
var useIsBlocked = (scope) => {
|
|
315
|
+
return useUIBlockingStore((state) => state.isBlocked(scope));
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
// src/hooks/useScheduledBlocker/useScheduledBlocker.utils.ts
|
|
319
|
+
var MAX_TIMEOUT_MS = 2147483647;
|
|
320
|
+
function parseDate(date) {
|
|
321
|
+
return new Date(date).getTime();
|
|
322
|
+
}
|
|
323
|
+
function isValidTimestamp(timestamp) {
|
|
324
|
+
return !Number.isNaN(timestamp);
|
|
325
|
+
}
|
|
326
|
+
function calculateEndTime(schedule, startTime) {
|
|
327
|
+
if (schedule.duration) {
|
|
328
|
+
return startTime + schedule.duration;
|
|
329
|
+
}
|
|
330
|
+
if (schedule.end) {
|
|
331
|
+
const endTime = parseDate(schedule.end);
|
|
332
|
+
return isValidTimestamp(endTime) ? endTime : void 0;
|
|
333
|
+
}
|
|
334
|
+
return void 0;
|
|
335
|
+
}
|
|
336
|
+
function isSafeTimeout(delay) {
|
|
337
|
+
return delay > 0 && delay <= MAX_TIMEOUT_MS;
|
|
338
|
+
}
|
|
339
|
+
function isInBlockingPeriod(startTime, endTime, now) {
|
|
340
|
+
if (startTime > now) {
|
|
341
|
+
return false;
|
|
342
|
+
}
|
|
343
|
+
if (!endTime) {
|
|
344
|
+
return true;
|
|
345
|
+
}
|
|
346
|
+
return endTime > now;
|
|
347
|
+
}
|
|
348
|
+
function isScheduleInPast(startTime, endTime, now) {
|
|
349
|
+
if (!endTime) {
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
return endTime <= now && startTime <= now;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// src/hooks/useScheduledBlocker/useScheduledBlocker.ts
|
|
318
356
|
var useScheduledBlocker = (blockerId, config) => {
|
|
319
357
|
const { addBlocker, removeBlocker } = useUIBlockingStore();
|
|
320
358
|
const timeoutsRef = useRef({});
|
|
@@ -331,41 +369,47 @@ var useScheduledBlocker = (blockerId, config) => {
|
|
|
331
369
|
}, []);
|
|
332
370
|
useEffect(() => {
|
|
333
371
|
const currentConfig = configRef.current;
|
|
334
|
-
const startTime =
|
|
372
|
+
const startTime = parseDate(currentConfig.schedule.start);
|
|
335
373
|
const now = Date.now();
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
} else if (currentConfig.schedule.end) {
|
|
340
|
-
endTime = new Date(currentConfig.schedule.end).getTime();
|
|
374
|
+
if (!isValidTimestamp(startTime)) {
|
|
375
|
+
console.error(`[UIBlocking] Invalid start time for blocker "${blockerId}"`);
|
|
376
|
+
return;
|
|
341
377
|
}
|
|
342
|
-
const scheduleEnd = (
|
|
343
|
-
const
|
|
378
|
+
const scheduleEnd = () => {
|
|
379
|
+
const endTime = calculateEndTime(currentConfig.schedule, startTime);
|
|
380
|
+
if (!endTime) {
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
const remainingTime = endTime - Date.now();
|
|
344
384
|
if (remainingTime > 0) {
|
|
345
385
|
timeoutsRef.current.end = setTimeout(() => {
|
|
346
|
-
removeBlocker(blockerId);
|
|
347
386
|
configRef.current.onScheduleEnd?.();
|
|
387
|
+
removeBlocker(blockerId);
|
|
348
388
|
}, remainingTime);
|
|
349
389
|
}
|
|
350
390
|
};
|
|
391
|
+
const startBlocking = () => {
|
|
392
|
+
const cfg = configRef.current;
|
|
393
|
+
addBlocker(blockerId, createBlockerConfig(cfg));
|
|
394
|
+
cfg.onScheduleStart?.();
|
|
395
|
+
scheduleEnd();
|
|
396
|
+
};
|
|
351
397
|
if (startTime > now) {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
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?.();
|
|
398
|
+
const delay = startTime - now;
|
|
399
|
+
if (!isSafeTimeout(delay)) {
|
|
400
|
+
console.warn(
|
|
401
|
+
`[UIBlocking] Schedule delay exceeds maximum timeout (${MAX_TIMEOUT_MS.toString()}ms) for blocker "${blockerId}"`
|
|
402
|
+
);
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
timeoutsRef.current.start = setTimeout(startBlocking, delay);
|
|
367
406
|
} else {
|
|
368
|
-
|
|
407
|
+
const endTime = calculateEndTime(currentConfig.schedule, startTime);
|
|
408
|
+
if (isInBlockingPeriod(startTime, endTime, now)) {
|
|
409
|
+
startBlocking();
|
|
410
|
+
} else if (isScheduleInPast(startTime, endTime, now)) {
|
|
411
|
+
console.warn(`[UIBlocking] Schedule is in the past for blocker "${blockerId}"`);
|
|
412
|
+
}
|
|
369
413
|
}
|
|
370
414
|
return () => {
|
|
371
415
|
cleanup();
|
|
@@ -374,56 +418,6 @@ var useScheduledBlocker = (blockerId, config) => {
|
|
|
374
418
|
}, [blockerId, addBlocker, removeBlocker, cleanup]);
|
|
375
419
|
};
|
|
376
420
|
|
|
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
421
|
// src/middleware/analyticsMiddleware.utils.ts
|
|
428
422
|
var capitalizeFirst = (str) => {
|
|
429
423
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
@@ -494,6 +488,56 @@ var createAnalyticsMiddleware = (config) => {
|
|
|
494
488
|
};
|
|
495
489
|
};
|
|
496
490
|
|
|
491
|
+
// src/middleware/loggerMiddleware.utils.ts
|
|
492
|
+
var getActionEmoji = (action) => {
|
|
493
|
+
switch (action) {
|
|
494
|
+
case "add":
|
|
495
|
+
return "\u2795";
|
|
496
|
+
case "remove":
|
|
497
|
+
return "\u2796";
|
|
498
|
+
case "update":
|
|
499
|
+
return "\u{1F504}";
|
|
500
|
+
case "cancel":
|
|
501
|
+
return "\u274C";
|
|
502
|
+
case "timeout":
|
|
503
|
+
return "\u23F1\uFE0F";
|
|
504
|
+
default:
|
|
505
|
+
return "\u2753";
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
var extractConfigDetails = (config) => {
|
|
509
|
+
if (!config) {
|
|
510
|
+
return {};
|
|
511
|
+
}
|
|
512
|
+
const { scope, reason, priority } = config;
|
|
513
|
+
const details = {
|
|
514
|
+
scope,
|
|
515
|
+
reason
|
|
516
|
+
};
|
|
517
|
+
if (priority !== void 0) {
|
|
518
|
+
details.priority = priority;
|
|
519
|
+
}
|
|
520
|
+
return details;
|
|
521
|
+
};
|
|
522
|
+
var formatLogData = (context) => {
|
|
523
|
+
const configDetails = extractConfigDetails(context.config);
|
|
524
|
+
if (context.prevState) {
|
|
525
|
+
return {
|
|
526
|
+
config: configDetails,
|
|
527
|
+
prevState: extractConfigDetails(context.prevState)
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
return configDetails;
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
// src/middleware/loggerMiddleware.ts
|
|
534
|
+
var LOG_PREFIX = "[UIBlocking]";
|
|
535
|
+
var loggerMiddleware = (context) => {
|
|
536
|
+
const emoji = getActionEmoji(context.action);
|
|
537
|
+
const logData = formatLogData(context);
|
|
538
|
+
console.log(LOG_PREFIX, emoji, context.blockerId, logData);
|
|
539
|
+
};
|
|
540
|
+
|
|
497
541
|
// src/middleware/performanceMiddleware.utils.ts
|
|
498
542
|
var handleAddAction = (blockerId, timestamp, blockStartTimes) => {
|
|
499
543
|
blockStartTimes.set(blockerId, timestamp);
|
|
@@ -511,7 +555,9 @@ var handleRemoveAction = (context, blockStartTimes, slowBlockThreshold, onSlowBl
|
|
|
511
555
|
const duration = context.timestamp - startTime;
|
|
512
556
|
blockStartTimes.delete(context.blockerId);
|
|
513
557
|
if (duration >= slowBlockThreshold) {
|
|
514
|
-
console.warn(
|
|
558
|
+
console.warn(
|
|
559
|
+
`[UIBlocking] Slow block detected: "${context.blockerId}" took ${duration.toString()}ms`
|
|
560
|
+
);
|
|
515
561
|
onSlowBlock?.(context.blockerId, duration);
|
|
516
562
|
}
|
|
517
563
|
};
|