@jhits/plugin-telemetry 0.0.4 → 0.0.6

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.
@@ -0,0 +1,55 @@
1
+ import 'server-only';
2
+ /**
3
+ * Server-only exports for @jhits/plugin-telemetry
4
+ * These exports should only be used in server-side code (API routes, server components)
5
+ */
6
+ interface PluginRegistration {
7
+ name: string;
8
+ version: string;
9
+ description?: string;
10
+ routes: Array<{
11
+ path: string;
12
+ component: string;
13
+ }>;
14
+ apiHandlers: Array<{
15
+ method: string;
16
+ path: string;
17
+ handler: string;
18
+ }>;
19
+ cssFiles: string[];
20
+ setup?: () => Promise<void>;
21
+ dependencies?: string[];
22
+ config?: Record<string, any>;
23
+ }
24
+ import { NextRequest, NextResponse } from 'next/server';
25
+ /**
26
+ * Main API handler for telemetry plugin
27
+ */
28
+ export declare function handleApi(req: NextRequest, path: string[], config: any): Promise<NextResponse>;
29
+ /**
30
+ * Plugin registration for auto-configuration
31
+ */
32
+ export declare function registerPlugin(): Promise<PluginRegistration>;
33
+ /**
34
+ * API handler for retrieving logs
35
+ */
36
+ export declare function getLogsHandler(req: NextRequest, path: string[], config: any): Promise<NextResponse>;
37
+ /**
38
+ * Telemetry Handler
39
+ * Server-only function for processing telemetry data
40
+ *
41
+ * @param data - Telemetry entry or array of entries
42
+ * @param context - Optional context with userId and sessionId
43
+ * @returns Result object with success status and logging information
44
+ */
45
+ export declare function telemetryHandler(data: any, context?: {
46
+ userId?: string;
47
+ sessionId?: string;
48
+ }): Promise<{
49
+ success: boolean;
50
+ logged?: number;
51
+ rejected?: number;
52
+ error?: string;
53
+ }>;
54
+ export {};
55
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AAErB;;;GAGG;AAGH,UAAU,kBAAkB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,WAAW,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC9B;AAED,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAoExD;;GAEG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE,MAAM,EAAE,EACd,MAAM,EAAE,GAAG,GACV,OAAO,CAAC,YAAY,CAAC,CA8BvB;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAyClE;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE,MAAM,EAAE,EACd,MAAM,EAAE,GAAG,GACV,OAAO,CAAC,YAAY,CAAC,CAkCvB;AA8FD;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAClC,IAAI,EAAE,GAAG,EACT,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAClD,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA2DnF"}
package/dist/server.js ADDED
@@ -0,0 +1,313 @@
1
+ import 'server-only';
2
+ import { NextResponse } from 'next/server';
3
+ import fs from 'fs/promises';
4
+ import path from 'path';
5
+ const LOG_DIR = path.join(process.cwd(), 'logs');
6
+ const LOG_FILE = path.join(LOG_DIR, 'jhits-system.log');
7
+ const OLD_LOG_FILE = path.join(LOG_DIR, 'jhits-system.old.log');
8
+ const MAX_LOG_SIZE = 10 * 1024 * 1024; // 10MB
9
+ const MAX_BATCH_SIZE = 100; // Maximum entries per request
10
+ const MAX_ENTRY_SIZE = 100 * 1024; // 100KB per entry
11
+ /**
12
+ * Ensure logs directory exists
13
+ */
14
+ async function ensureLogDir() {
15
+ try {
16
+ await fs.access(LOG_DIR);
17
+ }
18
+ catch {
19
+ await fs.mkdir(LOG_DIR, { recursive: true });
20
+ }
21
+ }
22
+ /**
23
+ * Check log file size and rotate if necessary
24
+ */
25
+ async function rotateLogIfNeeded() {
26
+ try {
27
+ const stats = await fs.stat(LOG_FILE);
28
+ if (stats.size > MAX_LOG_SIZE) {
29
+ // Rename current log to old log
30
+ try {
31
+ await fs.rename(LOG_FILE, OLD_LOG_FILE);
32
+ }
33
+ catch (error) {
34
+ // If old log exists, remove it first
35
+ if (error.code === 'EEXIST' || error.code === 'ENOENT') {
36
+ try {
37
+ await fs.unlink(OLD_LOG_FILE);
38
+ await fs.rename(LOG_FILE, OLD_LOG_FILE);
39
+ }
40
+ catch {
41
+ // If still fails, just overwrite
42
+ await fs.copyFile(LOG_FILE, OLD_LOG_FILE);
43
+ await fs.unlink(LOG_FILE);
44
+ }
45
+ }
46
+ else {
47
+ throw error;
48
+ }
49
+ }
50
+ }
51
+ }
52
+ catch (error) {
53
+ // If file doesn't exist, that's fine - we'll create it
54
+ if (error.code !== 'ENOENT') {
55
+ console.error('[Telemetry Handler] Error checking log size:', error);
56
+ }
57
+ }
58
+ }
59
+ /**
60
+ * Main API handler for telemetry plugin
61
+ */
62
+ export async function handleApi(req, path, config) {
63
+ try {
64
+ const { searchParams } = new URL(req.url);
65
+ const action = path[0] || 'log';
66
+ switch (action) {
67
+ case 'log':
68
+ const data = await req.json();
69
+ const result = await telemetryHandler(data, {
70
+ userId: req.headers.get('x-user-id') || undefined,
71
+ sessionId: req.headers.get('x-session-id') || undefined
72
+ });
73
+ return NextResponse.json(result);
74
+ case 'logs':
75
+ return await getLogsHandler(req, path, config);
76
+ default:
77
+ return NextResponse.json({
78
+ success: false,
79
+ error: 'Unknown telemetry action'
80
+ }, { status: 404 });
81
+ }
82
+ }
83
+ catch (error) {
84
+ console.error('[Telemetry API] Error:', error);
85
+ return NextResponse.json({
86
+ success: false,
87
+ error: 'Internal server error'
88
+ }, { status: 500 });
89
+ }
90
+ }
91
+ /**
92
+ * Plugin registration for auto-configuration
93
+ */
94
+ export async function registerPlugin() {
95
+ return {
96
+ name: 'telemetry',
97
+ version: '0.0.1',
98
+ description: 'System telemetry and logging plugin',
99
+ routes: [
100
+ {
101
+ path: '/dashboard/telemetry',
102
+ component: 'TelemetryDashboard'
103
+ }
104
+ ],
105
+ apiHandlers: [
106
+ {
107
+ method: 'POST',
108
+ path: '/log',
109
+ handler: 'telemetryHandler'
110
+ },
111
+ {
112
+ method: 'GET',
113
+ path: '/logs',
114
+ handler: 'getLogsHandler'
115
+ }
116
+ ],
117
+ cssFiles: ['telemetry-styles.css'],
118
+ setup: async () => {
119
+ // Create logs directory
120
+ const { mkdir } = await import('fs/promises');
121
+ const { join } = await import('path');
122
+ try {
123
+ await mkdir(join(process.cwd(), 'logs'), { recursive: true });
124
+ }
125
+ catch (error) {
126
+ // Directory might already exist
127
+ }
128
+ },
129
+ dependencies: [],
130
+ config: {
131
+ maxLogSize: 10 * 1024 * 1024, // 10MB
132
+ maxBatchSize: 100,
133
+ maxEntrySize: 100 * 1024 // 100KB
134
+ }
135
+ };
136
+ }
137
+ /**
138
+ * API handler for retrieving logs
139
+ */
140
+ export async function getLogsHandler(req, path, config) {
141
+ try {
142
+ const fs = await import('fs/promises');
143
+ const path = await import('path');
144
+ const LOG_FILE = path.join(process.cwd(), 'logs', 'jhits-system.log');
145
+ const { searchParams } = new URL(req.url);
146
+ const lines = parseInt(searchParams.get('lines') || '100');
147
+ const category = searchParams.get('category');
148
+ // Read log file
149
+ const logContent = await fs.readFile(LOG_FILE, 'utf8');
150
+ const logLines = logContent.split('\n').filter(line => line.trim());
151
+ // Filter by category if specified
152
+ const filteredLines = category
153
+ ? logLines.filter(line => line.includes(`[${category}]`))
154
+ : logLines;
155
+ // Get last N lines
156
+ const recentLines = filteredLines.slice(-lines);
157
+ return NextResponse.json({
158
+ success: true,
159
+ logs: recentLines,
160
+ total: filteredLines.length
161
+ });
162
+ }
163
+ catch (error) {
164
+ return NextResponse.json({
165
+ success: false,
166
+ error: 'Failed to read logs',
167
+ logs: []
168
+ }, { status: 500 });
169
+ }
170
+ }
171
+ /**
172
+ * Format log entry as single-line JSON (or pretty-printed in debug mode)
173
+ * CRITICAL: Single-line format for easier grep/tailing, but pretty-printed if debug flag is on
174
+ */
175
+ function formatLogEntry(entry, debug = false) {
176
+ const timestamp = new Date(entry.timestamp).toISOString();
177
+ const context = entry.context || 'unknown';
178
+ const userId = entry.userId || 'anonymous';
179
+ const sessionId = entry.sessionId || 'unknown';
180
+ // Check for debug mode via environment variable
181
+ const isDebugMode = debug || process.env.TELEMETRY_DEBUG === 'true';
182
+ if (isDebugMode) {
183
+ // Pretty-printed format for debugging
184
+ const logObject = {
185
+ timestamp,
186
+ context,
187
+ userId,
188
+ sessionId,
189
+ category: entry.category,
190
+ message: entry.message,
191
+ data: entry.data,
192
+ ...(entry.stack && { stack: entry.stack })
193
+ };
194
+ return JSON.stringify(logObject, null, 2) + '\n';
195
+ }
196
+ else {
197
+ // Single-line JSON format for production (easier grep/tailing)
198
+ const sanitizedData = typeof entry.data === 'object'
199
+ ? JSON.stringify(entry.data).replace(/\n/g, '\\n').replace(/\r/g, '\\r')
200
+ : String(entry.data);
201
+ const stackStr = entry.stack ? ` "stack":"${entry.stack.replace(/"/g, '\\"').replace(/\n/g, '\\n')}"` : '';
202
+ return `[${timestamp}] [${context}] [${userId}] [${sessionId}] [${entry.category}] ${entry.message} ${sanitizedData}${stackStr}\n`;
203
+ }
204
+ }
205
+ /**
206
+ * Validate and sanitize telemetry entry
207
+ */
208
+ function validateEntry(entry) {
209
+ // Basic validation
210
+ if (!entry || typeof entry !== 'object') {
211
+ return null;
212
+ }
213
+ // Check required fields
214
+ if (!entry.id || !entry.timestamp || !entry.category || !entry.message) {
215
+ return null;
216
+ }
217
+ // Size check to prevent log injection attacks
218
+ const entrySize = JSON.stringify(entry).length;
219
+ if (entrySize > MAX_ENTRY_SIZE) {
220
+ console.warn('[Telemetry Handler] Entry too large, skipping:', entry.id);
221
+ return null;
222
+ }
223
+ // Sanitize string fields
224
+ return {
225
+ id: String(entry.id).substring(0, 100),
226
+ timestamp: Number(entry.timestamp),
227
+ category: String(entry.category).substring(0, 50),
228
+ message: String(entry.message).substring(0, 500),
229
+ data: entry.data || {},
230
+ stack: entry.stack ? String(entry.stack).substring(0, 5000) : undefined,
231
+ context: entry.context ? String(entry.context).substring(0, 100) : undefined,
232
+ userId: entry.userId ? String(entry.userId).substring(0, 100) : undefined,
233
+ sessionId: entry.sessionId ? String(entry.sessionId).substring(0, 100) : undefined,
234
+ };
235
+ }
236
+ /**
237
+ * Extract user/session info from request headers or cookies
238
+ */
239
+ function extractContext(request) {
240
+ // Try to get user ID from headers (custom header)
241
+ const userId = request.headers.get('x-user-id') ||
242
+ request.headers.get('x-userid') ||
243
+ undefined;
244
+ // Try to get session ID from headers or cookies
245
+ const sessionId = request.headers.get('x-session-id') ||
246
+ request.headers.get('x-sessionid') ||
247
+ request.cookies.get('sessionId')?.value ||
248
+ request.cookies.get('session')?.value ||
249
+ undefined;
250
+ return { userId, sessionId };
251
+ }
252
+ /**
253
+ * Telemetry Handler
254
+ * Server-only function for processing telemetry data
255
+ *
256
+ * @param data - Telemetry entry or array of entries
257
+ * @param context - Optional context with userId and sessionId
258
+ * @returns Result object with success status and logging information
259
+ */
260
+ export async function telemetryHandler(data, context) {
261
+ try {
262
+ // Ensure log directory exists
263
+ await ensureLogDir();
264
+ // Rotate log if needed
265
+ await rotateLogIfNeeded();
266
+ // Handle single entry or batch of entries
267
+ const entries = Array.isArray(data) ? data : [data];
268
+ // Rate limiting: Check batch size
269
+ if (entries.length > MAX_BATCH_SIZE) {
270
+ return {
271
+ success: false,
272
+ error: `Batch size exceeds maximum of ${MAX_BATCH_SIZE}`
273
+ };
274
+ }
275
+ // Validate and sanitize entries
276
+ const validEntries = [];
277
+ for (const entry of entries) {
278
+ const validated = validateEntry(entry);
279
+ if (validated) {
280
+ // Add context if provided
281
+ if (context?.userId && !validated.userId) {
282
+ validated.userId = context.userId;
283
+ }
284
+ if (context?.sessionId && !validated.sessionId) {
285
+ validated.sessionId = context.sessionId;
286
+ }
287
+ validEntries.push(validated);
288
+ }
289
+ }
290
+ if (validEntries.length === 0) {
291
+ return {
292
+ success: false,
293
+ error: 'No valid entries to log'
294
+ };
295
+ }
296
+ // Format and append each entry (check for debug mode)
297
+ const debugMode = process.env.TELEMETRY_DEBUG === 'true';
298
+ const logLines = validEntries.map(entry => formatLogEntry(entry, debugMode)).join('');
299
+ await fs.appendFile(LOG_FILE, logLines, 'utf8');
300
+ return {
301
+ success: true,
302
+ logged: validEntries.length,
303
+ rejected: entries.length - validEntries.length
304
+ };
305
+ }
306
+ catch (error) {
307
+ console.error('[Telemetry Handler] Error writing log:', error);
308
+ return {
309
+ success: false,
310
+ error: 'Failed to write log',
311
+ };
312
+ }
313
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Telemetry Types
3
+ * Type definitions for the telemetry system
4
+ */
5
+ export type TelemetryCategory = 'DRAG_DROP' | 'STATE' | 'ERROR' | 'UI';
6
+ export interface TelemetryEntry {
7
+ id: string;
8
+ timestamp: number;
9
+ category: TelemetryCategory;
10
+ message: string;
11
+ data: any;
12
+ stack?: string;
13
+ context?: string;
14
+ userId?: string;
15
+ sessionId?: string;
16
+ }
17
+ export interface TelemetryService {
18
+ log: (category: TelemetryCategory, message: string, data?: any, context?: string) => void;
19
+ error: (message: string, error: Error | unknown, data?: any, context?: string) => void;
20
+ exportLogs: () => void;
21
+ clearLogs: () => void;
22
+ getLogs: () => TelemetryEntry[];
23
+ flush: () => Promise<void>;
24
+ setContext: (context: string) => void;
25
+ }
26
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,OAAO,GAAG,OAAO,GAAG,IAAI,CAAC;AAEvE,MAAM,WAAW,cAAc;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,GAAG,CAAC;IACV,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC7B,GAAG,EAAE,CAAC,QAAQ,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1F,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACvF,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,cAAc,EAAE,CAAC;IAChC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC"}
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Telemetry Types
3
+ * Type definitions for the telemetry system
4
+ */
5
+ export {};
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Log Cleaner Utilities
3
+ * Optimizes telemetry payloads by summarizing large data structures
4
+ */
5
+ interface BlockLike {
6
+ id: string | number;
7
+ type?: string;
8
+ nestedBlocks?: BlockLike[];
9
+ }
10
+ /**
11
+ * Summarized block representation for telemetry
12
+ */
13
+ export interface BlockSummary {
14
+ id: string;
15
+ type: string;
16
+ childCount: number;
17
+ }
18
+ /**
19
+ * Summarize a single block to reduce log payload size
20
+ * Only includes essential information: id, type, and child count
21
+ */
22
+ export declare function summarizeBlock(block: BlockLike | {
23
+ id: string;
24
+ type: string;
25
+ nestedBlocks?: any[];
26
+ }): BlockSummary;
27
+ /**
28
+ * Summarize an array of blocks to reduce log payload size
29
+ * Recursively summarizes nested blocks up to a maximum depth
30
+ */
31
+ export declare function summarizeBlocks(blocks: BlockLike[] | undefined, maxDepth?: number): BlockSummary[];
32
+ /**
33
+ * Extract action-specific data for telemetry
34
+ */
35
+ export interface MoveBlockData {
36
+ blockId: string;
37
+ fromParent: string | null;
38
+ toParent: string | null;
39
+ fromIndex?: number;
40
+ toIndex: number;
41
+ }
42
+ export interface DeleteBlockData {
43
+ blockId: string;
44
+ blockType: string;
45
+ parentId: string | null;
46
+ }
47
+ export interface InsertBlockData {
48
+ newBlockType: string;
49
+ parentId: string | null;
50
+ index: number;
51
+ newBlockId?: string;
52
+ }
53
+ /**
54
+ * Create optimized telemetry payload for block operations
55
+ * Removes full block arrays and only includes essential action data
56
+ */
57
+ export declare function createBlockActionPayload(actionType: 'MOVE_BLOCK' | 'DELETE_BLOCK' | 'INSERT_BLOCK', data: MoveBlockData | DeleteBlockData | InsertBlockData, options?: {
58
+ includeBlocks?: boolean;
59
+ affectedBlockId?: string;
60
+ }): Record<string, any>;
61
+ export {};
62
+ //# sourceMappingURL=logCleaner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logCleaner.d.ts","sourceRoot":"","sources":["../../src/utils/logCleaner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,UAAU,SAAS;IACf,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,SAAS,EAAE,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,GAAG,EAAE,CAAA;CAAE,GAAG,YAAY,CAMlH;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC3B,MAAM,EAAE,SAAS,EAAE,GAAG,SAAS,EAC/B,QAAQ,GAAE,MAAU,GACrB,YAAY,EAAE,CAoBhB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACpC,UAAU,EAAE,YAAY,GAAG,cAAc,GAAG,cAAc,EAC1D,IAAI,EAAE,aAAa,GAAG,eAAe,GAAG,eAAe,EACvD,OAAO,CAAC,EAAE;IACN,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B,GACF,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAYrB"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Log Cleaner Utilities
3
+ * Optimizes telemetry payloads by summarizing large data structures
4
+ */
5
+ /**
6
+ * Summarize a single block to reduce log payload size
7
+ * Only includes essential information: id, type, and child count
8
+ */
9
+ export function summarizeBlock(block) {
10
+ return {
11
+ id: String(block.id),
12
+ type: String(block.type || 'unknown'),
13
+ childCount: Array.isArray(block.nestedBlocks) ? block.nestedBlocks.length : 0
14
+ };
15
+ }
16
+ /**
17
+ * Summarize an array of blocks to reduce log payload size
18
+ * Recursively summarizes nested blocks up to a maximum depth
19
+ */
20
+ export function summarizeBlocks(blocks, maxDepth = 2) {
21
+ if (!Array.isArray(blocks) || blocks.length === 0) {
22
+ return [];
23
+ }
24
+ return blocks.map(block => {
25
+ const summary = {
26
+ id: String(block.id),
27
+ type: String(block.type || 'unknown'),
28
+ childCount: Array.isArray(block.nestedBlocks) ? block.nestedBlocks.length : 0
29
+ };
30
+ // Optionally include nested summaries if depth allows (for debugging)
31
+ if (maxDepth > 0 && block.nestedBlocks && block.nestedBlocks.length > 0) {
32
+ // Only include nested summaries in debug mode
33
+ // For production, just the childCount is sufficient
34
+ }
35
+ return summary;
36
+ });
37
+ }
38
+ /**
39
+ * Create optimized telemetry payload for block operations
40
+ * Removes full block arrays and only includes essential action data
41
+ */
42
+ export function createBlockActionPayload(actionType, data, options) {
43
+ const payload = {
44
+ actionType,
45
+ ...data
46
+ };
47
+ // Only include full blocks for critical errors
48
+ if (options?.includeBlocks && options.affectedBlockId) {
49
+ payload.affectedBlockId = options.affectedBlockId;
50
+ }
51
+ return payload;
52
+ }
package/package.json CHANGED
@@ -1,37 +1,39 @@
1
1
  {
2
2
  "name": "@jhits/plugin-telemetry",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "System logging and telemetry utilities for the JHITS ecosystem",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
8
- "main": "./src/index.ts",
9
- "types": "./src/index.ts",
8
+ "main": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "scripts": {
11
+ "build": "tsc"
12
+ },
10
13
  "exports": {
11
14
  ".": {
12
- "types": "./src/index.ts",
13
- "default": "./src/index.ts"
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
14
17
  },
15
18
  "./server": {
16
- "types": "./src/server.ts",
17
- "default": "./src/server.ts"
19
+ "types": "./dist/server.d.ts",
20
+ "default": "./dist/server.js"
18
21
  },
19
22
  "./api/route": {
20
- "types": "./src/api/route.ts",
21
- "default": "./src/api/route.ts"
23
+ "types": "./dist/api/route.d.ts",
24
+ "default": "./dist/api/route.js"
22
25
  },
23
26
  "./api/handler": {
24
- "types": "./src/api/handler.ts",
25
- "default": "./src/api/handler.ts"
27
+ "types": "./dist/api/handler.d.ts",
28
+ "default": "./dist/api/handler.js"
26
29
  },
27
30
  "./utils/logCleaner": {
28
- "types": "./src/utils/logCleaner.ts",
29
- "default": "./src/utils/logCleaner.ts"
31
+ "types": "./dist/utils/logCleaner.d.ts",
32
+ "default": "./dist/utils/logCleaner.js"
30
33
  }
31
34
  },
32
35
  "dependencies": {
33
- "@jhits/plugin-core": "^0.0.1",
34
- "server-only": "^0.0.1"
36
+ "@jhits/plugin-core": "^0.0.2"
35
37
  },
36
38
  "peerDependencies": {
37
39
  "next": ">=15.0.0",
@@ -39,18 +41,17 @@
39
41
  "react-dom": ">=18.0.0"
40
42
  },
41
43
  "devDependencies": {
42
- "@types/node": "^20.19.27",
43
- "@types/react": "^19",
44
- "@types/react-dom": "^19",
45
- "next": "16.1.1",
46
- "react": "19.2.3",
47
- "react-dom": "19.2.3",
48
- "typescript": "^5"
44
+ "@types/node": "^25.2.3",
45
+ "@types/react": "^19.2.14",
46
+ "@types/react-dom": "^19.2.3",
47
+ "next": "16.1.6",
48
+ "react": "19.2.4",
49
+ "react-dom": "19.2.4",
50
+ "typescript": "^5.9.3"
49
51
  },
50
52
  "files": [
51
- "src/**/*.{ts,tsx,json}",
52
- "!src/**/*.md",
53
- "!src/**/README.md",
53
+ "dist",
54
+ "src",
54
55
  "package.json"
55
56
  ]
56
57
  }