@djangocfg/ui-core 2.1.100 → 2.1.102
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/components.cjs +6825 -0
- package/dist/components.cjs.map +1 -0
- package/dist/components.d.mts +1536 -0
- package/dist/components.d.ts +1536 -0
- package/dist/components.mjs +6523 -0
- package/dist/components.mjs.map +1 -0
- package/dist/hooks.cjs +715 -0
- package/dist/hooks.cjs.map +1 -0
- package/dist/hooks.mjs +675 -0
- package/dist/hooks.mjs.map +1 -0
- package/dist/index.cjs +7301 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.mts +1861 -0
- package/dist/index.d.ts +1861 -0
- package/dist/index.mjs +6969 -0
- package/dist/index.mjs.map +1 -0
- package/dist/lib.cjs +277 -0
- package/dist/lib.cjs.map +1 -0
- package/dist/lib.mjs +264 -0
- package/dist/lib.mjs.map +1 -0
- package/package.json +30 -8
- package/src/components/otp/index.tsx +1 -1
package/dist/lib.cjs
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var clsx = require('clsx');
|
|
4
|
+
var tailwindMerge = require('tailwind-merge');
|
|
5
|
+
var consola = require('consola');
|
|
6
|
+
var zustand = require('zustand');
|
|
7
|
+
|
|
8
|
+
var __defProp = Object.defineProperty;
|
|
9
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
10
|
+
function cn(...inputs) {
|
|
11
|
+
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
12
|
+
}
|
|
13
|
+
__name(cn, "cn");
|
|
14
|
+
|
|
15
|
+
// src/lib/og-image.ts
|
|
16
|
+
var DEFAULT_OG_IMAGE_BASE_URL = "https://djangocfg.com/api/og";
|
|
17
|
+
function encodeBase64(str) {
|
|
18
|
+
if (typeof Buffer !== "undefined") {
|
|
19
|
+
return Buffer.from(str, "utf-8").toString("base64");
|
|
20
|
+
}
|
|
21
|
+
const utf8Bytes = new TextEncoder().encode(str);
|
|
22
|
+
const binaryString = Array.from(utf8Bytes, (byte) => String.fromCharCode(byte)).join("");
|
|
23
|
+
return btoa(binaryString);
|
|
24
|
+
}
|
|
25
|
+
__name(encodeBase64, "encodeBase64");
|
|
26
|
+
function generateOgImageUrl(params, options = {}) {
|
|
27
|
+
const { baseUrl = DEFAULT_OG_IMAGE_BASE_URL, useBase64 = true } = options;
|
|
28
|
+
if (useBase64) {
|
|
29
|
+
const cleanParams = {};
|
|
30
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
31
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
32
|
+
cleanParams[key] = value;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
const jsonString = JSON.stringify(cleanParams);
|
|
36
|
+
const base64Data = encodeBase64(jsonString);
|
|
37
|
+
return `${baseUrl}/${base64Data}`;
|
|
38
|
+
} else {
|
|
39
|
+
const searchParams = new URLSearchParams();
|
|
40
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
41
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
42
|
+
searchParams.append(key, String(value));
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
const query = searchParams.toString();
|
|
46
|
+
return query ? `${baseUrl}?${query}` : baseUrl;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
__name(generateOgImageUrl, "generateOgImageUrl");
|
|
50
|
+
function getAbsoluteOgImageUrl(relativePath, siteUrl) {
|
|
51
|
+
if (relativePath.startsWith("http://") || relativePath.startsWith("https://")) {
|
|
52
|
+
return relativePath;
|
|
53
|
+
}
|
|
54
|
+
const cleanSiteUrl = siteUrl.replace(/\/$/, "");
|
|
55
|
+
const cleanPath = relativePath.startsWith("/") ? relativePath : `/${relativePath}`;
|
|
56
|
+
return `${cleanSiteUrl}${cleanPath}`;
|
|
57
|
+
}
|
|
58
|
+
__name(getAbsoluteOgImageUrl, "getAbsoluteOgImageUrl");
|
|
59
|
+
function createOgImageUrlBuilder(defaults = {}, options = {}) {
|
|
60
|
+
return (params) => {
|
|
61
|
+
return generateOgImageUrl({ ...defaults, ...params }, options);
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
__name(createOgImageUrlBuilder, "createOgImageUrlBuilder");
|
|
65
|
+
var DEFAULT_FILTER = {
|
|
66
|
+
levels: ["debug", "info", "warn", "error", "success"],
|
|
67
|
+
component: void 0,
|
|
68
|
+
search: void 0,
|
|
69
|
+
since: void 0
|
|
70
|
+
};
|
|
71
|
+
var MAX_LOGS = 1e3;
|
|
72
|
+
function generateId() {
|
|
73
|
+
return `log-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
74
|
+
}
|
|
75
|
+
__name(generateId, "generateId");
|
|
76
|
+
function matchesFilter(entry, filter) {
|
|
77
|
+
if (!filter.levels.includes(entry.level)) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
if (filter.component) {
|
|
81
|
+
const comp = filter.component.toLowerCase();
|
|
82
|
+
if (!entry.component.toLowerCase().includes(comp)) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (filter.search) {
|
|
87
|
+
const search = filter.search.toLowerCase();
|
|
88
|
+
const inMessage = entry.message.toLowerCase().includes(search);
|
|
89
|
+
const inData = entry.data ? JSON.stringify(entry.data).toLowerCase().includes(search) : false;
|
|
90
|
+
if (!inMessage && !inData) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (filter.since && entry.timestamp < filter.since) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
__name(matchesFilter, "matchesFilter");
|
|
100
|
+
var useLogStore = zustand.create((set, get) => ({
|
|
101
|
+
logs: [],
|
|
102
|
+
filter: DEFAULT_FILTER,
|
|
103
|
+
maxLogs: MAX_LOGS,
|
|
104
|
+
addLog: /* @__PURE__ */ __name((entry) => {
|
|
105
|
+
const newEntry = {
|
|
106
|
+
...entry,
|
|
107
|
+
id: generateId(),
|
|
108
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
109
|
+
};
|
|
110
|
+
set((state) => {
|
|
111
|
+
const newLogs = [...state.logs, newEntry];
|
|
112
|
+
if (newLogs.length > state.maxLogs) {
|
|
113
|
+
return { logs: newLogs.slice(-state.maxLogs) };
|
|
114
|
+
}
|
|
115
|
+
return { logs: newLogs };
|
|
116
|
+
});
|
|
117
|
+
}, "addLog"),
|
|
118
|
+
clearLogs: /* @__PURE__ */ __name(() => {
|
|
119
|
+
set({ logs: [] });
|
|
120
|
+
}, "clearLogs"),
|
|
121
|
+
setFilter: /* @__PURE__ */ __name((filter) => {
|
|
122
|
+
set((state) => ({
|
|
123
|
+
filter: { ...state.filter, ...filter }
|
|
124
|
+
}));
|
|
125
|
+
}, "setFilter"),
|
|
126
|
+
resetFilter: /* @__PURE__ */ __name(() => {
|
|
127
|
+
set({ filter: DEFAULT_FILTER });
|
|
128
|
+
}, "resetFilter"),
|
|
129
|
+
getFilteredLogs: /* @__PURE__ */ __name(() => {
|
|
130
|
+
const { logs, filter } = get();
|
|
131
|
+
return logs.filter((entry) => matchesFilter(entry, filter));
|
|
132
|
+
}, "getFilteredLogs"),
|
|
133
|
+
exportLogs: /* @__PURE__ */ __name(() => {
|
|
134
|
+
const { logs } = get();
|
|
135
|
+
return JSON.stringify(logs, null, 2);
|
|
136
|
+
}, "exportLogs")
|
|
137
|
+
}));
|
|
138
|
+
var useFilteredLogs = /* @__PURE__ */ __name(() => {
|
|
139
|
+
const logs = useLogStore((state) => state.logs);
|
|
140
|
+
const filter = useLogStore((state) => state.filter);
|
|
141
|
+
return logs.filter((entry) => matchesFilter(entry, filter));
|
|
142
|
+
}, "useFilteredLogs");
|
|
143
|
+
var useLogCount = /* @__PURE__ */ __name(() => {
|
|
144
|
+
return useLogStore((state) => state.logs.length);
|
|
145
|
+
}, "useLogCount");
|
|
146
|
+
var useErrorCount = /* @__PURE__ */ __name(() => {
|
|
147
|
+
return useLogStore(
|
|
148
|
+
(state) => state.logs.filter((log2) => log2.level === "error").length
|
|
149
|
+
);
|
|
150
|
+
}, "useErrorCount");
|
|
151
|
+
var isBrowser = typeof window !== "undefined";
|
|
152
|
+
var baseConsola = consola.consola.create({
|
|
153
|
+
level: 4
|
|
154
|
+
// 4 = debug, 2 = warn
|
|
155
|
+
});
|
|
156
|
+
function extractErrorData(data) {
|
|
157
|
+
if (!data) return { cleanData: void 0, stack: void 0 };
|
|
158
|
+
const cleanData = { ...data };
|
|
159
|
+
let stack;
|
|
160
|
+
if (data.error instanceof Error) {
|
|
161
|
+
stack = data.error.stack;
|
|
162
|
+
cleanData.error = {
|
|
163
|
+
name: data.error.name,
|
|
164
|
+
message: data.error.message
|
|
165
|
+
};
|
|
166
|
+
} else if (typeof data.error === "object" && data.error !== null) {
|
|
167
|
+
const errObj = data.error;
|
|
168
|
+
if (typeof errObj.stack === "string") {
|
|
169
|
+
stack = errObj.stack;
|
|
170
|
+
}
|
|
171
|
+
if (typeof errObj.message === "string") {
|
|
172
|
+
cleanData.error = errObj.message;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return { cleanData, stack };
|
|
176
|
+
}
|
|
177
|
+
__name(extractErrorData, "extractErrorData");
|
|
178
|
+
function formatBufferRanges(buffered, duration) {
|
|
179
|
+
if (buffered.length === 0) return "empty";
|
|
180
|
+
const ranges = [];
|
|
181
|
+
for (let i = 0; i < buffered.length; i++) {
|
|
182
|
+
const start = buffered.start(i);
|
|
183
|
+
const end = buffered.end(i);
|
|
184
|
+
const percent = ((end - start) / duration * 100).toFixed(1);
|
|
185
|
+
ranges.push(`${start.toFixed(1)}-${end.toFixed(1)}s (${percent}%)`);
|
|
186
|
+
}
|
|
187
|
+
return ranges.join(", ");
|
|
188
|
+
}
|
|
189
|
+
__name(formatBufferRanges, "formatBufferRanges");
|
|
190
|
+
function createLogger(component) {
|
|
191
|
+
const consolaTagged = baseConsola.withTag(component);
|
|
192
|
+
const log2 = /* @__PURE__ */ __name((level, message, data) => {
|
|
193
|
+
const { cleanData, stack } = extractErrorData(data);
|
|
194
|
+
if (isBrowser) {
|
|
195
|
+
useLogStore.getState().addLog({
|
|
196
|
+
level,
|
|
197
|
+
component,
|
|
198
|
+
message,
|
|
199
|
+
data: cleanData,
|
|
200
|
+
stack
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
{
|
|
204
|
+
const consolaMethod = level === "success" ? "success" : level;
|
|
205
|
+
if (cleanData) {
|
|
206
|
+
consolaTagged[consolaMethod](message, cleanData);
|
|
207
|
+
} else {
|
|
208
|
+
consolaTagged[consolaMethod](message);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}, "log");
|
|
212
|
+
return {
|
|
213
|
+
debug: /* @__PURE__ */ __name((message, data) => log2("debug", message, data), "debug"),
|
|
214
|
+
info: /* @__PURE__ */ __name((message, data) => log2("info", message, data), "info"),
|
|
215
|
+
warn: /* @__PURE__ */ __name((message, data) => log2("warn", message, data), "warn"),
|
|
216
|
+
error: /* @__PURE__ */ __name((message, data) => log2("error", message, data), "error"),
|
|
217
|
+
success: /* @__PURE__ */ __name((message, data) => log2("success", message, data), "success")
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
__name(createLogger, "createLogger");
|
|
221
|
+
function createMediaLogger(component) {
|
|
222
|
+
const baseLogger = createLogger(component);
|
|
223
|
+
return {
|
|
224
|
+
...baseLogger,
|
|
225
|
+
load: /* @__PURE__ */ __name((src, type) => {
|
|
226
|
+
const typeStr = type ? ` (${type})` : "";
|
|
227
|
+
baseLogger.info(`LOAD: ${src}${typeStr}`);
|
|
228
|
+
}, "load"),
|
|
229
|
+
state: /* @__PURE__ */ __name((state, details) => {
|
|
230
|
+
baseLogger.debug(`STATE: ${state}`, details);
|
|
231
|
+
}, "state"),
|
|
232
|
+
seek: /* @__PURE__ */ __name((from, to, duration) => {
|
|
233
|
+
baseLogger.debug(`SEEK: ${from.toFixed(2)}s -> ${to.toFixed(2)}s`, {
|
|
234
|
+
from,
|
|
235
|
+
to,
|
|
236
|
+
duration,
|
|
237
|
+
progress: `${(to / duration * 100).toFixed(1)}%`
|
|
238
|
+
});
|
|
239
|
+
}, "seek"),
|
|
240
|
+
buffer: /* @__PURE__ */ __name((buffered, duration) => {
|
|
241
|
+
if (buffered.length > 0) {
|
|
242
|
+
baseLogger.debug(`BUFFER: ${formatBufferRanges(buffered, duration)}`);
|
|
243
|
+
}
|
|
244
|
+
}, "buffer"),
|
|
245
|
+
event: /* @__PURE__ */ __name((name, data) => {
|
|
246
|
+
if (data !== void 0) {
|
|
247
|
+
baseLogger.debug(`EVENT: ${name}`, { data });
|
|
248
|
+
} else {
|
|
249
|
+
baseLogger.debug(`EVENT: ${name}`);
|
|
250
|
+
}
|
|
251
|
+
}, "event")
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
__name(createMediaLogger, "createMediaLogger");
|
|
255
|
+
var logger = createLogger("App");
|
|
256
|
+
var log = {
|
|
257
|
+
debug: /* @__PURE__ */ __name((component, message, data) => createLogger(component).debug(message, data), "debug"),
|
|
258
|
+
info: /* @__PURE__ */ __name((component, message, data) => createLogger(component).info(message, data), "info"),
|
|
259
|
+
warn: /* @__PURE__ */ __name((component, message, data) => createLogger(component).warn(message, data), "warn"),
|
|
260
|
+
error: /* @__PURE__ */ __name((component, message, data) => createLogger(component).error(message, data), "error"),
|
|
261
|
+
success: /* @__PURE__ */ __name((component, message, data) => createLogger(component).success(message, data), "success")
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
exports.cn = cn;
|
|
265
|
+
exports.createLogger = createLogger;
|
|
266
|
+
exports.createMediaLogger = createMediaLogger;
|
|
267
|
+
exports.createOgImageUrlBuilder = createOgImageUrlBuilder;
|
|
268
|
+
exports.generateOgImageUrl = generateOgImageUrl;
|
|
269
|
+
exports.getAbsoluteOgImageUrl = getAbsoluteOgImageUrl;
|
|
270
|
+
exports.log = log;
|
|
271
|
+
exports.logger = logger;
|
|
272
|
+
exports.useErrorCount = useErrorCount;
|
|
273
|
+
exports.useFilteredLogs = useFilteredLogs;
|
|
274
|
+
exports.useLogCount = useLogCount;
|
|
275
|
+
exports.useLogStore = useLogStore;
|
|
276
|
+
//# sourceMappingURL=lib.cjs.map
|
|
277
|
+
//# sourceMappingURL=lib.cjs.map
|
package/dist/lib.cjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/lib/og-image.ts","../src/lib/logger/logStore.ts","../src/lib/logger/logger.ts"],"names":["twMerge","clsx","create","log","consola"],"mappings":"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","file":"lib.cjs","sourcesContent":["import { ClassValue, clsx} from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","/**\n * OG Image URL Generation Utilities\n *\n * Client-side utilities for generating OG image URLs.\n */\n\n/** Default OG Image API base URL */\nconst DEFAULT_OG_IMAGE_BASE_URL = 'https://djangocfg.com/api/og';\n\n/**\n * Encode string to base64 with Unicode support\n * Works in both browser and Node.js environments\n */\nfunction encodeBase64(str: string): string {\n // Node.js environment\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(str, 'utf-8').toString('base64');\n }\n // Browser environment - handle Unicode via UTF-8 encoding\n const utf8Bytes = new TextEncoder().encode(str);\n const binaryString = Array.from(utf8Bytes, byte => String.fromCharCode(byte)).join('');\n return btoa(binaryString);\n}\n\n/**\n * OG Image URL parameters\n */\nexport interface OgImageUrlParams {\n /** Page title */\n title: string;\n /** Page description (optional) */\n description?: string;\n /** Site name (optional) */\n siteName?: string;\n /** Logo URL (optional) */\n logo?: string;\n /** Background type: 'gradient' or 'solid' */\n backgroundType?: 'gradient' | 'solid';\n /** Gradient start color (hex) */\n gradientStart?: string;\n /** Gradient end color (hex) */\n gradientEnd?: string;\n /** Background color (for solid type) */\n backgroundColor?: string;\n /** Title font size (px) */\n titleSize?: number;\n /** Title font weight */\n titleWeight?: number;\n /** Title text color */\n titleColor?: string;\n /** Description font size (px) */\n descriptionSize?: number;\n /** Description text color */\n descriptionColor?: string;\n /** Site name font size (px) */\n siteNameSize?: number;\n /** Site name text color */\n siteNameColor?: string;\n /** Padding (px) */\n padding?: number;\n /** Logo size (px) */\n logoSize?: number;\n /** Show logo flag */\n showLogo?: boolean;\n /** Show site name flag */\n showSiteName?: boolean;\n /** Additional custom parameters */\n [key: string]: string | number | boolean | undefined;\n}\n\n/**\n * Options for generating OG image URL\n */\nexport interface GenerateOgImageUrlOptions {\n /**\n * Base URL of the OG image API route\n * @default 'https://djangocfg.com/api/og'\n */\n baseUrl?: string;\n /**\n * If true, encode params as base64 for safer URLs\n * @default true\n */\n useBase64?: boolean;\n}\n\n/**\n * Generate OG image URL with query parameters or base64 encoding\n *\n * @example\n * ```typescript\n * // Using default baseUrl (https://djangocfg.com/api/og)\n * const url = generateOgImageUrl({ title: 'My Page Title' });\n *\n * // With custom baseUrl\n * const url = generateOgImageUrl({ title: 'My Page' }, { baseUrl: '/api/og' });\n * ```\n */\nexport function generateOgImageUrl(\n params: OgImageUrlParams,\n options: GenerateOgImageUrlOptions = {}\n): string {\n const { baseUrl = DEFAULT_OG_IMAGE_BASE_URL, useBase64 = true } = options;\n\n if (useBase64) {\n const cleanParams: Record<string, string | number | boolean> = {};\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined && value !== null && value !== '') {\n cleanParams[key] = value;\n }\n });\n\n const jsonString = JSON.stringify(cleanParams);\n const base64Data = encodeBase64(jsonString);\n return `${baseUrl}/${base64Data}`;\n } else {\n const searchParams = new URLSearchParams();\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined && value !== null && value !== '') {\n searchParams.append(key, String(value));\n }\n });\n const query = searchParams.toString();\n return query ? `${baseUrl}?${query}` : baseUrl;\n }\n}\n\n/**\n * Get absolute OG image URL from relative path\n */\nexport function getAbsoluteOgImageUrl(relativePath: string, siteUrl: string): string {\n // If path is already an absolute URL, return as-is\n if (relativePath.startsWith('http://') || relativePath.startsWith('https://')) {\n return relativePath;\n }\n const cleanSiteUrl = siteUrl.replace(/\\/$/, '');\n const cleanPath = relativePath.startsWith('/') ? relativePath : `/${relativePath}`;\n return `${cleanSiteUrl}${cleanPath}`;\n}\n\n/**\n * Create OG image URL builder with preset configuration\n */\nexport function createOgImageUrlBuilder(\n defaults: Partial<OgImageUrlParams> = {},\n options: GenerateOgImageUrlOptions = {}\n) {\n return (params: OgImageUrlParams): string => {\n return generateOgImageUrl({ ...defaults, ...params }, options);\n };\n}\n","/**\n * Log Store\n *\n * Zustand store for log accumulation and filtering.\n * Keeps logs in memory for Console panel display.\n */\n\n'use client';\n\nimport { create } from 'zustand';\nimport type { LogStore, LogEntry, LogFilter } from './types';\n\nconst DEFAULT_FILTER: LogFilter = {\n levels: ['debug', 'info', 'warn', 'error', 'success'],\n component: undefined,\n search: undefined,\n since: undefined,\n};\n\nconst MAX_LOGS = 1000;\n\nfunction generateId(): string {\n return `log-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;\n}\n\nfunction matchesFilter(entry: LogEntry, filter: LogFilter): boolean {\n // Level filter\n if (!filter.levels.includes(entry.level)) {\n return false;\n }\n\n // Component filter (case-insensitive partial match)\n if (filter.component) {\n const comp = filter.component.toLowerCase();\n if (!entry.component.toLowerCase().includes(comp)) {\n return false;\n }\n }\n\n // Search filter (case-insensitive, searches message and data)\n if (filter.search) {\n const search = filter.search.toLowerCase();\n const inMessage = entry.message.toLowerCase().includes(search);\n const inData = entry.data\n ? JSON.stringify(entry.data).toLowerCase().includes(search)\n : false;\n if (!inMessage && !inData) {\n return false;\n }\n }\n\n // Time filter\n if (filter.since && entry.timestamp < filter.since) {\n return false;\n }\n\n return true;\n}\n\nexport const useLogStore = create<LogStore>((set, get) => ({\n logs: [],\n filter: DEFAULT_FILTER,\n maxLogs: MAX_LOGS,\n\n addLog: (entry) => {\n const newEntry: LogEntry = {\n ...entry,\n id: generateId(),\n timestamp: new Date(),\n };\n\n set((state) => {\n const newLogs = [...state.logs, newEntry];\n // Trim to max size\n if (newLogs.length > state.maxLogs) {\n return { logs: newLogs.slice(-state.maxLogs) };\n }\n return { logs: newLogs };\n });\n },\n\n clearLogs: () => {\n set({ logs: [] });\n },\n\n setFilter: (filter) => {\n set((state) => ({\n filter: { ...state.filter, ...filter },\n }));\n },\n\n resetFilter: () => {\n set({ filter: DEFAULT_FILTER });\n },\n\n getFilteredLogs: () => {\n const { logs, filter } = get();\n return logs.filter((entry) => matchesFilter(entry, filter));\n },\n\n exportLogs: () => {\n const { logs } = get();\n return JSON.stringify(logs, null, 2);\n },\n}));\n\n// Selector hooks for performance\nexport const useFilteredLogs = () => {\n const logs = useLogStore((state) => state.logs);\n const filter = useLogStore((state) => state.filter);\n return logs.filter((entry) => matchesFilter(entry, filter));\n};\n\nexport const useLogCount = () => {\n return useLogStore((state) => state.logs.length);\n};\n\nexport const useErrorCount = () => {\n return useLogStore((state) =>\n state.logs.filter((log) => log.level === 'error').length\n );\n};\n","/**\n * Logger\n *\n * Universal logger with consola + zustand store integration.\n * Logs are accumulated for Console panel display.\n * In production, only logs to store (no console output).\n */\n\n'use client';\n\nimport { consola, type ConsolaInstance } from 'consola';\nimport { useLogStore } from './logStore';\nimport type { Logger, LogLevel, MediaLogger } from './types';\n\n// Check environment\nconst isDev = process.env.NODE_ENV !== 'production';\nconst isBrowser = typeof window !== 'undefined';\n\n// Create base consola instance\nconst baseConsola = consola.create({\n level: isDev ? 4 : 2, // 4 = debug, 2 = warn\n});\n\n/**\n * Extract error details from unknown error type\n */\nfunction extractErrorData(data?: Record<string, unknown>): {\n cleanData: Record<string, unknown> | undefined;\n stack: string | undefined;\n} {\n if (!data) return { cleanData: undefined, stack: undefined };\n\n const cleanData = { ...data };\n let stack: string | undefined;\n\n // Extract stack from error object\n if (data.error instanceof Error) {\n stack = data.error.stack;\n cleanData.error = {\n name: data.error.name,\n message: data.error.message,\n };\n } else if (typeof data.error === 'object' && data.error !== null) {\n const errObj = data.error as Record<string, unknown>;\n if (typeof errObj.stack === 'string') {\n stack = errObj.stack;\n }\n if (typeof errObj.message === 'string') {\n cleanData.error = errObj.message;\n }\n }\n\n return { cleanData, stack };\n}\n\n/**\n * Format buffer ranges for logging\n */\nfunction formatBufferRanges(buffered: TimeRanges, duration: number): string {\n if (buffered.length === 0) return 'empty';\n\n const ranges: string[] = [];\n for (let i = 0; i < buffered.length; i++) {\n const start = buffered.start(i);\n const end = buffered.end(i);\n const percent = ((end - start) / duration * 100).toFixed(1);\n ranges.push(`${start.toFixed(1)}-${end.toFixed(1)}s (${percent}%)`);\n }\n return ranges.join(', ');\n}\n\n/**\n * Create a logger for a specific component/module\n */\nexport function createLogger(component: string): Logger {\n const consolaTagged = baseConsola.withTag(component);\n\n const log = (level: LogLevel, message: string, data?: Record<string, unknown>) => {\n const { cleanData, stack } = extractErrorData(data);\n\n // Add to store (for Console panel)\n if (isBrowser) {\n useLogStore.getState().addLog({\n level,\n component,\n message,\n data: cleanData,\n stack,\n });\n }\n\n // Log to console via consola (in dev mode)\n if (isDev) {\n const consolaMethod = level === 'success' ? 'success' : level;\n if (cleanData) {\n consolaTagged[consolaMethod](message, cleanData);\n } else {\n consolaTagged[consolaMethod](message);\n }\n }\n };\n\n return {\n debug: (message, data) => log('debug', message, data),\n info: (message, data) => log('info', message, data),\n warn: (message, data) => log('warn', message, data),\n error: (message, data) => log('error', message, data),\n success: (message, data) => log('success', message, data),\n };\n}\n\n/**\n * Create a media-specific logger with helper methods\n * for AudioPlayer, VideoPlayer, ImageViewer\n */\nexport function createMediaLogger(component: string): MediaLogger {\n const baseLogger = createLogger(component);\n\n return {\n ...baseLogger,\n\n load: (src: string, type?: string) => {\n const typeStr = type ? ` (${type})` : '';\n baseLogger.info(`LOAD: ${src}${typeStr}`);\n },\n\n state: (state: string, details?: Record<string, unknown>) => {\n baseLogger.debug(`STATE: ${state}`, details);\n },\n\n seek: (from: number, to: number, duration: number) => {\n baseLogger.debug(`SEEK: ${from.toFixed(2)}s -> ${to.toFixed(2)}s`, {\n from,\n to,\n duration,\n progress: `${((to / duration) * 100).toFixed(1)}%`,\n });\n },\n\n buffer: (buffered: TimeRanges, duration: number) => {\n if (buffered.length > 0) {\n baseLogger.debug(`BUFFER: ${formatBufferRanges(buffered, duration)}`);\n }\n },\n\n event: (name: string, data?: unknown) => {\n if (data !== undefined) {\n baseLogger.debug(`EVENT: ${name}`, { data });\n } else {\n baseLogger.debug(`EVENT: ${name}`);\n }\n },\n };\n}\n\n/**\n * Global logger for non-component code\n */\nexport const logger = createLogger('App');\n\n/**\n * Quick access for one-off logs\n */\nexport const log = {\n debug: (component: string, message: string, data?: Record<string, unknown>) =>\n createLogger(component).debug(message, data),\n info: (component: string, message: string, data?: Record<string, unknown>) =>\n createLogger(component).info(message, data),\n warn: (component: string, message: string, data?: Record<string, unknown>) =>\n createLogger(component).warn(message, data),\n error: (component: string, message: string, data?: Record<string, unknown>) =>\n createLogger(component).error(message, data),\n success: (component: string, message: string, data?: Record<string, unknown>) =>\n createLogger(component).success(message, data),\n};\n"]}
|
package/dist/lib.mjs
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { clsx } from 'clsx';
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
import { consola } from 'consola';
|
|
4
|
+
import { create } from 'zustand';
|
|
5
|
+
|
|
6
|
+
var __defProp = Object.defineProperty;
|
|
7
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
8
|
+
function cn(...inputs) {
|
|
9
|
+
return twMerge(clsx(inputs));
|
|
10
|
+
}
|
|
11
|
+
__name(cn, "cn");
|
|
12
|
+
|
|
13
|
+
// src/lib/og-image.ts
|
|
14
|
+
var DEFAULT_OG_IMAGE_BASE_URL = "https://djangocfg.com/api/og";
|
|
15
|
+
function encodeBase64(str) {
|
|
16
|
+
if (typeof Buffer !== "undefined") {
|
|
17
|
+
return Buffer.from(str, "utf-8").toString("base64");
|
|
18
|
+
}
|
|
19
|
+
const utf8Bytes = new TextEncoder().encode(str);
|
|
20
|
+
const binaryString = Array.from(utf8Bytes, (byte) => String.fromCharCode(byte)).join("");
|
|
21
|
+
return btoa(binaryString);
|
|
22
|
+
}
|
|
23
|
+
__name(encodeBase64, "encodeBase64");
|
|
24
|
+
function generateOgImageUrl(params, options = {}) {
|
|
25
|
+
const { baseUrl = DEFAULT_OG_IMAGE_BASE_URL, useBase64 = true } = options;
|
|
26
|
+
if (useBase64) {
|
|
27
|
+
const cleanParams = {};
|
|
28
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
29
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
30
|
+
cleanParams[key] = value;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
const jsonString = JSON.stringify(cleanParams);
|
|
34
|
+
const base64Data = encodeBase64(jsonString);
|
|
35
|
+
return `${baseUrl}/${base64Data}`;
|
|
36
|
+
} else {
|
|
37
|
+
const searchParams = new URLSearchParams();
|
|
38
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
39
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
40
|
+
searchParams.append(key, String(value));
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
const query = searchParams.toString();
|
|
44
|
+
return query ? `${baseUrl}?${query}` : baseUrl;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
__name(generateOgImageUrl, "generateOgImageUrl");
|
|
48
|
+
function getAbsoluteOgImageUrl(relativePath, siteUrl) {
|
|
49
|
+
if (relativePath.startsWith("http://") || relativePath.startsWith("https://")) {
|
|
50
|
+
return relativePath;
|
|
51
|
+
}
|
|
52
|
+
const cleanSiteUrl = siteUrl.replace(/\/$/, "");
|
|
53
|
+
const cleanPath = relativePath.startsWith("/") ? relativePath : `/${relativePath}`;
|
|
54
|
+
return `${cleanSiteUrl}${cleanPath}`;
|
|
55
|
+
}
|
|
56
|
+
__name(getAbsoluteOgImageUrl, "getAbsoluteOgImageUrl");
|
|
57
|
+
function createOgImageUrlBuilder(defaults = {}, options = {}) {
|
|
58
|
+
return (params) => {
|
|
59
|
+
return generateOgImageUrl({ ...defaults, ...params }, options);
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
__name(createOgImageUrlBuilder, "createOgImageUrlBuilder");
|
|
63
|
+
var DEFAULT_FILTER = {
|
|
64
|
+
levels: ["debug", "info", "warn", "error", "success"],
|
|
65
|
+
component: void 0,
|
|
66
|
+
search: void 0,
|
|
67
|
+
since: void 0
|
|
68
|
+
};
|
|
69
|
+
var MAX_LOGS = 1e3;
|
|
70
|
+
function generateId() {
|
|
71
|
+
return `log-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
72
|
+
}
|
|
73
|
+
__name(generateId, "generateId");
|
|
74
|
+
function matchesFilter(entry, filter) {
|
|
75
|
+
if (!filter.levels.includes(entry.level)) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
if (filter.component) {
|
|
79
|
+
const comp = filter.component.toLowerCase();
|
|
80
|
+
if (!entry.component.toLowerCase().includes(comp)) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (filter.search) {
|
|
85
|
+
const search = filter.search.toLowerCase();
|
|
86
|
+
const inMessage = entry.message.toLowerCase().includes(search);
|
|
87
|
+
const inData = entry.data ? JSON.stringify(entry.data).toLowerCase().includes(search) : false;
|
|
88
|
+
if (!inMessage && !inData) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (filter.since && entry.timestamp < filter.since) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
__name(matchesFilter, "matchesFilter");
|
|
98
|
+
var useLogStore = create((set, get) => ({
|
|
99
|
+
logs: [],
|
|
100
|
+
filter: DEFAULT_FILTER,
|
|
101
|
+
maxLogs: MAX_LOGS,
|
|
102
|
+
addLog: /* @__PURE__ */ __name((entry) => {
|
|
103
|
+
const newEntry = {
|
|
104
|
+
...entry,
|
|
105
|
+
id: generateId(),
|
|
106
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
107
|
+
};
|
|
108
|
+
set((state) => {
|
|
109
|
+
const newLogs = [...state.logs, newEntry];
|
|
110
|
+
if (newLogs.length > state.maxLogs) {
|
|
111
|
+
return { logs: newLogs.slice(-state.maxLogs) };
|
|
112
|
+
}
|
|
113
|
+
return { logs: newLogs };
|
|
114
|
+
});
|
|
115
|
+
}, "addLog"),
|
|
116
|
+
clearLogs: /* @__PURE__ */ __name(() => {
|
|
117
|
+
set({ logs: [] });
|
|
118
|
+
}, "clearLogs"),
|
|
119
|
+
setFilter: /* @__PURE__ */ __name((filter) => {
|
|
120
|
+
set((state) => ({
|
|
121
|
+
filter: { ...state.filter, ...filter }
|
|
122
|
+
}));
|
|
123
|
+
}, "setFilter"),
|
|
124
|
+
resetFilter: /* @__PURE__ */ __name(() => {
|
|
125
|
+
set({ filter: DEFAULT_FILTER });
|
|
126
|
+
}, "resetFilter"),
|
|
127
|
+
getFilteredLogs: /* @__PURE__ */ __name(() => {
|
|
128
|
+
const { logs, filter } = get();
|
|
129
|
+
return logs.filter((entry) => matchesFilter(entry, filter));
|
|
130
|
+
}, "getFilteredLogs"),
|
|
131
|
+
exportLogs: /* @__PURE__ */ __name(() => {
|
|
132
|
+
const { logs } = get();
|
|
133
|
+
return JSON.stringify(logs, null, 2);
|
|
134
|
+
}, "exportLogs")
|
|
135
|
+
}));
|
|
136
|
+
var useFilteredLogs = /* @__PURE__ */ __name(() => {
|
|
137
|
+
const logs = useLogStore((state) => state.logs);
|
|
138
|
+
const filter = useLogStore((state) => state.filter);
|
|
139
|
+
return logs.filter((entry) => matchesFilter(entry, filter));
|
|
140
|
+
}, "useFilteredLogs");
|
|
141
|
+
var useLogCount = /* @__PURE__ */ __name(() => {
|
|
142
|
+
return useLogStore((state) => state.logs.length);
|
|
143
|
+
}, "useLogCount");
|
|
144
|
+
var useErrorCount = /* @__PURE__ */ __name(() => {
|
|
145
|
+
return useLogStore(
|
|
146
|
+
(state) => state.logs.filter((log2) => log2.level === "error").length
|
|
147
|
+
);
|
|
148
|
+
}, "useErrorCount");
|
|
149
|
+
var isBrowser = typeof window !== "undefined";
|
|
150
|
+
var baseConsola = consola.create({
|
|
151
|
+
level: 4
|
|
152
|
+
// 4 = debug, 2 = warn
|
|
153
|
+
});
|
|
154
|
+
function extractErrorData(data) {
|
|
155
|
+
if (!data) return { cleanData: void 0, stack: void 0 };
|
|
156
|
+
const cleanData = { ...data };
|
|
157
|
+
let stack;
|
|
158
|
+
if (data.error instanceof Error) {
|
|
159
|
+
stack = data.error.stack;
|
|
160
|
+
cleanData.error = {
|
|
161
|
+
name: data.error.name,
|
|
162
|
+
message: data.error.message
|
|
163
|
+
};
|
|
164
|
+
} else if (typeof data.error === "object" && data.error !== null) {
|
|
165
|
+
const errObj = data.error;
|
|
166
|
+
if (typeof errObj.stack === "string") {
|
|
167
|
+
stack = errObj.stack;
|
|
168
|
+
}
|
|
169
|
+
if (typeof errObj.message === "string") {
|
|
170
|
+
cleanData.error = errObj.message;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return { cleanData, stack };
|
|
174
|
+
}
|
|
175
|
+
__name(extractErrorData, "extractErrorData");
|
|
176
|
+
function formatBufferRanges(buffered, duration) {
|
|
177
|
+
if (buffered.length === 0) return "empty";
|
|
178
|
+
const ranges = [];
|
|
179
|
+
for (let i = 0; i < buffered.length; i++) {
|
|
180
|
+
const start = buffered.start(i);
|
|
181
|
+
const end = buffered.end(i);
|
|
182
|
+
const percent = ((end - start) / duration * 100).toFixed(1);
|
|
183
|
+
ranges.push(`${start.toFixed(1)}-${end.toFixed(1)}s (${percent}%)`);
|
|
184
|
+
}
|
|
185
|
+
return ranges.join(", ");
|
|
186
|
+
}
|
|
187
|
+
__name(formatBufferRanges, "formatBufferRanges");
|
|
188
|
+
function createLogger(component) {
|
|
189
|
+
const consolaTagged = baseConsola.withTag(component);
|
|
190
|
+
const log2 = /* @__PURE__ */ __name((level, message, data) => {
|
|
191
|
+
const { cleanData, stack } = extractErrorData(data);
|
|
192
|
+
if (isBrowser) {
|
|
193
|
+
useLogStore.getState().addLog({
|
|
194
|
+
level,
|
|
195
|
+
component,
|
|
196
|
+
message,
|
|
197
|
+
data: cleanData,
|
|
198
|
+
stack
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
{
|
|
202
|
+
const consolaMethod = level === "success" ? "success" : level;
|
|
203
|
+
if (cleanData) {
|
|
204
|
+
consolaTagged[consolaMethod](message, cleanData);
|
|
205
|
+
} else {
|
|
206
|
+
consolaTagged[consolaMethod](message);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}, "log");
|
|
210
|
+
return {
|
|
211
|
+
debug: /* @__PURE__ */ __name((message, data) => log2("debug", message, data), "debug"),
|
|
212
|
+
info: /* @__PURE__ */ __name((message, data) => log2("info", message, data), "info"),
|
|
213
|
+
warn: /* @__PURE__ */ __name((message, data) => log2("warn", message, data), "warn"),
|
|
214
|
+
error: /* @__PURE__ */ __name((message, data) => log2("error", message, data), "error"),
|
|
215
|
+
success: /* @__PURE__ */ __name((message, data) => log2("success", message, data), "success")
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
__name(createLogger, "createLogger");
|
|
219
|
+
function createMediaLogger(component) {
|
|
220
|
+
const baseLogger = createLogger(component);
|
|
221
|
+
return {
|
|
222
|
+
...baseLogger,
|
|
223
|
+
load: /* @__PURE__ */ __name((src, type) => {
|
|
224
|
+
const typeStr = type ? ` (${type})` : "";
|
|
225
|
+
baseLogger.info(`LOAD: ${src}${typeStr}`);
|
|
226
|
+
}, "load"),
|
|
227
|
+
state: /* @__PURE__ */ __name((state, details) => {
|
|
228
|
+
baseLogger.debug(`STATE: ${state}`, details);
|
|
229
|
+
}, "state"),
|
|
230
|
+
seek: /* @__PURE__ */ __name((from, to, duration) => {
|
|
231
|
+
baseLogger.debug(`SEEK: ${from.toFixed(2)}s -> ${to.toFixed(2)}s`, {
|
|
232
|
+
from,
|
|
233
|
+
to,
|
|
234
|
+
duration,
|
|
235
|
+
progress: `${(to / duration * 100).toFixed(1)}%`
|
|
236
|
+
});
|
|
237
|
+
}, "seek"),
|
|
238
|
+
buffer: /* @__PURE__ */ __name((buffered, duration) => {
|
|
239
|
+
if (buffered.length > 0) {
|
|
240
|
+
baseLogger.debug(`BUFFER: ${formatBufferRanges(buffered, duration)}`);
|
|
241
|
+
}
|
|
242
|
+
}, "buffer"),
|
|
243
|
+
event: /* @__PURE__ */ __name((name, data) => {
|
|
244
|
+
if (data !== void 0) {
|
|
245
|
+
baseLogger.debug(`EVENT: ${name}`, { data });
|
|
246
|
+
} else {
|
|
247
|
+
baseLogger.debug(`EVENT: ${name}`);
|
|
248
|
+
}
|
|
249
|
+
}, "event")
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
__name(createMediaLogger, "createMediaLogger");
|
|
253
|
+
var logger = createLogger("App");
|
|
254
|
+
var log = {
|
|
255
|
+
debug: /* @__PURE__ */ __name((component, message, data) => createLogger(component).debug(message, data), "debug"),
|
|
256
|
+
info: /* @__PURE__ */ __name((component, message, data) => createLogger(component).info(message, data), "info"),
|
|
257
|
+
warn: /* @__PURE__ */ __name((component, message, data) => createLogger(component).warn(message, data), "warn"),
|
|
258
|
+
error: /* @__PURE__ */ __name((component, message, data) => createLogger(component).error(message, data), "error"),
|
|
259
|
+
success: /* @__PURE__ */ __name((component, message, data) => createLogger(component).success(message, data), "success")
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
export { cn, createLogger, createMediaLogger, createOgImageUrlBuilder, generateOgImageUrl, getAbsoluteOgImageUrl, log, logger, useErrorCount, useFilteredLogs, useLogCount, useLogStore };
|
|
263
|
+
//# sourceMappingURL=lib.mjs.map
|
|
264
|
+
//# sourceMappingURL=lib.mjs.map
|
package/dist/lib.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/lib/og-image.ts","../src/lib/logger/logStore.ts","../src/lib/logger/logger.ts"],"names":["log"],"mappings":"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","file":"lib.mjs","sourcesContent":["import { ClassValue, clsx} from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","/**\n * OG Image URL Generation Utilities\n *\n * Client-side utilities for generating OG image URLs.\n */\n\n/** Default OG Image API base URL */\nconst DEFAULT_OG_IMAGE_BASE_URL = 'https://djangocfg.com/api/og';\n\n/**\n * Encode string to base64 with Unicode support\n * Works in both browser and Node.js environments\n */\nfunction encodeBase64(str: string): string {\n // Node.js environment\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(str, 'utf-8').toString('base64');\n }\n // Browser environment - handle Unicode via UTF-8 encoding\n const utf8Bytes = new TextEncoder().encode(str);\n const binaryString = Array.from(utf8Bytes, byte => String.fromCharCode(byte)).join('');\n return btoa(binaryString);\n}\n\n/**\n * OG Image URL parameters\n */\nexport interface OgImageUrlParams {\n /** Page title */\n title: string;\n /** Page description (optional) */\n description?: string;\n /** Site name (optional) */\n siteName?: string;\n /** Logo URL (optional) */\n logo?: string;\n /** Background type: 'gradient' or 'solid' */\n backgroundType?: 'gradient' | 'solid';\n /** Gradient start color (hex) */\n gradientStart?: string;\n /** Gradient end color (hex) */\n gradientEnd?: string;\n /** Background color (for solid type) */\n backgroundColor?: string;\n /** Title font size (px) */\n titleSize?: number;\n /** Title font weight */\n titleWeight?: number;\n /** Title text color */\n titleColor?: string;\n /** Description font size (px) */\n descriptionSize?: number;\n /** Description text color */\n descriptionColor?: string;\n /** Site name font size (px) */\n siteNameSize?: number;\n /** Site name text color */\n siteNameColor?: string;\n /** Padding (px) */\n padding?: number;\n /** Logo size (px) */\n logoSize?: number;\n /** Show logo flag */\n showLogo?: boolean;\n /** Show site name flag */\n showSiteName?: boolean;\n /** Additional custom parameters */\n [key: string]: string | number | boolean | undefined;\n}\n\n/**\n * Options for generating OG image URL\n */\nexport interface GenerateOgImageUrlOptions {\n /**\n * Base URL of the OG image API route\n * @default 'https://djangocfg.com/api/og'\n */\n baseUrl?: string;\n /**\n * If true, encode params as base64 for safer URLs\n * @default true\n */\n useBase64?: boolean;\n}\n\n/**\n * Generate OG image URL with query parameters or base64 encoding\n *\n * @example\n * ```typescript\n * // Using default baseUrl (https://djangocfg.com/api/og)\n * const url = generateOgImageUrl({ title: 'My Page Title' });\n *\n * // With custom baseUrl\n * const url = generateOgImageUrl({ title: 'My Page' }, { baseUrl: '/api/og' });\n * ```\n */\nexport function generateOgImageUrl(\n params: OgImageUrlParams,\n options: GenerateOgImageUrlOptions = {}\n): string {\n const { baseUrl = DEFAULT_OG_IMAGE_BASE_URL, useBase64 = true } = options;\n\n if (useBase64) {\n const cleanParams: Record<string, string | number | boolean> = {};\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined && value !== null && value !== '') {\n cleanParams[key] = value;\n }\n });\n\n const jsonString = JSON.stringify(cleanParams);\n const base64Data = encodeBase64(jsonString);\n return `${baseUrl}/${base64Data}`;\n } else {\n const searchParams = new URLSearchParams();\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined && value !== null && value !== '') {\n searchParams.append(key, String(value));\n }\n });\n const query = searchParams.toString();\n return query ? `${baseUrl}?${query}` : baseUrl;\n }\n}\n\n/**\n * Get absolute OG image URL from relative path\n */\nexport function getAbsoluteOgImageUrl(relativePath: string, siteUrl: string): string {\n // If path is already an absolute URL, return as-is\n if (relativePath.startsWith('http://') || relativePath.startsWith('https://')) {\n return relativePath;\n }\n const cleanSiteUrl = siteUrl.replace(/\\/$/, '');\n const cleanPath = relativePath.startsWith('/') ? relativePath : `/${relativePath}`;\n return `${cleanSiteUrl}${cleanPath}`;\n}\n\n/**\n * Create OG image URL builder with preset configuration\n */\nexport function createOgImageUrlBuilder(\n defaults: Partial<OgImageUrlParams> = {},\n options: GenerateOgImageUrlOptions = {}\n) {\n return (params: OgImageUrlParams): string => {\n return generateOgImageUrl({ ...defaults, ...params }, options);\n };\n}\n","/**\n * Log Store\n *\n * Zustand store for log accumulation and filtering.\n * Keeps logs in memory for Console panel display.\n */\n\n'use client';\n\nimport { create } from 'zustand';\nimport type { LogStore, LogEntry, LogFilter } from './types';\n\nconst DEFAULT_FILTER: LogFilter = {\n levels: ['debug', 'info', 'warn', 'error', 'success'],\n component: undefined,\n search: undefined,\n since: undefined,\n};\n\nconst MAX_LOGS = 1000;\n\nfunction generateId(): string {\n return `log-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;\n}\n\nfunction matchesFilter(entry: LogEntry, filter: LogFilter): boolean {\n // Level filter\n if (!filter.levels.includes(entry.level)) {\n return false;\n }\n\n // Component filter (case-insensitive partial match)\n if (filter.component) {\n const comp = filter.component.toLowerCase();\n if (!entry.component.toLowerCase().includes(comp)) {\n return false;\n }\n }\n\n // Search filter (case-insensitive, searches message and data)\n if (filter.search) {\n const search = filter.search.toLowerCase();\n const inMessage = entry.message.toLowerCase().includes(search);\n const inData = entry.data\n ? JSON.stringify(entry.data).toLowerCase().includes(search)\n : false;\n if (!inMessage && !inData) {\n return false;\n }\n }\n\n // Time filter\n if (filter.since && entry.timestamp < filter.since) {\n return false;\n }\n\n return true;\n}\n\nexport const useLogStore = create<LogStore>((set, get) => ({\n logs: [],\n filter: DEFAULT_FILTER,\n maxLogs: MAX_LOGS,\n\n addLog: (entry) => {\n const newEntry: LogEntry = {\n ...entry,\n id: generateId(),\n timestamp: new Date(),\n };\n\n set((state) => {\n const newLogs = [...state.logs, newEntry];\n // Trim to max size\n if (newLogs.length > state.maxLogs) {\n return { logs: newLogs.slice(-state.maxLogs) };\n }\n return { logs: newLogs };\n });\n },\n\n clearLogs: () => {\n set({ logs: [] });\n },\n\n setFilter: (filter) => {\n set((state) => ({\n filter: { ...state.filter, ...filter },\n }));\n },\n\n resetFilter: () => {\n set({ filter: DEFAULT_FILTER });\n },\n\n getFilteredLogs: () => {\n const { logs, filter } = get();\n return logs.filter((entry) => matchesFilter(entry, filter));\n },\n\n exportLogs: () => {\n const { logs } = get();\n return JSON.stringify(logs, null, 2);\n },\n}));\n\n// Selector hooks for performance\nexport const useFilteredLogs = () => {\n const logs = useLogStore((state) => state.logs);\n const filter = useLogStore((state) => state.filter);\n return logs.filter((entry) => matchesFilter(entry, filter));\n};\n\nexport const useLogCount = () => {\n return useLogStore((state) => state.logs.length);\n};\n\nexport const useErrorCount = () => {\n return useLogStore((state) =>\n state.logs.filter((log) => log.level === 'error').length\n );\n};\n","/**\n * Logger\n *\n * Universal logger with consola + zustand store integration.\n * Logs are accumulated for Console panel display.\n * In production, only logs to store (no console output).\n */\n\n'use client';\n\nimport { consola, type ConsolaInstance } from 'consola';\nimport { useLogStore } from './logStore';\nimport type { Logger, LogLevel, MediaLogger } from './types';\n\n// Check environment\nconst isDev = process.env.NODE_ENV !== 'production';\nconst isBrowser = typeof window !== 'undefined';\n\n// Create base consola instance\nconst baseConsola = consola.create({\n level: isDev ? 4 : 2, // 4 = debug, 2 = warn\n});\n\n/**\n * Extract error details from unknown error type\n */\nfunction extractErrorData(data?: Record<string, unknown>): {\n cleanData: Record<string, unknown> | undefined;\n stack: string | undefined;\n} {\n if (!data) return { cleanData: undefined, stack: undefined };\n\n const cleanData = { ...data };\n let stack: string | undefined;\n\n // Extract stack from error object\n if (data.error instanceof Error) {\n stack = data.error.stack;\n cleanData.error = {\n name: data.error.name,\n message: data.error.message,\n };\n } else if (typeof data.error === 'object' && data.error !== null) {\n const errObj = data.error as Record<string, unknown>;\n if (typeof errObj.stack === 'string') {\n stack = errObj.stack;\n }\n if (typeof errObj.message === 'string') {\n cleanData.error = errObj.message;\n }\n }\n\n return { cleanData, stack };\n}\n\n/**\n * Format buffer ranges for logging\n */\nfunction formatBufferRanges(buffered: TimeRanges, duration: number): string {\n if (buffered.length === 0) return 'empty';\n\n const ranges: string[] = [];\n for (let i = 0; i < buffered.length; i++) {\n const start = buffered.start(i);\n const end = buffered.end(i);\n const percent = ((end - start) / duration * 100).toFixed(1);\n ranges.push(`${start.toFixed(1)}-${end.toFixed(1)}s (${percent}%)`);\n }\n return ranges.join(', ');\n}\n\n/**\n * Create a logger for a specific component/module\n */\nexport function createLogger(component: string): Logger {\n const consolaTagged = baseConsola.withTag(component);\n\n const log = (level: LogLevel, message: string, data?: Record<string, unknown>) => {\n const { cleanData, stack } = extractErrorData(data);\n\n // Add to store (for Console panel)\n if (isBrowser) {\n useLogStore.getState().addLog({\n level,\n component,\n message,\n data: cleanData,\n stack,\n });\n }\n\n // Log to console via consola (in dev mode)\n if (isDev) {\n const consolaMethod = level === 'success' ? 'success' : level;\n if (cleanData) {\n consolaTagged[consolaMethod](message, cleanData);\n } else {\n consolaTagged[consolaMethod](message);\n }\n }\n };\n\n return {\n debug: (message, data) => log('debug', message, data),\n info: (message, data) => log('info', message, data),\n warn: (message, data) => log('warn', message, data),\n error: (message, data) => log('error', message, data),\n success: (message, data) => log('success', message, data),\n };\n}\n\n/**\n * Create a media-specific logger with helper methods\n * for AudioPlayer, VideoPlayer, ImageViewer\n */\nexport function createMediaLogger(component: string): MediaLogger {\n const baseLogger = createLogger(component);\n\n return {\n ...baseLogger,\n\n load: (src: string, type?: string) => {\n const typeStr = type ? ` (${type})` : '';\n baseLogger.info(`LOAD: ${src}${typeStr}`);\n },\n\n state: (state: string, details?: Record<string, unknown>) => {\n baseLogger.debug(`STATE: ${state}`, details);\n },\n\n seek: (from: number, to: number, duration: number) => {\n baseLogger.debug(`SEEK: ${from.toFixed(2)}s -> ${to.toFixed(2)}s`, {\n from,\n to,\n duration,\n progress: `${((to / duration) * 100).toFixed(1)}%`,\n });\n },\n\n buffer: (buffered: TimeRanges, duration: number) => {\n if (buffered.length > 0) {\n baseLogger.debug(`BUFFER: ${formatBufferRanges(buffered, duration)}`);\n }\n },\n\n event: (name: string, data?: unknown) => {\n if (data !== undefined) {\n baseLogger.debug(`EVENT: ${name}`, { data });\n } else {\n baseLogger.debug(`EVENT: ${name}`);\n }\n },\n };\n}\n\n/**\n * Global logger for non-component code\n */\nexport const logger = createLogger('App');\n\n/**\n * Quick access for one-off logs\n */\nexport const log = {\n debug: (component: string, message: string, data?: Record<string, unknown>) =>\n createLogger(component).debug(message, data),\n info: (component: string, message: string, data?: Record<string, unknown>) =>\n createLogger(component).info(message, data),\n warn: (component: string, message: string, data?: Record<string, unknown>) =>\n createLogger(component).warn(message, data),\n error: (component: string, message: string, data?: Record<string, unknown>) =>\n createLogger(component).error(message, data),\n success: (component: string, message: string, data?: Record<string, unknown>) =>\n createLogger(component).success(message, data),\n};\n"]}
|