@djangocfg/ui-nextjs 2.1.90 → 2.1.91
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 +6 -15
- package/package.json +6 -25
- package/src/blocks/SplitHero/SplitHeroMedia.tsx +1 -1
- package/src/components/index.ts +0 -40
- package/src/hooks/index.ts +0 -6
- package/src/index.ts +2 -11
- package/src/components/button-download.tsx +0 -277
- package/src/components/markdown/MarkdownMessage.tsx +0 -340
- package/src/components/markdown/index.ts +0 -5
- package/src/components/menubar.tsx +0 -275
- package/src/components/multi-select-pro/async.tsx +0 -598
- package/src/components/multi-select-pro/helpers.tsx +0 -84
- package/src/components/multi-select-pro/index.tsx +0 -612
- package/src/components/navigation-menu.tsx +0 -154
- package/src/components/otp/index.tsx +0 -197
- package/src/components/otp/types.ts +0 -133
- package/src/components/otp/use-otp-input.ts +0 -225
- package/src/components/phone-input.tsx +0 -277
- package/src/components/sonner.tsx +0 -32
- package/src/hooks/useLocalStorage.ts +0 -300
- package/src/hooks/useSessionStorage.ts +0 -290
- package/src/lib/index.ts +0 -5
- package/src/lib/logger/index.ts +0 -10
- package/src/lib/logger/logStore.ts +0 -122
- package/src/lib/logger/logger.ts +0 -175
- package/src/lib/logger/types.ts +0 -82
- package/src/stores/index.ts +0 -8
- package/src/stores/mediaCache.ts +0 -534
- package/src/tools/AudioPlayer/README.md +0 -206
- package/src/tools/AudioPlayer/components/HybridAudioPlayer.tsx +0 -216
- package/src/tools/AudioPlayer/components/HybridSimplePlayer.tsx +0 -280
- package/src/tools/AudioPlayer/components/HybridWaveform.tsx +0 -279
- package/src/tools/AudioPlayer/components/ReactiveCover/AudioReactiveCover.tsx +0 -149
- package/src/tools/AudioPlayer/components/ReactiveCover/effects/GlowEffect.tsx +0 -110
- package/src/tools/AudioPlayer/components/ReactiveCover/effects/MeshEffect.tsx +0 -58
- package/src/tools/AudioPlayer/components/ReactiveCover/effects/OrbsEffect.tsx +0 -45
- package/src/tools/AudioPlayer/components/ReactiveCover/effects/SpotlightEffect.tsx +0 -82
- package/src/tools/AudioPlayer/components/ReactiveCover/effects/index.ts +0 -8
- package/src/tools/AudioPlayer/components/ReactiveCover/index.ts +0 -6
- package/src/tools/AudioPlayer/components/index.ts +0 -22
- package/src/tools/AudioPlayer/context/HybridAudioProvider.tsx +0 -158
- package/src/tools/AudioPlayer/context/index.ts +0 -16
- package/src/tools/AudioPlayer/effects/index.ts +0 -412
- package/src/tools/AudioPlayer/hooks/index.ts +0 -35
- package/src/tools/AudioPlayer/hooks/useHybridAudio.ts +0 -387
- package/src/tools/AudioPlayer/hooks/useHybridAudioAnalysis.ts +0 -95
- package/src/tools/AudioPlayer/hooks/useVisualization.tsx +0 -207
- package/src/tools/AudioPlayer/index.ts +0 -133
- package/src/tools/AudioPlayer/types/effects.ts +0 -73
- package/src/tools/AudioPlayer/types/index.ts +0 -27
- package/src/tools/AudioPlayer/utils/debug.ts +0 -14
- package/src/tools/AudioPlayer/utils/formatTime.ts +0 -10
- package/src/tools/AudioPlayer/utils/index.ts +0 -6
- package/src/tools/ImageViewer/@refactoring/00-PLAN.md +0 -71
- package/src/tools/ImageViewer/@refactoring/01-TYPES.md +0 -121
- package/src/tools/ImageViewer/@refactoring/02-UTILS.md +0 -143
- package/src/tools/ImageViewer/@refactoring/03-HOOKS.md +0 -261
- package/src/tools/ImageViewer/@refactoring/04-COMPONENTS.md +0 -427
- package/src/tools/ImageViewer/@refactoring/05-EXECUTION-CHECKLIST.md +0 -126
- package/src/tools/ImageViewer/README.md +0 -200
- package/src/tools/ImageViewer/components/ImageInfo.tsx +0 -44
- package/src/tools/ImageViewer/components/ImageToolbar.tsx +0 -150
- package/src/tools/ImageViewer/components/ImageViewer.tsx +0 -241
- package/src/tools/ImageViewer/components/index.ts +0 -7
- package/src/tools/ImageViewer/hooks/index.ts +0 -9
- package/src/tools/ImageViewer/hooks/useImageLoading.ts +0 -204
- package/src/tools/ImageViewer/hooks/useImageTransform.ts +0 -101
- package/src/tools/ImageViewer/index.ts +0 -60
- package/src/tools/ImageViewer/types.ts +0 -81
- package/src/tools/ImageViewer/utils/constants.ts +0 -59
- package/src/tools/ImageViewer/utils/debug.ts +0 -14
- package/src/tools/ImageViewer/utils/index.ts +0 -17
- package/src/tools/ImageViewer/utils/lqip.ts +0 -47
- package/src/tools/JsonForm/JsonSchemaForm.tsx +0 -197
- package/src/tools/JsonForm/examples/BotConfigExample.tsx +0 -249
- package/src/tools/JsonForm/examples/RealBotConfigExample.tsx +0 -161
- package/src/tools/JsonForm/index.ts +0 -46
- package/src/tools/JsonForm/templates/ArrayFieldItemTemplate.tsx +0 -47
- package/src/tools/JsonForm/templates/ArrayFieldTemplate.tsx +0 -74
- package/src/tools/JsonForm/templates/BaseInputTemplate.tsx +0 -107
- package/src/tools/JsonForm/templates/ErrorListTemplate.tsx +0 -35
- package/src/tools/JsonForm/templates/FieldTemplate.tsx +0 -62
- package/src/tools/JsonForm/templates/ObjectFieldTemplate.tsx +0 -116
- package/src/tools/JsonForm/templates/index.ts +0 -12
- package/src/tools/JsonForm/types.ts +0 -83
- package/src/tools/JsonForm/utils.ts +0 -213
- package/src/tools/JsonForm/widgets/CheckboxWidget.tsx +0 -37
- package/src/tools/JsonForm/widgets/ColorWidget.tsx +0 -219
- package/src/tools/JsonForm/widgets/NumberWidget.tsx +0 -89
- package/src/tools/JsonForm/widgets/SelectWidget.tsx +0 -97
- package/src/tools/JsonForm/widgets/SliderWidget.tsx +0 -148
- package/src/tools/JsonForm/widgets/SwitchWidget.tsx +0 -35
- package/src/tools/JsonForm/widgets/TextWidget.tsx +0 -96
- package/src/tools/JsonForm/widgets/index.ts +0 -14
- package/src/tools/JsonTree/index.tsx +0 -243
- package/src/tools/LottiePlayer/LottiePlayer.client.tsx +0 -213
- package/src/tools/LottiePlayer/index.tsx +0 -55
- package/src/tools/LottiePlayer/types.ts +0 -108
- package/src/tools/LottiePlayer/useLottie.ts +0 -164
- package/src/tools/Mermaid/Mermaid.client.tsx +0 -82
- package/src/tools/Mermaid/components/MermaidCodeViewer.tsx +0 -95
- package/src/tools/Mermaid/components/MermaidFullscreenModal.tsx +0 -103
- package/src/tools/Mermaid/hooks/index.ts +0 -4
- package/src/tools/Mermaid/hooks/useMermaidCleanup.ts +0 -73
- package/src/tools/Mermaid/hooks/useMermaidFullscreen.ts +0 -46
- package/src/tools/Mermaid/hooks/useMermaidRenderer.ts +0 -226
- package/src/tools/Mermaid/hooks/useMermaidValidation.ts +0 -29
- package/src/tools/Mermaid/index.tsx +0 -41
- package/src/tools/Mermaid/utils/mermaid-helpers.ts +0 -33
- package/src/tools/OpenapiViewer/components/EndpointInfo.tsx +0 -149
- package/src/tools/OpenapiViewer/components/EndpointsLibrary.tsx +0 -263
- package/src/tools/OpenapiViewer/components/PlaygroundLayout.tsx +0 -125
- package/src/tools/OpenapiViewer/components/PlaygroundStepper.tsx +0 -100
- package/src/tools/OpenapiViewer/components/RequestBuilder.tsx +0 -157
- package/src/tools/OpenapiViewer/components/RequestParametersForm.tsx +0 -253
- package/src/tools/OpenapiViewer/components/ResponseViewer.tsx +0 -173
- package/src/tools/OpenapiViewer/components/VersionSelector.tsx +0 -68
- package/src/tools/OpenapiViewer/components/index.ts +0 -14
- package/src/tools/OpenapiViewer/constants.ts +0 -39
- package/src/tools/OpenapiViewer/context/PlaygroundContext.tsx +0 -337
- package/src/tools/OpenapiViewer/hooks/index.ts +0 -8
- package/src/tools/OpenapiViewer/hooks/useMobile.ts +0 -10
- package/src/tools/OpenapiViewer/hooks/useOpenApiSchema.ts +0 -199
- package/src/tools/OpenapiViewer/index.tsx +0 -38
- package/src/tools/OpenapiViewer/types.ts +0 -151
- package/src/tools/OpenapiViewer/utils/apiKeyManager.ts +0 -149
- package/src/tools/OpenapiViewer/utils/formatters.ts +0 -71
- package/src/tools/OpenapiViewer/utils/index.ts +0 -9
- package/src/tools/OpenapiViewer/utils/versionManager.ts +0 -161
- package/src/tools/PrettyCode/PrettyCode.client.tsx +0 -208
- package/src/tools/PrettyCode/index.tsx +0 -45
- package/src/tools/VideoPlayer/@refactoring/00-PLAN.md +0 -91
- package/src/tools/VideoPlayer/@refactoring/01-TYPES.md +0 -284
- package/src/tools/VideoPlayer/@refactoring/02-UTILS.md +0 -141
- package/src/tools/VideoPlayer/@refactoring/03-HOOKS.md +0 -178
- package/src/tools/VideoPlayer/@refactoring/04-COMPONENTS.md +0 -95
- package/src/tools/VideoPlayer/@refactoring/05-EXECUTION-CHECKLIST.md +0 -139
- package/src/tools/VideoPlayer/README.md +0 -264
- package/src/tools/VideoPlayer/components/VideoControls.tsx +0 -138
- package/src/tools/VideoPlayer/components/VideoErrorFallback.tsx +0 -174
- package/src/tools/VideoPlayer/components/VideoPlayer.tsx +0 -201
- package/src/tools/VideoPlayer/components/index.ts +0 -14
- package/src/tools/VideoPlayer/context/VideoPlayerContext.tsx +0 -52
- package/src/tools/VideoPlayer/context/index.ts +0 -8
- package/src/tools/VideoPlayer/hooks/index.ts +0 -12
- package/src/tools/VideoPlayer/hooks/useVideoPlayerSettings.ts +0 -70
- package/src/tools/VideoPlayer/hooks/useVideoPositionCache.ts +0 -116
- package/src/tools/VideoPlayer/index.ts +0 -77
- package/src/tools/VideoPlayer/providers/NativeProvider.tsx +0 -284
- package/src/tools/VideoPlayer/providers/StreamProvider.tsx +0 -505
- package/src/tools/VideoPlayer/providers/VidstackProvider.tsx +0 -400
- package/src/tools/VideoPlayer/providers/index.ts +0 -8
- package/src/tools/VideoPlayer/types/index.ts +0 -38
- package/src/tools/VideoPlayer/types/player.ts +0 -116
- package/src/tools/VideoPlayer/types/provider.ts +0 -93
- package/src/tools/VideoPlayer/types/sources.ts +0 -97
- package/src/tools/VideoPlayer/utils/debug.ts +0 -14
- package/src/tools/VideoPlayer/utils/fileSource.ts +0 -78
- package/src/tools/VideoPlayer/utils/index.ts +0 -12
- package/src/tools/VideoPlayer/utils/resolvers.ts +0 -75
- package/src/tools/index.ts +0 -170
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useState } from 'react';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Storage wrapper format with metadata
|
|
7
|
-
* Used when TTL is specified
|
|
8
|
-
*/
|
|
9
|
-
interface StorageWrapper<T> {
|
|
10
|
-
_meta: {
|
|
11
|
-
createdAt: number;
|
|
12
|
-
ttl: number;
|
|
13
|
-
};
|
|
14
|
-
_value: T;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Options for useSessionStorage hook
|
|
19
|
-
*/
|
|
20
|
-
export interface UseSessionStorageOptions {
|
|
21
|
-
/**
|
|
22
|
-
* Time-to-live in milliseconds.
|
|
23
|
-
* After this time, value is considered expired and initialValue is returned.
|
|
24
|
-
* Data is automatically cleaned up on next read.
|
|
25
|
-
* @example 24 * 60 * 60 * 1000 // 24 hours
|
|
26
|
-
*/
|
|
27
|
-
ttl?: number;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Check if data is in new wrapped format with _meta
|
|
32
|
-
*/
|
|
33
|
-
function isWrappedFormat<T>(data: unknown): data is StorageWrapper<T> {
|
|
34
|
-
return (
|
|
35
|
-
data !== null &&
|
|
36
|
-
typeof data === 'object' &&
|
|
37
|
-
'_meta' in data &&
|
|
38
|
-
'_value' in data &&
|
|
39
|
-
typeof (data as StorageWrapper<T>)._meta === 'object' &&
|
|
40
|
-
typeof (data as StorageWrapper<T>)._meta.createdAt === 'number'
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Check if wrapped data is expired
|
|
46
|
-
*/
|
|
47
|
-
function isExpired<T>(wrapped: StorageWrapper<T>): boolean {
|
|
48
|
-
if (!wrapped._meta.ttl) return false;
|
|
49
|
-
const age = Date.now() - wrapped._meta.createdAt;
|
|
50
|
-
return age > wrapped._meta.ttl;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Simple sessionStorage hook with better error handling and optional TTL support
|
|
55
|
-
*
|
|
56
|
-
* @param key - Storage key
|
|
57
|
-
* @param initialValue - Default value if key doesn't exist
|
|
58
|
-
* @param options - Optional configuration (ttl for auto-expiration)
|
|
59
|
-
* @returns [value, setValue, removeValue] - Current value, setter function, and remove function
|
|
60
|
-
*
|
|
61
|
-
* @example
|
|
62
|
-
* // Without TTL (backwards compatible)
|
|
63
|
-
* const [value, setValue] = useSessionStorage('key', 'default');
|
|
64
|
-
*
|
|
65
|
-
* @example
|
|
66
|
-
* // With TTL (1 hour)
|
|
67
|
-
* const [value, setValue] = useSessionStorage('key', 'default', {
|
|
68
|
-
* ttl: 60 * 60 * 1000
|
|
69
|
-
* });
|
|
70
|
-
*/
|
|
71
|
-
export function useSessionStorage<T>(
|
|
72
|
-
key: string,
|
|
73
|
-
initialValue: T,
|
|
74
|
-
options?: UseSessionStorageOptions
|
|
75
|
-
) {
|
|
76
|
-
const ttl = options?.ttl;
|
|
77
|
-
|
|
78
|
-
// Get initial value from sessionStorage or use provided initialValue
|
|
79
|
-
const [storedValue, setStoredValue] = useState<T>(() => {
|
|
80
|
-
if (typeof window === 'undefined') {
|
|
81
|
-
return initialValue;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
try {
|
|
85
|
-
const item = window.sessionStorage.getItem(key);
|
|
86
|
-
if (item === null) return initialValue;
|
|
87
|
-
|
|
88
|
-
try {
|
|
89
|
-
const parsed = JSON.parse(item);
|
|
90
|
-
|
|
91
|
-
// Check if new format with _meta
|
|
92
|
-
if (isWrappedFormat<T>(parsed)) {
|
|
93
|
-
// Check TTL expiration
|
|
94
|
-
if (isExpired(parsed)) {
|
|
95
|
-
// Expired! Clean up and use initial value
|
|
96
|
-
window.sessionStorage.removeItem(key);
|
|
97
|
-
return initialValue;
|
|
98
|
-
}
|
|
99
|
-
// Not expired, extract value
|
|
100
|
-
return parsed._value;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Old format (backwards compatible)
|
|
104
|
-
return parsed as T;
|
|
105
|
-
} catch {
|
|
106
|
-
// If JSON.parse fails, return as string
|
|
107
|
-
return item as T;
|
|
108
|
-
}
|
|
109
|
-
} catch (error) {
|
|
110
|
-
console.error(`Error reading sessionStorage key "${key}":`, error);
|
|
111
|
-
return initialValue;
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
// Check data size and limit
|
|
116
|
-
const checkDataSize = (data: any): boolean => {
|
|
117
|
-
try {
|
|
118
|
-
const jsonString = JSON.stringify(data);
|
|
119
|
-
const sizeInBytes = new Blob([jsonString]).size;
|
|
120
|
-
const sizeInKB = sizeInBytes / 1024;
|
|
121
|
-
|
|
122
|
-
// Limit to 1MB per item
|
|
123
|
-
if (sizeInKB > 1024) {
|
|
124
|
-
console.warn(`Data size (${sizeInKB.toFixed(2)}KB) exceeds 1MB limit for key "${key}"`);
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return true;
|
|
129
|
-
} catch (error) {
|
|
130
|
-
console.error(`Error checking data size for key "${key}":`, error);
|
|
131
|
-
return false;
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
// Clear old data when sessionStorage is full
|
|
136
|
-
const clearOldData = () => {
|
|
137
|
-
try {
|
|
138
|
-
const keys = Object.keys(sessionStorage).filter(k => k && typeof k === 'string');
|
|
139
|
-
// Remove oldest items if we have more than 50 items
|
|
140
|
-
if (keys.length > 50) {
|
|
141
|
-
const itemsToRemove = Math.ceil(keys.length * 0.2);
|
|
142
|
-
for (let i = 0; i < itemsToRemove; i++) {
|
|
143
|
-
try {
|
|
144
|
-
const k = keys[i];
|
|
145
|
-
if (k) {
|
|
146
|
-
sessionStorage.removeItem(k);
|
|
147
|
-
}
|
|
148
|
-
} catch {
|
|
149
|
-
// Ignore errors when removing items
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
} catch (error) {
|
|
154
|
-
console.error('Error clearing old sessionStorage data:', error);
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
// Force clear all data if quota is exceeded
|
|
159
|
-
const forceClearAll = () => {
|
|
160
|
-
try {
|
|
161
|
-
const keys = Object.keys(sessionStorage);
|
|
162
|
-
for (const k of keys) {
|
|
163
|
-
try {
|
|
164
|
-
sessionStorage.removeItem(k);
|
|
165
|
-
} catch {
|
|
166
|
-
// Ignore errors when removing items
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
} catch (error) {
|
|
170
|
-
console.error('Error force clearing sessionStorage:', error);
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
// Prepare data for storage (with or without TTL wrapper)
|
|
175
|
-
const prepareForStorage = (value: T): string => {
|
|
176
|
-
if (ttl) {
|
|
177
|
-
// Wrap with _meta for TTL support
|
|
178
|
-
const wrapped: StorageWrapper<T> = {
|
|
179
|
-
_meta: {
|
|
180
|
-
createdAt: Date.now(),
|
|
181
|
-
ttl,
|
|
182
|
-
},
|
|
183
|
-
_value: value,
|
|
184
|
-
};
|
|
185
|
-
return JSON.stringify(wrapped);
|
|
186
|
-
}
|
|
187
|
-
// Old format (no wrapper) - for strings, store directly
|
|
188
|
-
if (typeof value === 'string') {
|
|
189
|
-
return value;
|
|
190
|
-
}
|
|
191
|
-
return JSON.stringify(value);
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
// Update sessionStorage when value changes
|
|
195
|
-
const setValue = (value: T | ((val: T) => T)) => {
|
|
196
|
-
try {
|
|
197
|
-
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
|
198
|
-
|
|
199
|
-
// Check data size before attempting to save
|
|
200
|
-
if (!checkDataSize(valueToStore)) {
|
|
201
|
-
console.warn(`Data size too large for key "${key}", removing key`);
|
|
202
|
-
// Remove the key if data is too large
|
|
203
|
-
try {
|
|
204
|
-
window.sessionStorage.removeItem(key);
|
|
205
|
-
} catch {
|
|
206
|
-
// Ignore errors when removing
|
|
207
|
-
}
|
|
208
|
-
// Still update the state
|
|
209
|
-
setStoredValue(valueToStore);
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
setStoredValue(valueToStore);
|
|
214
|
-
|
|
215
|
-
if (typeof window !== 'undefined') {
|
|
216
|
-
const dataToStore = prepareForStorage(valueToStore);
|
|
217
|
-
|
|
218
|
-
// Try to set the value
|
|
219
|
-
try {
|
|
220
|
-
window.sessionStorage.setItem(key, dataToStore);
|
|
221
|
-
} catch (storageError: any) {
|
|
222
|
-
// If quota exceeded, clear old data and try again
|
|
223
|
-
if (storageError.name === 'QuotaExceededError' ||
|
|
224
|
-
storageError.code === 22 ||
|
|
225
|
-
storageError.message?.includes('quota')) {
|
|
226
|
-
console.warn('sessionStorage quota exceeded, clearing old data...');
|
|
227
|
-
clearOldData();
|
|
228
|
-
|
|
229
|
-
// Try again after clearing
|
|
230
|
-
try {
|
|
231
|
-
window.sessionStorage.setItem(key, dataToStore);
|
|
232
|
-
} catch (retryError) {
|
|
233
|
-
console.error(`Failed to set sessionStorage key "${key}" after clearing old data:`, retryError);
|
|
234
|
-
// If still fails, force clear all and try one more time
|
|
235
|
-
try {
|
|
236
|
-
forceClearAll();
|
|
237
|
-
window.sessionStorage.setItem(key, dataToStore);
|
|
238
|
-
} catch (finalError) {
|
|
239
|
-
console.error(`Failed to set sessionStorage key "${key}" after force clearing:`, finalError);
|
|
240
|
-
// If still fails, just update the state without sessionStorage
|
|
241
|
-
setStoredValue(valueToStore);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
} else {
|
|
245
|
-
throw storageError;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
} catch (error) {
|
|
250
|
-
console.error(`Error setting sessionStorage key "${key}":`, error);
|
|
251
|
-
// Still update the state even if sessionStorage fails
|
|
252
|
-
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
|
253
|
-
setStoredValue(valueToStore);
|
|
254
|
-
}
|
|
255
|
-
};
|
|
256
|
-
|
|
257
|
-
// Remove value from sessionStorage
|
|
258
|
-
const removeValue = () => {
|
|
259
|
-
try {
|
|
260
|
-
setStoredValue(initialValue);
|
|
261
|
-
if (typeof window !== 'undefined') {
|
|
262
|
-
try {
|
|
263
|
-
window.sessionStorage.removeItem(key);
|
|
264
|
-
} catch (removeError: any) {
|
|
265
|
-
// If removal fails due to quota, try to clear some data first
|
|
266
|
-
if (removeError.name === 'QuotaExceededError' ||
|
|
267
|
-
removeError.code === 22 ||
|
|
268
|
-
removeError.message?.includes('quota')) {
|
|
269
|
-
console.warn('sessionStorage quota exceeded during removal, clearing old data...');
|
|
270
|
-
clearOldData();
|
|
271
|
-
|
|
272
|
-
try {
|
|
273
|
-
window.sessionStorage.removeItem(key);
|
|
274
|
-
} catch (retryError) {
|
|
275
|
-
console.error(`Failed to remove sessionStorage key "${key}" after clearing:`, retryError);
|
|
276
|
-
// If still fails, force clear all
|
|
277
|
-
forceClearAll();
|
|
278
|
-
}
|
|
279
|
-
} else {
|
|
280
|
-
throw removeError;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
} catch (error) {
|
|
285
|
-
console.error(`Error removing sessionStorage key "${key}":`, error);
|
|
286
|
-
}
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
return [storedValue, setValue, removeValue] as const;
|
|
290
|
-
}
|
package/src/lib/index.ts
DELETED
package/src/lib/logger/index.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Universal Logger
|
|
3
|
-
*
|
|
4
|
-
* Combines console logging with zustand store for Console panel.
|
|
5
|
-
* Use createMediaLogger for media tools (AudioPlayer, VideoPlayer, ImageViewer).
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export { createLogger, createMediaLogger, logger, log } from './logger';
|
|
9
|
-
export { useLogStore, useFilteredLogs, useLogCount, useErrorCount } from './logStore';
|
|
10
|
-
export type { LogEntry, LogLevel, LogFilter, LogStore, Logger, MediaLogger } from './types';
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Log Store
|
|
3
|
-
*
|
|
4
|
-
* Zustand store for log accumulation and filtering.
|
|
5
|
-
* Keeps logs in memory for Console panel display.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
'use client';
|
|
9
|
-
|
|
10
|
-
import { create } from 'zustand';
|
|
11
|
-
import type { LogStore, LogEntry, LogFilter } from './types';
|
|
12
|
-
|
|
13
|
-
const DEFAULT_FILTER: LogFilter = {
|
|
14
|
-
levels: ['debug', 'info', 'warn', 'error', 'success'],
|
|
15
|
-
component: undefined,
|
|
16
|
-
search: undefined,
|
|
17
|
-
since: undefined,
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const MAX_LOGS = 1000;
|
|
21
|
-
|
|
22
|
-
function generateId(): string {
|
|
23
|
-
return `log-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function matchesFilter(entry: LogEntry, filter: LogFilter): boolean {
|
|
27
|
-
// Level filter
|
|
28
|
-
if (!filter.levels.includes(entry.level)) {
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Component filter (case-insensitive partial match)
|
|
33
|
-
if (filter.component) {
|
|
34
|
-
const comp = filter.component.toLowerCase();
|
|
35
|
-
if (!entry.component.toLowerCase().includes(comp)) {
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Search filter (case-insensitive, searches message and data)
|
|
41
|
-
if (filter.search) {
|
|
42
|
-
const search = filter.search.toLowerCase();
|
|
43
|
-
const inMessage = entry.message.toLowerCase().includes(search);
|
|
44
|
-
const inData = entry.data
|
|
45
|
-
? JSON.stringify(entry.data).toLowerCase().includes(search)
|
|
46
|
-
: false;
|
|
47
|
-
if (!inMessage && !inData) {
|
|
48
|
-
return false;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Time filter
|
|
53
|
-
if (filter.since && entry.timestamp < filter.since) {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return true;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export const useLogStore = create<LogStore>((set, get) => ({
|
|
61
|
-
logs: [],
|
|
62
|
-
filter: DEFAULT_FILTER,
|
|
63
|
-
maxLogs: MAX_LOGS,
|
|
64
|
-
|
|
65
|
-
addLog: (entry) => {
|
|
66
|
-
const newEntry: LogEntry = {
|
|
67
|
-
...entry,
|
|
68
|
-
id: generateId(),
|
|
69
|
-
timestamp: new Date(),
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
set((state) => {
|
|
73
|
-
const newLogs = [...state.logs, newEntry];
|
|
74
|
-
// Trim to max size
|
|
75
|
-
if (newLogs.length > state.maxLogs) {
|
|
76
|
-
return { logs: newLogs.slice(-state.maxLogs) };
|
|
77
|
-
}
|
|
78
|
-
return { logs: newLogs };
|
|
79
|
-
});
|
|
80
|
-
},
|
|
81
|
-
|
|
82
|
-
clearLogs: () => {
|
|
83
|
-
set({ logs: [] });
|
|
84
|
-
},
|
|
85
|
-
|
|
86
|
-
setFilter: (filter) => {
|
|
87
|
-
set((state) => ({
|
|
88
|
-
filter: { ...state.filter, ...filter },
|
|
89
|
-
}));
|
|
90
|
-
},
|
|
91
|
-
|
|
92
|
-
resetFilter: () => {
|
|
93
|
-
set({ filter: DEFAULT_FILTER });
|
|
94
|
-
},
|
|
95
|
-
|
|
96
|
-
getFilteredLogs: () => {
|
|
97
|
-
const { logs, filter } = get();
|
|
98
|
-
return logs.filter((entry) => matchesFilter(entry, filter));
|
|
99
|
-
},
|
|
100
|
-
|
|
101
|
-
exportLogs: () => {
|
|
102
|
-
const { logs } = get();
|
|
103
|
-
return JSON.stringify(logs, null, 2);
|
|
104
|
-
},
|
|
105
|
-
}));
|
|
106
|
-
|
|
107
|
-
// Selector hooks for performance
|
|
108
|
-
export const useFilteredLogs = () => {
|
|
109
|
-
const logs = useLogStore((state) => state.logs);
|
|
110
|
-
const filter = useLogStore((state) => state.filter);
|
|
111
|
-
return logs.filter((entry) => matchesFilter(entry, filter));
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
export const useLogCount = () => {
|
|
115
|
-
return useLogStore((state) => state.logs.length);
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
export const useErrorCount = () => {
|
|
119
|
-
return useLogStore((state) =>
|
|
120
|
-
state.logs.filter((log) => log.level === 'error').length
|
|
121
|
-
);
|
|
122
|
-
};
|
package/src/lib/logger/logger.ts
DELETED
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Logger
|
|
3
|
-
*
|
|
4
|
-
* Universal logger with consola + zustand store integration.
|
|
5
|
-
* Logs are accumulated for Console panel display.
|
|
6
|
-
* In production, only logs to store (no console output).
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
'use client';
|
|
10
|
-
|
|
11
|
-
import { consola, type ConsolaInstance } from 'consola';
|
|
12
|
-
import { useLogStore } from './logStore';
|
|
13
|
-
import type { Logger, LogLevel, MediaLogger } from './types';
|
|
14
|
-
|
|
15
|
-
// Check environment
|
|
16
|
-
const isDev = process.env.NODE_ENV !== 'production';
|
|
17
|
-
const isBrowser = typeof window !== 'undefined';
|
|
18
|
-
|
|
19
|
-
// Create base consola instance
|
|
20
|
-
const baseConsola = consola.create({
|
|
21
|
-
level: isDev ? 4 : 2, // 4 = debug, 2 = warn
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Extract error details from unknown error type
|
|
26
|
-
*/
|
|
27
|
-
function extractErrorData(data?: Record<string, unknown>): {
|
|
28
|
-
cleanData: Record<string, unknown> | undefined;
|
|
29
|
-
stack: string | undefined;
|
|
30
|
-
} {
|
|
31
|
-
if (!data) return { cleanData: undefined, stack: undefined };
|
|
32
|
-
|
|
33
|
-
const cleanData = { ...data };
|
|
34
|
-
let stack: string | undefined;
|
|
35
|
-
|
|
36
|
-
// Extract stack from error object
|
|
37
|
-
if (data.error instanceof Error) {
|
|
38
|
-
stack = data.error.stack;
|
|
39
|
-
cleanData.error = {
|
|
40
|
-
name: data.error.name,
|
|
41
|
-
message: data.error.message,
|
|
42
|
-
};
|
|
43
|
-
} else if (typeof data.error === 'object' && data.error !== null) {
|
|
44
|
-
const errObj = data.error as Record<string, unknown>;
|
|
45
|
-
if (typeof errObj.stack === 'string') {
|
|
46
|
-
stack = errObj.stack;
|
|
47
|
-
}
|
|
48
|
-
if (typeof errObj.message === 'string') {
|
|
49
|
-
cleanData.error = errObj.message;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return { cleanData, stack };
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Format buffer ranges for logging
|
|
58
|
-
*/
|
|
59
|
-
function formatBufferRanges(buffered: TimeRanges, duration: number): string {
|
|
60
|
-
if (buffered.length === 0) return 'empty';
|
|
61
|
-
|
|
62
|
-
const ranges: string[] = [];
|
|
63
|
-
for (let i = 0; i < buffered.length; i++) {
|
|
64
|
-
const start = buffered.start(i);
|
|
65
|
-
const end = buffered.end(i);
|
|
66
|
-
const percent = ((end - start) / duration * 100).toFixed(1);
|
|
67
|
-
ranges.push(`${start.toFixed(1)}-${end.toFixed(1)}s (${percent}%)`);
|
|
68
|
-
}
|
|
69
|
-
return ranges.join(', ');
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Create a logger for a specific component/module
|
|
74
|
-
*/
|
|
75
|
-
export function createLogger(component: string): Logger {
|
|
76
|
-
const consolaTagged = baseConsola.withTag(component);
|
|
77
|
-
|
|
78
|
-
const log = (level: LogLevel, message: string, data?: Record<string, unknown>) => {
|
|
79
|
-
const { cleanData, stack } = extractErrorData(data);
|
|
80
|
-
|
|
81
|
-
// Add to store (for Console panel)
|
|
82
|
-
if (isBrowser) {
|
|
83
|
-
useLogStore.getState().addLog({
|
|
84
|
-
level,
|
|
85
|
-
component,
|
|
86
|
-
message,
|
|
87
|
-
data: cleanData,
|
|
88
|
-
stack,
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Log to console via consola (in dev mode)
|
|
93
|
-
if (isDev) {
|
|
94
|
-
const consolaMethod = level === 'success' ? 'success' : level;
|
|
95
|
-
if (cleanData) {
|
|
96
|
-
consolaTagged[consolaMethod](message, cleanData);
|
|
97
|
-
} else {
|
|
98
|
-
consolaTagged[consolaMethod](message);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
return {
|
|
104
|
-
debug: (message, data) => log('debug', message, data),
|
|
105
|
-
info: (message, data) => log('info', message, data),
|
|
106
|
-
warn: (message, data) => log('warn', message, data),
|
|
107
|
-
error: (message, data) => log('error', message, data),
|
|
108
|
-
success: (message, data) => log('success', message, data),
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Create a media-specific logger with helper methods
|
|
114
|
-
* for AudioPlayer, VideoPlayer, ImageViewer
|
|
115
|
-
*/
|
|
116
|
-
export function createMediaLogger(component: string): MediaLogger {
|
|
117
|
-
const baseLogger = createLogger(component);
|
|
118
|
-
|
|
119
|
-
return {
|
|
120
|
-
...baseLogger,
|
|
121
|
-
|
|
122
|
-
load: (src: string, type?: string) => {
|
|
123
|
-
const typeStr = type ? ` (${type})` : '';
|
|
124
|
-
baseLogger.info(`LOAD: ${src}${typeStr}`);
|
|
125
|
-
},
|
|
126
|
-
|
|
127
|
-
state: (state: string, details?: Record<string, unknown>) => {
|
|
128
|
-
baseLogger.debug(`STATE: ${state}`, details);
|
|
129
|
-
},
|
|
130
|
-
|
|
131
|
-
seek: (from: number, to: number, duration: number) => {
|
|
132
|
-
baseLogger.debug(`SEEK: ${from.toFixed(2)}s -> ${to.toFixed(2)}s`, {
|
|
133
|
-
from,
|
|
134
|
-
to,
|
|
135
|
-
duration,
|
|
136
|
-
progress: `${((to / duration) * 100).toFixed(1)}%`,
|
|
137
|
-
});
|
|
138
|
-
},
|
|
139
|
-
|
|
140
|
-
buffer: (buffered: TimeRanges, duration: number) => {
|
|
141
|
-
if (buffered.length > 0) {
|
|
142
|
-
baseLogger.debug(`BUFFER: ${formatBufferRanges(buffered, duration)}`);
|
|
143
|
-
}
|
|
144
|
-
},
|
|
145
|
-
|
|
146
|
-
event: (name: string, data?: unknown) => {
|
|
147
|
-
if (data !== undefined) {
|
|
148
|
-
baseLogger.debug(`EVENT: ${name}`, { data });
|
|
149
|
-
} else {
|
|
150
|
-
baseLogger.debug(`EVENT: ${name}`);
|
|
151
|
-
}
|
|
152
|
-
},
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Global logger for non-component code
|
|
158
|
-
*/
|
|
159
|
-
export const logger = createLogger('App');
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Quick access for one-off logs
|
|
163
|
-
*/
|
|
164
|
-
export const log = {
|
|
165
|
-
debug: (component: string, message: string, data?: Record<string, unknown>) =>
|
|
166
|
-
createLogger(component).debug(message, data),
|
|
167
|
-
info: (component: string, message: string, data?: Record<string, unknown>) =>
|
|
168
|
-
createLogger(component).info(message, data),
|
|
169
|
-
warn: (component: string, message: string, data?: Record<string, unknown>) =>
|
|
170
|
-
createLogger(component).warn(message, data),
|
|
171
|
-
error: (component: string, message: string, data?: Record<string, unknown>) =>
|
|
172
|
-
createLogger(component).error(message, data),
|
|
173
|
-
success: (component: string, message: string, data?: Record<string, unknown>) =>
|
|
174
|
-
createLogger(component).success(message, data),
|
|
175
|
-
};
|
package/src/lib/logger/types.ts
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Logger Types
|
|
3
|
-
*
|
|
4
|
-
* Type definitions for the universal logging system.
|
|
5
|
-
* Compatible with Console panel in FileWorkspace IDE layout.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'success';
|
|
9
|
-
|
|
10
|
-
export interface LogEntry {
|
|
11
|
-
/** Unique log ID */
|
|
12
|
-
id: string;
|
|
13
|
-
/** Timestamp when log was created */
|
|
14
|
-
timestamp: Date;
|
|
15
|
-
/** Log level */
|
|
16
|
-
level: LogLevel;
|
|
17
|
-
/** Component/module name that created the log */
|
|
18
|
-
component: string;
|
|
19
|
-
/** Log message */
|
|
20
|
-
message: string;
|
|
21
|
-
/** Additional data (objects, errors, etc.) */
|
|
22
|
-
data?: Record<string, unknown>;
|
|
23
|
-
/** Error stack trace (for error level) */
|
|
24
|
-
stack?: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface LogFilter {
|
|
28
|
-
/** Filter by log levels */
|
|
29
|
-
levels: LogLevel[];
|
|
30
|
-
/** Filter by component name (partial match) */
|
|
31
|
-
component?: string;
|
|
32
|
-
/** Filter by message text (partial match) */
|
|
33
|
-
search?: string;
|
|
34
|
-
/** Filter by time range */
|
|
35
|
-
since?: Date;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface LogStore {
|
|
39
|
-
/** All accumulated logs */
|
|
40
|
-
logs: LogEntry[];
|
|
41
|
-
/** Current filter settings */
|
|
42
|
-
filter: LogFilter;
|
|
43
|
-
/** Maximum logs to keep */
|
|
44
|
-
maxLogs: number;
|
|
45
|
-
|
|
46
|
-
/** Add new log entry */
|
|
47
|
-
addLog: (entry: Omit<LogEntry, 'id' | 'timestamp'>) => void;
|
|
48
|
-
/** Clear all logs */
|
|
49
|
-
clearLogs: () => void;
|
|
50
|
-
/** Update filter settings */
|
|
51
|
-
setFilter: (filter: Partial<LogFilter>) => void;
|
|
52
|
-
/** Reset filter to defaults */
|
|
53
|
-
resetFilter: () => void;
|
|
54
|
-
/** Get filtered logs */
|
|
55
|
-
getFilteredLogs: () => LogEntry[];
|
|
56
|
-
/** Export logs as JSON string */
|
|
57
|
-
exportLogs: () => string;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export interface Logger {
|
|
61
|
-
debug: (message: string, data?: Record<string, unknown>) => void;
|
|
62
|
-
info: (message: string, data?: Record<string, unknown>) => void;
|
|
63
|
-
warn: (message: string, data?: Record<string, unknown>) => void;
|
|
64
|
-
error: (message: string, data?: Record<string, unknown>) => void;
|
|
65
|
-
success: (message: string, data?: Record<string, unknown>) => void;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Media-specific log helper methods
|
|
70
|
-
*/
|
|
71
|
-
export interface MediaLogger extends Logger {
|
|
72
|
-
/** Log source load event */
|
|
73
|
-
load: (src: string, type?: string) => void;
|
|
74
|
-
/** Log state change */
|
|
75
|
-
state: (state: string, details?: Record<string, unknown>) => void;
|
|
76
|
-
/** Log seek event */
|
|
77
|
-
seek: (from: number, to: number, duration: number) => void;
|
|
78
|
-
/** Log buffer ranges */
|
|
79
|
-
buffer: (buffered: TimeRanges, duration: number) => void;
|
|
80
|
-
/** Log generic event */
|
|
81
|
-
event: (name: string, data?: unknown) => void;
|
|
82
|
-
}
|