@geekmidas/studio 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/{DataBrowser-hGwiTffZ.d.cts → DataBrowser-B-jz8KBR.d.mts} +5 -2
  2. package/dist/DataBrowser-B-jz8KBR.d.mts.map +1 -0
  3. package/dist/{DataBrowser-SOcqmZb2.d.mts → DataBrowser-BTe9HWJy.d.cts} +5 -2
  4. package/dist/DataBrowser-BTe9HWJy.d.cts.map +1 -0
  5. package/dist/{DataBrowser-c-Gs6PZB.cjs → DataBrowser-D8c_pBf4.cjs} +4 -4
  6. package/dist/DataBrowser-D8c_pBf4.cjs.map +1 -0
  7. package/dist/{DataBrowser-DQ3-ZxdV.mjs → DataBrowser-kgcI9ApJ.mjs} +4 -4
  8. package/dist/DataBrowser-kgcI9ApJ.mjs.map +1 -0
  9. package/dist/Studio-CYzz3wD2.d.cts +152 -0
  10. package/dist/Studio-CYzz3wD2.d.cts.map +1 -0
  11. package/dist/Studio-D5yGscb8.d.mts +152 -0
  12. package/dist/Studio-D5yGscb8.d.mts.map +1 -0
  13. package/dist/data/index.cjs +1 -1
  14. package/dist/data/index.d.cts +1 -1
  15. package/dist/data/index.d.mts +1 -1
  16. package/dist/data/index.mjs +1 -1
  17. package/dist/index.cjs +33 -3
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +4 -131
  20. package/dist/index.d.mts +4 -131
  21. package/dist/index.mjs +33 -3
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/server/hono.cjs +168 -21
  24. package/dist/server/hono.cjs.map +1 -1
  25. package/dist/server/hono.d.cts +13 -2
  26. package/dist/server/hono.d.cts.map +1 -0
  27. package/dist/server/hono.d.mts +13 -2
  28. package/dist/server/hono.d.mts.map +1 -0
  29. package/dist/server/hono.mjs +168 -21
  30. package/dist/server/hono.mjs.map +1 -1
  31. package/dist/types-BZv87Ikv.mjs.map +1 -1
  32. package/dist/types-CMttUZYk.cjs.map +1 -1
  33. package/package.json +5 -5
  34. package/src/Studio.ts +341 -292
  35. package/src/__tests__/Studio.spec.ts +447 -0
  36. package/src/data/DataBrowser.ts +147 -143
  37. package/src/data/__tests__/DataBrowser.integration.spec.ts +404 -404
  38. package/src/data/__tests__/filtering.integration.spec.ts +726 -726
  39. package/src/data/__tests__/introspection.integration.spec.ts +340 -340
  40. package/src/data/__tests__/pagination.spec.ts +123 -0
  41. package/src/data/filtering.ts +154 -154
  42. package/src/data/introspection.ts +141 -141
  43. package/src/data/pagination.ts +15 -15
  44. package/src/index.ts +22 -24
  45. package/src/server/__tests__/hono.integration.spec.ts +605 -347
  46. package/src/server/hono.ts +392 -190
  47. package/src/types.ts +138 -138
  48. package/src/ui-assets.ts +10 -13
  49. package/tsconfig.json +9 -0
  50. package/tsdown.config.ts +9 -9
  51. package/ui/package.json +28 -22
  52. package/ui/src/App.tsx +95 -235
  53. package/ui/src/api.ts +184 -42
  54. package/ui/src/components/FilterPanel.tsx +198 -198
  55. package/ui/src/components/NavRail.tsx +183 -0
  56. package/ui/src/components/RowDetail.tsx +106 -106
  57. package/ui/src/components/StudioHeader.tsx +109 -0
  58. package/ui/src/components/TableList.tsx +49 -49
  59. package/ui/src/components/TableView.tsx +530 -485
  60. package/ui/src/main.tsx +3 -3
  61. package/ui/src/pages/DashboardPage.tsx +500 -0
  62. package/ui/src/pages/DatabasePage.tsx +226 -0
  63. package/ui/src/pages/EndpointDetailsPage.tsx +288 -0
  64. package/ui/src/pages/ExceptionsPage.tsx +268 -0
  65. package/ui/src/pages/LogsPage.tsx +228 -0
  66. package/ui/src/pages/MonitoringPage.tsx +46 -0
  67. package/ui/src/pages/PerformancePage.tsx +307 -0
  68. package/ui/src/pages/RequestsPage.tsx +379 -0
  69. package/ui/src/providers/StudioProvider.tsx +194 -0
  70. package/ui/src/styles.css +53 -142
  71. package/ui/src/types.ts +154 -30
  72. package/ui/tsconfig.tsbuildinfo +1 -1
  73. package/ui/vite.config.ts +6 -6
  74. package/dist/DataBrowser-DQ3-ZxdV.mjs.map +0 -1
  75. package/dist/DataBrowser-c-Gs6PZB.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["options: StudioOptions<DB>","Telescope","DataBrowser","entry: Parameters<Telescope['recordRequest']>[0]","entries: Parameters<Telescope['log']>[0]","message: string","context?: Record<string, unknown>","requestId?: string","error: Error","options?: Parameters<Telescope['getRequests']>[0]","id: string","options?: Parameters<Telescope['getExceptions']>[0]","options?: Parameters<Telescope['getLogs']>[0]","ws: WebSocket","event: StudioEvent","path: string","olderThan: Date"],"sources":["../src/Studio.ts"],"sourcesContent":["import { Telescope } from '@geekmidas/telescope';\nimport { DataBrowser } from './data/DataBrowser';\nimport type {\n NormalizedStudioOptions,\n StudioEvent,\n StudioOptions,\n} from './types';\n\n/**\n * Unified development tools dashboard combining monitoring and database browsing.\n *\n * @example\n * ```typescript\n * import { Studio, Direction } from '@geekmidas/studio';\n * import { InMemoryStorage } from '@geekmidas/telescope/storage/memory';\n *\n * const studio = new Studio({\n * monitoring: {\n * storage: new InMemoryStorage(),\n * },\n * data: {\n * db: kyselyInstance,\n * cursor: { field: 'id', direction: Direction.Desc },\n * },\n * });\n * ```\n */\nexport class Studio<DB = unknown> {\n private telescope: Telescope;\n private dataBrowser: DataBrowser<DB>;\n private options: NormalizedStudioOptions<DB>;\n private wsClients = new Set<WebSocket>();\n\n constructor(options: StudioOptions<DB>) {\n this.options = this.normalizeOptions(options);\n\n // Initialize Telescope internally\n this.telescope = new Telescope({\n storage: this.options.monitoring.storage,\n enabled: this.options.enabled,\n path: `${this.options.path}/monitoring`,\n recordBody: this.options.monitoring.recordBody,\n maxBodySize: this.options.monitoring.maxBodySize,\n ignorePatterns: [\n ...this.options.monitoring.ignorePatterns,\n `${this.options.path}/*`, // Ignore Studio's own routes\n ],\n pruneAfterHours: this.options.monitoring.pruneAfterHours,\n });\n\n // Initialize DataBrowser\n this.dataBrowser = new DataBrowser(this.options.data);\n }\n\n // ============================================\n // Public API - Configuration\n // ============================================\n\n /**\n * Get the Studio dashboard path.\n */\n get path(): string {\n return this.options.path;\n }\n\n /**\n * Check if Studio is enabled.\n */\n get enabled(): boolean {\n return this.options.enabled;\n }\n\n /**\n * Get the data browser instance.\n */\n get data(): DataBrowser<DB> {\n return this.dataBrowser;\n }\n\n /**\n * Check if body recording is enabled for monitoring.\n */\n get recordBody(): boolean {\n return this.options.monitoring.recordBody;\n }\n\n /**\n * Get max body size for monitoring.\n */\n get maxBodySize(): number {\n return this.options.monitoring.maxBodySize;\n }\n\n // ============================================\n // Public API - Monitoring (delegated to Telescope)\n // ============================================\n\n /**\n * Record a request entry.\n */\n async recordRequest(\n entry: Parameters<Telescope['recordRequest']>[0],\n ): Promise<string> {\n return this.telescope.recordRequest(entry);\n }\n\n /**\n * Record log entries in batch.\n */\n async log(entries: Parameters<Telescope['log']>[0]): Promise<void> {\n return this.telescope.log(entries);\n }\n\n /**\n * Log a debug message.\n */\n async debug(\n message: string,\n context?: Record<string, unknown>,\n requestId?: string,\n ): Promise<void> {\n return this.telescope.debug(message, context, requestId);\n }\n\n /**\n * Log an info message.\n */\n async info(\n message: string,\n context?: Record<string, unknown>,\n requestId?: string,\n ): Promise<void> {\n return this.telescope.info(message, context, requestId);\n }\n\n /**\n * Log a warning message.\n */\n async warn(\n message: string,\n context?: Record<string, unknown>,\n requestId?: string,\n ): Promise<void> {\n return this.telescope.warn(message, context, requestId);\n }\n\n /**\n * Log an error message.\n */\n async error(\n message: string,\n context?: Record<string, unknown>,\n requestId?: string,\n ): Promise<void> {\n return this.telescope.error(message, context, requestId);\n }\n\n /**\n * Record an exception.\n */\n async exception(error: Error, requestId?: string): Promise<void> {\n return this.telescope.exception(error, requestId);\n }\n\n /**\n * Get requests from storage.\n */\n async getRequests(\n options?: Parameters<Telescope['getRequests']>[0],\n ): ReturnType<Telescope['getRequests']> {\n return this.telescope.getRequests(options);\n }\n\n /**\n * Get a single request by ID.\n */\n async getRequest(id: string): ReturnType<Telescope['getRequest']> {\n return this.telescope.getRequest(id);\n }\n\n /**\n * Get exceptions from storage.\n */\n async getExceptions(\n options?: Parameters<Telescope['getExceptions']>[0],\n ): ReturnType<Telescope['getExceptions']> {\n return this.telescope.getExceptions(options);\n }\n\n /**\n * Get a single exception by ID.\n */\n async getException(id: string): ReturnType<Telescope['getException']> {\n return this.telescope.getException(id);\n }\n\n /**\n * Get logs from storage.\n */\n async getLogs(\n options?: Parameters<Telescope['getLogs']>[0],\n ): ReturnType<Telescope['getLogs']> {\n return this.telescope.getLogs(options);\n }\n\n /**\n * Get storage statistics.\n */\n async getStats(): ReturnType<Telescope['getStats']> {\n return this.telescope.getStats();\n }\n\n // ============================================\n // Public API - WebSocket\n // ============================================\n\n /**\n * Add a WebSocket client for real-time updates.\n */\n addWsClient(ws: WebSocket): void {\n this.wsClients.add(ws);\n // Also add to Telescope for monitoring events\n this.telescope.addWsClient(ws);\n }\n\n /**\n * Remove a WebSocket client.\n */\n removeWsClient(ws: WebSocket): void {\n this.wsClients.delete(ws);\n this.telescope.removeWsClient(ws);\n }\n\n /**\n * Broadcast an event to all connected WebSocket clients.\n */\n broadcast(event: StudioEvent): void {\n const data = JSON.stringify(event);\n for (const client of this.wsClients) {\n try {\n client.send(data);\n } catch {\n this.wsClients.delete(client);\n }\n }\n }\n\n // ============================================\n // Public API - Lifecycle\n // ============================================\n\n /**\n * Check if a path should be ignored for request recording.\n */\n shouldIgnore(path: string): boolean {\n // Ignore Studio's own routes\n if (path.startsWith(this.options.path)) {\n return true;\n }\n return this.telescope.shouldIgnore(path);\n }\n\n /**\n * Manually prune old monitoring entries.\n */\n async prune(olderThan: Date): Promise<number> {\n return this.telescope.prune(olderThan);\n }\n\n /**\n * Clean up resources.\n */\n destroy(): void {\n this.telescope.destroy();\n this.wsClients.clear();\n }\n\n // ============================================\n // Private Methods\n // ============================================\n\n private normalizeOptions(\n options: StudioOptions<DB>,\n ): NormalizedStudioOptions<DB> {\n const path = options.path ?? '/__studio';\n\n return {\n monitoring: {\n storage: options.monitoring.storage,\n ignorePatterns: options.monitoring.ignorePatterns ?? [],\n recordBody: options.monitoring.recordBody ?? true,\n maxBodySize: options.monitoring.maxBodySize ?? 64 * 1024,\n pruneAfterHours: options.monitoring.pruneAfterHours,\n },\n data: {\n db: options.data.db,\n cursor: options.data.cursor,\n tableCursors: options.data.tableCursors ?? {},\n excludeTables: options.data.excludeTables ?? [\n // Kysely\n 'kysely_migration',\n 'kysely_migration_lock',\n // Prisma\n '_prisma_migrations',\n // Rails/Knex\n 'schema_migrations',\n // Generic\n '_migrations',\n 'migrations',\n ],\n defaultPageSize: Math.min(options.data.defaultPageSize ?? 50, 100),\n showBinaryColumns: options.data.showBinaryColumns ?? false,\n },\n path,\n enabled: options.enabled ?? true,\n };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["options: StudioOptions<DB>","Telescope","DataBrowser","entry: Parameters<Telescope['recordRequest']>[0]","entries: Parameters<Telescope['log']>[0]","message: string","context?: Record<string, unknown>","requestId?: string","error: Error","options?: Parameters<Telescope['getRequests']>[0]","id: string","options?: Parameters<Telescope['getExceptions']>[0]","options?: Parameters<Telescope['getLogs']>[0]","options?: Parameters<Telescope['getMetrics']>[0]","options?: Parameters<Telescope['getEndpointMetrics']>[0]","method: string","path: string","options?: Parameters<Telescope['getEndpointDetails']>[2]","options?: Parameters<Telescope['getStatusDistribution']>[0]","ws: WebSocket","event: StudioEvent","olderThan: Date"],"sources":["../src/Studio.ts"],"sourcesContent":["import { Telescope } from '@geekmidas/telescope';\nimport { DataBrowser } from './data/DataBrowser';\nimport type {\n\tNormalizedStudioOptions,\n\tStudioEvent,\n\tStudioOptions,\n} from './types';\n\n/**\n * Unified development tools dashboard combining monitoring and database browsing.\n *\n * @example\n * ```typescript\n * import { Studio, Direction } from '@geekmidas/studio';\n * import { InMemoryStorage } from '@geekmidas/telescope/storage/memory';\n *\n * const studio = new Studio({\n * monitoring: {\n * storage: new InMemoryStorage(),\n * },\n * data: {\n * db: kyselyInstance,\n * cursor: { field: 'id', direction: Direction.Desc },\n * },\n * });\n * ```\n */\nexport class Studio<DB = unknown> {\n\tprivate telescope: Telescope;\n\tprivate dataBrowser: DataBrowser<DB>;\n\tprivate options: NormalizedStudioOptions<DB>;\n\tprivate wsClients = new Set<WebSocket>();\n\n\tconstructor(options: StudioOptions<DB>) {\n\t\tthis.options = this.normalizeOptions(options);\n\n\t\t// Initialize Telescope internally\n\t\tthis.telescope = new Telescope({\n\t\t\tstorage: this.options.monitoring.storage,\n\t\t\tenabled: this.options.enabled,\n\t\t\tpath: `${this.options.path}/monitoring`,\n\t\t\trecordBody: this.options.monitoring.recordBody,\n\t\t\tmaxBodySize: this.options.monitoring.maxBodySize,\n\t\t\tignorePatterns: [\n\t\t\t\t...this.options.monitoring.ignorePatterns,\n\t\t\t\t`${this.options.path}/*`, // Ignore Studio's own routes\n\t\t\t],\n\t\t\tpruneAfterHours: this.options.monitoring.pruneAfterHours,\n\t\t});\n\n\t\t// Initialize DataBrowser\n\t\tthis.dataBrowser = new DataBrowser(this.options.data);\n\t}\n\n\t// ============================================\n\t// Public API - Configuration\n\t// ============================================\n\n\t/**\n\t * Get the Studio dashboard path.\n\t */\n\tget path(): string {\n\t\treturn this.options.path;\n\t}\n\n\t/**\n\t * Check if Studio is enabled.\n\t */\n\tget enabled(): boolean {\n\t\treturn this.options.enabled;\n\t}\n\n\t/**\n\t * Get the data browser instance.\n\t */\n\tget data(): DataBrowser<DB> {\n\t\treturn this.dataBrowser;\n\t}\n\n\t/**\n\t * Check if body recording is enabled for monitoring.\n\t */\n\tget recordBody(): boolean {\n\t\treturn this.options.monitoring.recordBody;\n\t}\n\n\t/**\n\t * Get max body size for monitoring.\n\t */\n\tget maxBodySize(): number {\n\t\treturn this.options.monitoring.maxBodySize;\n\t}\n\n\t// ============================================\n\t// Public API - Monitoring (delegated to Telescope)\n\t// ============================================\n\n\t/**\n\t * Record a request entry.\n\t */\n\tasync recordRequest(\n\t\tentry: Parameters<Telescope['recordRequest']>[0],\n\t): Promise<string> {\n\t\treturn this.telescope.recordRequest(entry);\n\t}\n\n\t/**\n\t * Record log entries in batch.\n\t */\n\tasync log(entries: Parameters<Telescope['log']>[0]): Promise<void> {\n\t\treturn this.telescope.log(entries);\n\t}\n\n\t/**\n\t * Log a debug message.\n\t */\n\tasync debug(\n\t\tmessage: string,\n\t\tcontext?: Record<string, unknown>,\n\t\trequestId?: string,\n\t): Promise<void> {\n\t\treturn this.telescope.debug(message, context, requestId);\n\t}\n\n\t/**\n\t * Log an info message.\n\t */\n\tasync info(\n\t\tmessage: string,\n\t\tcontext?: Record<string, unknown>,\n\t\trequestId?: string,\n\t): Promise<void> {\n\t\treturn this.telescope.info(message, context, requestId);\n\t}\n\n\t/**\n\t * Log a warning message.\n\t */\n\tasync warn(\n\t\tmessage: string,\n\t\tcontext?: Record<string, unknown>,\n\t\trequestId?: string,\n\t): Promise<void> {\n\t\treturn this.telescope.warn(message, context, requestId);\n\t}\n\n\t/**\n\t * Log an error message.\n\t */\n\tasync error(\n\t\tmessage: string,\n\t\tcontext?: Record<string, unknown>,\n\t\trequestId?: string,\n\t): Promise<void> {\n\t\treturn this.telescope.error(message, context, requestId);\n\t}\n\n\t/**\n\t * Record an exception.\n\t */\n\tasync exception(error: Error, requestId?: string): Promise<void> {\n\t\treturn this.telescope.exception(error, requestId);\n\t}\n\n\t/**\n\t * Get requests from storage.\n\t */\n\tasync getRequests(\n\t\toptions?: Parameters<Telescope['getRequests']>[0],\n\t): ReturnType<Telescope['getRequests']> {\n\t\treturn this.telescope.getRequests(options);\n\t}\n\n\t/**\n\t * Get a single request by ID.\n\t */\n\tasync getRequest(id: string): ReturnType<Telescope['getRequest']> {\n\t\treturn this.telescope.getRequest(id);\n\t}\n\n\t/**\n\t * Get exceptions from storage.\n\t */\n\tasync getExceptions(\n\t\toptions?: Parameters<Telescope['getExceptions']>[0],\n\t): ReturnType<Telescope['getExceptions']> {\n\t\treturn this.telescope.getExceptions(options);\n\t}\n\n\t/**\n\t * Get a single exception by ID.\n\t */\n\tasync getException(id: string): ReturnType<Telescope['getException']> {\n\t\treturn this.telescope.getException(id);\n\t}\n\n\t/**\n\t * Get logs from storage.\n\t */\n\tasync getLogs(\n\t\toptions?: Parameters<Telescope['getLogs']>[0],\n\t): ReturnType<Telescope['getLogs']> {\n\t\treturn this.telescope.getLogs(options);\n\t}\n\n\t/**\n\t * Get storage statistics.\n\t */\n\tasync getStats(): ReturnType<Telescope['getStats']> {\n\t\treturn this.telescope.getStats();\n\t}\n\n\t// ============================================\n\t// Public API - Metrics (delegated to Telescope)\n\t// ============================================\n\n\t/**\n\t * Get aggregated request metrics.\n\t */\n\tgetMetrics(\n\t\toptions?: Parameters<Telescope['getMetrics']>[0],\n\t): ReturnType<Telescope['getMetrics']> {\n\t\treturn this.telescope.getMetrics(options);\n\t}\n\n\t/**\n\t * Get metrics grouped by endpoint.\n\t */\n\tgetEndpointMetrics(\n\t\toptions?: Parameters<Telescope['getEndpointMetrics']>[0],\n\t): ReturnType<Telescope['getEndpointMetrics']> {\n\t\treturn this.telescope.getEndpointMetrics(options);\n\t}\n\n\t/**\n\t * Get detailed metrics for a specific endpoint.\n\t */\n\tgetEndpointDetails(\n\t\tmethod: string,\n\t\tpath: string,\n\t\toptions?: Parameters<Telescope['getEndpointDetails']>[2],\n\t): ReturnType<Telescope['getEndpointDetails']> {\n\t\treturn this.telescope.getEndpointDetails(method, path, options);\n\t}\n\n\t/**\n\t * Get HTTP status code distribution.\n\t */\n\tgetStatusDistribution(\n\t\toptions?: Parameters<Telescope['getStatusDistribution']>[0],\n\t): ReturnType<Telescope['getStatusDistribution']> {\n\t\treturn this.telescope.getStatusDistribution(options);\n\t}\n\n\t/**\n\t * Reset all metrics.\n\t */\n\tresetMetrics(): void {\n\t\tthis.telescope.resetMetrics();\n\t}\n\n\t// ============================================\n\t// Public API - WebSocket\n\t// ============================================\n\n\t/**\n\t * Add a WebSocket client for real-time updates.\n\t */\n\taddWsClient(ws: WebSocket): void {\n\t\tthis.wsClients.add(ws);\n\t\t// Also add to Telescope for monitoring events\n\t\tthis.telescope.addWsClient(ws);\n\t}\n\n\t/**\n\t * Remove a WebSocket client.\n\t */\n\tremoveWsClient(ws: WebSocket): void {\n\t\tthis.wsClients.delete(ws);\n\t\tthis.telescope.removeWsClient(ws);\n\t}\n\n\t/**\n\t * Broadcast an event to all connected WebSocket clients.\n\t */\n\tbroadcast(event: StudioEvent): void {\n\t\tconst data = JSON.stringify(event);\n\t\tfor (const client of this.wsClients) {\n\t\t\ttry {\n\t\t\t\tclient.send(data);\n\t\t\t} catch {\n\t\t\t\tthis.wsClients.delete(client);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ============================================\n\t// Public API - Lifecycle\n\t// ============================================\n\n\t/**\n\t * Check if a path should be ignored for request recording.\n\t */\n\tshouldIgnore(path: string): boolean {\n\t\t// Ignore Studio's own routes\n\t\tif (path.startsWith(this.options.path)) {\n\t\t\treturn true;\n\t\t}\n\t\treturn this.telescope.shouldIgnore(path);\n\t}\n\n\t/**\n\t * Manually prune old monitoring entries.\n\t */\n\tasync prune(olderThan: Date): Promise<number> {\n\t\treturn this.telescope.prune(olderThan);\n\t}\n\n\t/**\n\t * Clean up resources.\n\t */\n\tdestroy(): void {\n\t\tthis.telescope.destroy();\n\t\tthis.wsClients.clear();\n\t}\n\n\t// ============================================\n\t// Private Methods\n\t// ============================================\n\n\tprivate normalizeOptions(\n\t\toptions: StudioOptions<DB>,\n\t): NormalizedStudioOptions<DB> {\n\t\tconst path = options.path ?? '/__studio';\n\n\t\treturn {\n\t\t\tmonitoring: {\n\t\t\t\tstorage: options.monitoring.storage,\n\t\t\t\tignorePatterns: options.monitoring.ignorePatterns ?? [],\n\t\t\t\trecordBody: options.monitoring.recordBody ?? true,\n\t\t\t\tmaxBodySize: options.monitoring.maxBodySize ?? 64 * 1024,\n\t\t\t\tpruneAfterHours: options.monitoring.pruneAfterHours ?? 24,\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tdb: options.data.db,\n\t\t\t\tcursor: options.data.cursor,\n\t\t\t\ttableCursors: options.data.tableCursors ?? {},\n\t\t\t\texcludeTables: options.data.excludeTables ?? [\n\t\t\t\t\t// Kysely\n\t\t\t\t\t'kysely_migration',\n\t\t\t\t\t'kysely_migration_lock',\n\t\t\t\t\t// Prisma\n\t\t\t\t\t'_prisma_migrations',\n\t\t\t\t\t// Rails/Knex\n\t\t\t\t\t'schema_migrations',\n\t\t\t\t\t// Generic\n\t\t\t\t\t'_migrations',\n\t\t\t\t\t'migrations',\n\t\t\t\t],\n\t\t\t\tdefaultPageSize: Math.min(options.data.defaultPageSize ?? 50, 100),\n\t\t\t\tshowBinaryColumns: options.data.showBinaryColumns ?? false,\n\t\t\t},\n\t\t\tpath,\n\t\t\tenabled: options.enabled ?? true,\n\t\t};\n\t}\n}\n"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -1,132 +1,5 @@
1
- import { ColumnInfo, ColumnType, CursorConfig, DataBrowser, DataBrowserOptions, Direction, FilterCondition, FilterOperator, MonitoringOptions, NormalizedStudioOptions, QueryOptions, QueryResult, SchemaInfo, SortConfig, StudioEvent, StudioEventType, StudioOptions, TableCursorConfig, TableInfo } from "./DataBrowser-hGwiTffZ.cjs";
2
- import { Telescope, TelescopeStorage as MonitoringStorage } from "@geekmidas/telescope";
1
+ import { ColumnInfo, ColumnType, CursorConfig, DataBrowserOptions, Direction, FilterCondition, FilterOperator, MonitoringOptions, NormalizedStudioOptions, QueryOptions, QueryResult, SchemaInfo, SortConfig, StudioEvent, StudioEventType, StudioOptions, TableCursorConfig, TableInfo } from "./DataBrowser-BTe9HWJy.cjs";
2
+ import { Studio } from "./Studio-CYzz3wD2.cjs";
3
+ import { TelescopeStorage as MonitoringStorage } from "@geekmidas/telescope";
3
4
  import { InMemoryStorage as InMemoryMonitoringStorage } from "@geekmidas/telescope/storage/memory";
4
-
5
- //#region src/Studio.d.ts
6
-
7
- /**
8
- * Unified development tools dashboard combining monitoring and database browsing.
9
- *
10
- * @example
11
- * ```typescript
12
- * import { Studio, Direction } from '@geekmidas/studio';
13
- * import { InMemoryStorage } from '@geekmidas/telescope/storage/memory';
14
- *
15
- * const studio = new Studio({
16
- * monitoring: {
17
- * storage: new InMemoryStorage(),
18
- * },
19
- * data: {
20
- * db: kyselyInstance,
21
- * cursor: { field: 'id', direction: Direction.Desc },
22
- * },
23
- * });
24
- * ```
25
- */
26
- declare class Studio<DB = unknown> {
27
- private telescope;
28
- private dataBrowser;
29
- private options;
30
- private wsClients;
31
- constructor(options: StudioOptions<DB>);
32
- /**
33
- * Get the Studio dashboard path.
34
- */
35
- get path(): string;
36
- /**
37
- * Check if Studio is enabled.
38
- */
39
- get enabled(): boolean;
40
- /**
41
- * Get the data browser instance.
42
- */
43
- get data(): DataBrowser<DB>;
44
- /**
45
- * Check if body recording is enabled for monitoring.
46
- */
47
- get recordBody(): boolean;
48
- /**
49
- * Get max body size for monitoring.
50
- */
51
- get maxBodySize(): number;
52
- /**
53
- * Record a request entry.
54
- */
55
- recordRequest(entry: Parameters<Telescope['recordRequest']>[0]): Promise<string>;
56
- /**
57
- * Record log entries in batch.
58
- */
59
- log(entries: Parameters<Telescope['log']>[0]): Promise<void>;
60
- /**
61
- * Log a debug message.
62
- */
63
- debug(message: string, context?: Record<string, unknown>, requestId?: string): Promise<void>;
64
- /**
65
- * Log an info message.
66
- */
67
- info(message: string, context?: Record<string, unknown>, requestId?: string): Promise<void>;
68
- /**
69
- * Log a warning message.
70
- */
71
- warn(message: string, context?: Record<string, unknown>, requestId?: string): Promise<void>;
72
- /**
73
- * Log an error message.
74
- */
75
- error(message: string, context?: Record<string, unknown>, requestId?: string): Promise<void>;
76
- /**
77
- * Record an exception.
78
- */
79
- exception(error: Error, requestId?: string): Promise<void>;
80
- /**
81
- * Get requests from storage.
82
- */
83
- getRequests(options?: Parameters<Telescope['getRequests']>[0]): ReturnType<Telescope['getRequests']>;
84
- /**
85
- * Get a single request by ID.
86
- */
87
- getRequest(id: string): ReturnType<Telescope['getRequest']>;
88
- /**
89
- * Get exceptions from storage.
90
- */
91
- getExceptions(options?: Parameters<Telescope['getExceptions']>[0]): ReturnType<Telescope['getExceptions']>;
92
- /**
93
- * Get a single exception by ID.
94
- */
95
- getException(id: string): ReturnType<Telescope['getException']>;
96
- /**
97
- * Get logs from storage.
98
- */
99
- getLogs(options?: Parameters<Telescope['getLogs']>[0]): ReturnType<Telescope['getLogs']>;
100
- /**
101
- * Get storage statistics.
102
- */
103
- getStats(): ReturnType<Telescope['getStats']>;
104
- /**
105
- * Add a WebSocket client for real-time updates.
106
- */
107
- addWsClient(ws: WebSocket): void;
108
- /**
109
- * Remove a WebSocket client.
110
- */
111
- removeWsClient(ws: WebSocket): void;
112
- /**
113
- * Broadcast an event to all connected WebSocket clients.
114
- */
115
- broadcast(event: StudioEvent): void;
116
- /**
117
- * Check if a path should be ignored for request recording.
118
- */
119
- shouldIgnore(path: string): boolean;
120
- /**
121
- * Manually prune old monitoring entries.
122
- */
123
- prune(olderThan: Date): Promise<number>;
124
- /**
125
- * Clean up resources.
126
- */
127
- destroy(): void;
128
- private normalizeOptions;
129
- }
130
- //#endregion
131
- export { ColumnInfo, ColumnType, CursorConfig, DataBrowserOptions, Direction, FilterCondition, FilterOperator, InMemoryMonitoringStorage, MonitoringOptions, MonitoringStorage, NormalizedStudioOptions, QueryOptions, QueryResult, SchemaInfo, SortConfig, Studio, StudioEvent, StudioEventType, StudioOptions, TableCursorConfig, TableInfo };
132
- //# sourceMappingURL=index.d.cts.map
5
+ export { ColumnInfo, ColumnType, CursorConfig, DataBrowserOptions, Direction, FilterCondition, FilterOperator, InMemoryMonitoringStorage, MonitoringOptions, MonitoringStorage, NormalizedStudioOptions, QueryOptions, QueryResult, SchemaInfo, SortConfig, Studio, StudioEvent, StudioEventType, StudioOptions, TableCursorConfig, TableInfo };
package/dist/index.d.mts CHANGED
@@ -1,132 +1,5 @@
1
- import { ColumnInfo, ColumnType, CursorConfig, DataBrowser, DataBrowserOptions, Direction, FilterCondition, FilterOperator, MonitoringOptions, NormalizedStudioOptions, QueryOptions, QueryResult, SchemaInfo, SortConfig, StudioEvent, StudioEventType, StudioOptions, TableCursorConfig, TableInfo } from "./DataBrowser-SOcqmZb2.mjs";
2
- import { Telescope, TelescopeStorage as MonitoringStorage } from "@geekmidas/telescope";
1
+ import { ColumnInfo, ColumnType, CursorConfig, DataBrowserOptions, Direction, FilterCondition, FilterOperator, MonitoringOptions, NormalizedStudioOptions, QueryOptions, QueryResult, SchemaInfo, SortConfig, StudioEvent, StudioEventType, StudioOptions, TableCursorConfig, TableInfo } from "./DataBrowser-B-jz8KBR.mjs";
2
+ import { Studio } from "./Studio-D5yGscb8.mjs";
3
3
  import { InMemoryStorage as InMemoryMonitoringStorage } from "@geekmidas/telescope/storage/memory";
4
-
5
- //#region src/Studio.d.ts
6
-
7
- /**
8
- * Unified development tools dashboard combining monitoring and database browsing.
9
- *
10
- * @example
11
- * ```typescript
12
- * import { Studio, Direction } from '@geekmidas/studio';
13
- * import { InMemoryStorage } from '@geekmidas/telescope/storage/memory';
14
- *
15
- * const studio = new Studio({
16
- * monitoring: {
17
- * storage: new InMemoryStorage(),
18
- * },
19
- * data: {
20
- * db: kyselyInstance,
21
- * cursor: { field: 'id', direction: Direction.Desc },
22
- * },
23
- * });
24
- * ```
25
- */
26
- declare class Studio<DB = unknown> {
27
- private telescope;
28
- private dataBrowser;
29
- private options;
30
- private wsClients;
31
- constructor(options: StudioOptions<DB>);
32
- /**
33
- * Get the Studio dashboard path.
34
- */
35
- get path(): string;
36
- /**
37
- * Check if Studio is enabled.
38
- */
39
- get enabled(): boolean;
40
- /**
41
- * Get the data browser instance.
42
- */
43
- get data(): DataBrowser<DB>;
44
- /**
45
- * Check if body recording is enabled for monitoring.
46
- */
47
- get recordBody(): boolean;
48
- /**
49
- * Get max body size for monitoring.
50
- */
51
- get maxBodySize(): number;
52
- /**
53
- * Record a request entry.
54
- */
55
- recordRequest(entry: Parameters<Telescope['recordRequest']>[0]): Promise<string>;
56
- /**
57
- * Record log entries in batch.
58
- */
59
- log(entries: Parameters<Telescope['log']>[0]): Promise<void>;
60
- /**
61
- * Log a debug message.
62
- */
63
- debug(message: string, context?: Record<string, unknown>, requestId?: string): Promise<void>;
64
- /**
65
- * Log an info message.
66
- */
67
- info(message: string, context?: Record<string, unknown>, requestId?: string): Promise<void>;
68
- /**
69
- * Log a warning message.
70
- */
71
- warn(message: string, context?: Record<string, unknown>, requestId?: string): Promise<void>;
72
- /**
73
- * Log an error message.
74
- */
75
- error(message: string, context?: Record<string, unknown>, requestId?: string): Promise<void>;
76
- /**
77
- * Record an exception.
78
- */
79
- exception(error: Error, requestId?: string): Promise<void>;
80
- /**
81
- * Get requests from storage.
82
- */
83
- getRequests(options?: Parameters<Telescope['getRequests']>[0]): ReturnType<Telescope['getRequests']>;
84
- /**
85
- * Get a single request by ID.
86
- */
87
- getRequest(id: string): ReturnType<Telescope['getRequest']>;
88
- /**
89
- * Get exceptions from storage.
90
- */
91
- getExceptions(options?: Parameters<Telescope['getExceptions']>[0]): ReturnType<Telescope['getExceptions']>;
92
- /**
93
- * Get a single exception by ID.
94
- */
95
- getException(id: string): ReturnType<Telescope['getException']>;
96
- /**
97
- * Get logs from storage.
98
- */
99
- getLogs(options?: Parameters<Telescope['getLogs']>[0]): ReturnType<Telescope['getLogs']>;
100
- /**
101
- * Get storage statistics.
102
- */
103
- getStats(): ReturnType<Telescope['getStats']>;
104
- /**
105
- * Add a WebSocket client for real-time updates.
106
- */
107
- addWsClient(ws: WebSocket): void;
108
- /**
109
- * Remove a WebSocket client.
110
- */
111
- removeWsClient(ws: WebSocket): void;
112
- /**
113
- * Broadcast an event to all connected WebSocket clients.
114
- */
115
- broadcast(event: StudioEvent): void;
116
- /**
117
- * Check if a path should be ignored for request recording.
118
- */
119
- shouldIgnore(path: string): boolean;
120
- /**
121
- * Manually prune old monitoring entries.
122
- */
123
- prune(olderThan: Date): Promise<number>;
124
- /**
125
- * Clean up resources.
126
- */
127
- destroy(): void;
128
- private normalizeOptions;
129
- }
130
- //#endregion
131
- export { ColumnInfo, ColumnType, CursorConfig, DataBrowserOptions, Direction, FilterCondition, FilterOperator, InMemoryMonitoringStorage, MonitoringOptions, MonitoringStorage, NormalizedStudioOptions, QueryOptions, QueryResult, SchemaInfo, SortConfig, Studio, StudioEvent, StudioEventType, StudioOptions, TableCursorConfig, TableInfo };
132
- //# sourceMappingURL=index.d.mts.map
4
+ import { TelescopeStorage as MonitoringStorage } from "@geekmidas/telescope";
5
+ export { ColumnInfo, ColumnType, CursorConfig, DataBrowserOptions, Direction, FilterCondition, FilterOperator, InMemoryMonitoringStorage, MonitoringOptions, MonitoringStorage, NormalizedStudioOptions, QueryOptions, QueryResult, SchemaInfo, SortConfig, Studio, StudioEvent, StudioEventType, StudioOptions, TableCursorConfig, TableInfo };
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Direction, FilterOperator } from "./types-BZv87Ikv.mjs";
2
- import { DataBrowser } from "./DataBrowser-DQ3-ZxdV.mjs";
3
- import { Telescope } from "@geekmidas/telescope";
2
+ import { DataBrowser } from "./DataBrowser-kgcI9ApJ.mjs";
4
3
  import { InMemoryStorage as InMemoryMonitoringStorage } from "@geekmidas/telescope/storage/memory";
4
+ import { Telescope } from "@geekmidas/telescope";
5
5
 
6
6
  //#region src/Studio.ts
7
7
  /**
@@ -150,6 +150,36 @@ var Studio = class {
150
150
  return this.telescope.getStats();
151
151
  }
152
152
  /**
153
+ * Get aggregated request metrics.
154
+ */
155
+ getMetrics(options) {
156
+ return this.telescope.getMetrics(options);
157
+ }
158
+ /**
159
+ * Get metrics grouped by endpoint.
160
+ */
161
+ getEndpointMetrics(options) {
162
+ return this.telescope.getEndpointMetrics(options);
163
+ }
164
+ /**
165
+ * Get detailed metrics for a specific endpoint.
166
+ */
167
+ getEndpointDetails(method, path, options) {
168
+ return this.telescope.getEndpointDetails(method, path, options);
169
+ }
170
+ /**
171
+ * Get HTTP status code distribution.
172
+ */
173
+ getStatusDistribution(options) {
174
+ return this.telescope.getStatusDistribution(options);
175
+ }
176
+ /**
177
+ * Reset all metrics.
178
+ */
179
+ resetMetrics() {
180
+ this.telescope.resetMetrics();
181
+ }
182
+ /**
153
183
  * Add a WebSocket client for real-time updates.
154
184
  */
155
185
  addWsClient(ws) {
@@ -202,7 +232,7 @@ var Studio = class {
202
232
  ignorePatterns: options.monitoring.ignorePatterns ?? [],
203
233
  recordBody: options.monitoring.recordBody ?? true,
204
234
  maxBodySize: options.monitoring.maxBodySize ?? 64 * 1024,
205
- pruneAfterHours: options.monitoring.pruneAfterHours
235
+ pruneAfterHours: options.monitoring.pruneAfterHours ?? 24
206
236
  },
207
237
  data: {
208
238
  db: options.data.db,
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["options: StudioOptions<DB>","entry: Parameters<Telescope['recordRequest']>[0]","entries: Parameters<Telescope['log']>[0]","message: string","context?: Record<string, unknown>","requestId?: string","error: Error","options?: Parameters<Telescope['getRequests']>[0]","id: string","options?: Parameters<Telescope['getExceptions']>[0]","options?: Parameters<Telescope['getLogs']>[0]","ws: WebSocket","event: StudioEvent","path: string","olderThan: Date"],"sources":["../src/Studio.ts"],"sourcesContent":["import { Telescope } from '@geekmidas/telescope';\nimport { DataBrowser } from './data/DataBrowser';\nimport type {\n NormalizedStudioOptions,\n StudioEvent,\n StudioOptions,\n} from './types';\n\n/**\n * Unified development tools dashboard combining monitoring and database browsing.\n *\n * @example\n * ```typescript\n * import { Studio, Direction } from '@geekmidas/studio';\n * import { InMemoryStorage } from '@geekmidas/telescope/storage/memory';\n *\n * const studio = new Studio({\n * monitoring: {\n * storage: new InMemoryStorage(),\n * },\n * data: {\n * db: kyselyInstance,\n * cursor: { field: 'id', direction: Direction.Desc },\n * },\n * });\n * ```\n */\nexport class Studio<DB = unknown> {\n private telescope: Telescope;\n private dataBrowser: DataBrowser<DB>;\n private options: NormalizedStudioOptions<DB>;\n private wsClients = new Set<WebSocket>();\n\n constructor(options: StudioOptions<DB>) {\n this.options = this.normalizeOptions(options);\n\n // Initialize Telescope internally\n this.telescope = new Telescope({\n storage: this.options.monitoring.storage,\n enabled: this.options.enabled,\n path: `${this.options.path}/monitoring`,\n recordBody: this.options.monitoring.recordBody,\n maxBodySize: this.options.monitoring.maxBodySize,\n ignorePatterns: [\n ...this.options.monitoring.ignorePatterns,\n `${this.options.path}/*`, // Ignore Studio's own routes\n ],\n pruneAfterHours: this.options.monitoring.pruneAfterHours,\n });\n\n // Initialize DataBrowser\n this.dataBrowser = new DataBrowser(this.options.data);\n }\n\n // ============================================\n // Public API - Configuration\n // ============================================\n\n /**\n * Get the Studio dashboard path.\n */\n get path(): string {\n return this.options.path;\n }\n\n /**\n * Check if Studio is enabled.\n */\n get enabled(): boolean {\n return this.options.enabled;\n }\n\n /**\n * Get the data browser instance.\n */\n get data(): DataBrowser<DB> {\n return this.dataBrowser;\n }\n\n /**\n * Check if body recording is enabled for monitoring.\n */\n get recordBody(): boolean {\n return this.options.monitoring.recordBody;\n }\n\n /**\n * Get max body size for monitoring.\n */\n get maxBodySize(): number {\n return this.options.monitoring.maxBodySize;\n }\n\n // ============================================\n // Public API - Monitoring (delegated to Telescope)\n // ============================================\n\n /**\n * Record a request entry.\n */\n async recordRequest(\n entry: Parameters<Telescope['recordRequest']>[0],\n ): Promise<string> {\n return this.telescope.recordRequest(entry);\n }\n\n /**\n * Record log entries in batch.\n */\n async log(entries: Parameters<Telescope['log']>[0]): Promise<void> {\n return this.telescope.log(entries);\n }\n\n /**\n * Log a debug message.\n */\n async debug(\n message: string,\n context?: Record<string, unknown>,\n requestId?: string,\n ): Promise<void> {\n return this.telescope.debug(message, context, requestId);\n }\n\n /**\n * Log an info message.\n */\n async info(\n message: string,\n context?: Record<string, unknown>,\n requestId?: string,\n ): Promise<void> {\n return this.telescope.info(message, context, requestId);\n }\n\n /**\n * Log a warning message.\n */\n async warn(\n message: string,\n context?: Record<string, unknown>,\n requestId?: string,\n ): Promise<void> {\n return this.telescope.warn(message, context, requestId);\n }\n\n /**\n * Log an error message.\n */\n async error(\n message: string,\n context?: Record<string, unknown>,\n requestId?: string,\n ): Promise<void> {\n return this.telescope.error(message, context, requestId);\n }\n\n /**\n * Record an exception.\n */\n async exception(error: Error, requestId?: string): Promise<void> {\n return this.telescope.exception(error, requestId);\n }\n\n /**\n * Get requests from storage.\n */\n async getRequests(\n options?: Parameters<Telescope['getRequests']>[0],\n ): ReturnType<Telescope['getRequests']> {\n return this.telescope.getRequests(options);\n }\n\n /**\n * Get a single request by ID.\n */\n async getRequest(id: string): ReturnType<Telescope['getRequest']> {\n return this.telescope.getRequest(id);\n }\n\n /**\n * Get exceptions from storage.\n */\n async getExceptions(\n options?: Parameters<Telescope['getExceptions']>[0],\n ): ReturnType<Telescope['getExceptions']> {\n return this.telescope.getExceptions(options);\n }\n\n /**\n * Get a single exception by ID.\n */\n async getException(id: string): ReturnType<Telescope['getException']> {\n return this.telescope.getException(id);\n }\n\n /**\n * Get logs from storage.\n */\n async getLogs(\n options?: Parameters<Telescope['getLogs']>[0],\n ): ReturnType<Telescope['getLogs']> {\n return this.telescope.getLogs(options);\n }\n\n /**\n * Get storage statistics.\n */\n async getStats(): ReturnType<Telescope['getStats']> {\n return this.telescope.getStats();\n }\n\n // ============================================\n // Public API - WebSocket\n // ============================================\n\n /**\n * Add a WebSocket client for real-time updates.\n */\n addWsClient(ws: WebSocket): void {\n this.wsClients.add(ws);\n // Also add to Telescope for monitoring events\n this.telescope.addWsClient(ws);\n }\n\n /**\n * Remove a WebSocket client.\n */\n removeWsClient(ws: WebSocket): void {\n this.wsClients.delete(ws);\n this.telescope.removeWsClient(ws);\n }\n\n /**\n * Broadcast an event to all connected WebSocket clients.\n */\n broadcast(event: StudioEvent): void {\n const data = JSON.stringify(event);\n for (const client of this.wsClients) {\n try {\n client.send(data);\n } catch {\n this.wsClients.delete(client);\n }\n }\n }\n\n // ============================================\n // Public API - Lifecycle\n // ============================================\n\n /**\n * Check if a path should be ignored for request recording.\n */\n shouldIgnore(path: string): boolean {\n // Ignore Studio's own routes\n if (path.startsWith(this.options.path)) {\n return true;\n }\n return this.telescope.shouldIgnore(path);\n }\n\n /**\n * Manually prune old monitoring entries.\n */\n async prune(olderThan: Date): Promise<number> {\n return this.telescope.prune(olderThan);\n }\n\n /**\n * Clean up resources.\n */\n destroy(): void {\n this.telescope.destroy();\n this.wsClients.clear();\n }\n\n // ============================================\n // Private Methods\n // ============================================\n\n private normalizeOptions(\n options: StudioOptions<DB>,\n ): NormalizedStudioOptions<DB> {\n const path = options.path ?? '/__studio';\n\n return {\n monitoring: {\n storage: options.monitoring.storage,\n ignorePatterns: options.monitoring.ignorePatterns ?? [],\n recordBody: options.monitoring.recordBody ?? true,\n maxBodySize: options.monitoring.maxBodySize ?? 64 * 1024,\n pruneAfterHours: options.monitoring.pruneAfterHours,\n },\n data: {\n db: options.data.db,\n cursor: options.data.cursor,\n tableCursors: options.data.tableCursors ?? {},\n excludeTables: options.data.excludeTables ?? [\n // Kysely\n 'kysely_migration',\n 'kysely_migration_lock',\n // Prisma\n '_prisma_migrations',\n // Rails/Knex\n 'schema_migrations',\n // Generic\n '_migrations',\n 'migrations',\n ],\n defaultPageSize: Math.min(options.data.defaultPageSize ?? 50, 100),\n showBinaryColumns: options.data.showBinaryColumns ?? false,\n },\n path,\n enabled: options.enabled ?? true,\n };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["options: StudioOptions<DB>","entry: Parameters<Telescope['recordRequest']>[0]","entries: Parameters<Telescope['log']>[0]","message: string","context?: Record<string, unknown>","requestId?: string","error: Error","options?: Parameters<Telescope['getRequests']>[0]","id: string","options?: Parameters<Telescope['getExceptions']>[0]","options?: Parameters<Telescope['getLogs']>[0]","options?: Parameters<Telescope['getMetrics']>[0]","options?: Parameters<Telescope['getEndpointMetrics']>[0]","method: string","path: string","options?: Parameters<Telescope['getEndpointDetails']>[2]","options?: Parameters<Telescope['getStatusDistribution']>[0]","ws: WebSocket","event: StudioEvent","olderThan: Date"],"sources":["../src/Studio.ts"],"sourcesContent":["import { Telescope } from '@geekmidas/telescope';\nimport { DataBrowser } from './data/DataBrowser';\nimport type {\n\tNormalizedStudioOptions,\n\tStudioEvent,\n\tStudioOptions,\n} from './types';\n\n/**\n * Unified development tools dashboard combining monitoring and database browsing.\n *\n * @example\n * ```typescript\n * import { Studio, Direction } from '@geekmidas/studio';\n * import { InMemoryStorage } from '@geekmidas/telescope/storage/memory';\n *\n * const studio = new Studio({\n * monitoring: {\n * storage: new InMemoryStorage(),\n * },\n * data: {\n * db: kyselyInstance,\n * cursor: { field: 'id', direction: Direction.Desc },\n * },\n * });\n * ```\n */\nexport class Studio<DB = unknown> {\n\tprivate telescope: Telescope;\n\tprivate dataBrowser: DataBrowser<DB>;\n\tprivate options: NormalizedStudioOptions<DB>;\n\tprivate wsClients = new Set<WebSocket>();\n\n\tconstructor(options: StudioOptions<DB>) {\n\t\tthis.options = this.normalizeOptions(options);\n\n\t\t// Initialize Telescope internally\n\t\tthis.telescope = new Telescope({\n\t\t\tstorage: this.options.monitoring.storage,\n\t\t\tenabled: this.options.enabled,\n\t\t\tpath: `${this.options.path}/monitoring`,\n\t\t\trecordBody: this.options.monitoring.recordBody,\n\t\t\tmaxBodySize: this.options.monitoring.maxBodySize,\n\t\t\tignorePatterns: [\n\t\t\t\t...this.options.monitoring.ignorePatterns,\n\t\t\t\t`${this.options.path}/*`, // Ignore Studio's own routes\n\t\t\t],\n\t\t\tpruneAfterHours: this.options.monitoring.pruneAfterHours,\n\t\t});\n\n\t\t// Initialize DataBrowser\n\t\tthis.dataBrowser = new DataBrowser(this.options.data);\n\t}\n\n\t// ============================================\n\t// Public API - Configuration\n\t// ============================================\n\n\t/**\n\t * Get the Studio dashboard path.\n\t */\n\tget path(): string {\n\t\treturn this.options.path;\n\t}\n\n\t/**\n\t * Check if Studio is enabled.\n\t */\n\tget enabled(): boolean {\n\t\treturn this.options.enabled;\n\t}\n\n\t/**\n\t * Get the data browser instance.\n\t */\n\tget data(): DataBrowser<DB> {\n\t\treturn this.dataBrowser;\n\t}\n\n\t/**\n\t * Check if body recording is enabled for monitoring.\n\t */\n\tget recordBody(): boolean {\n\t\treturn this.options.monitoring.recordBody;\n\t}\n\n\t/**\n\t * Get max body size for monitoring.\n\t */\n\tget maxBodySize(): number {\n\t\treturn this.options.monitoring.maxBodySize;\n\t}\n\n\t// ============================================\n\t// Public API - Monitoring (delegated to Telescope)\n\t// ============================================\n\n\t/**\n\t * Record a request entry.\n\t */\n\tasync recordRequest(\n\t\tentry: Parameters<Telescope['recordRequest']>[0],\n\t): Promise<string> {\n\t\treturn this.telescope.recordRequest(entry);\n\t}\n\n\t/**\n\t * Record log entries in batch.\n\t */\n\tasync log(entries: Parameters<Telescope['log']>[0]): Promise<void> {\n\t\treturn this.telescope.log(entries);\n\t}\n\n\t/**\n\t * Log a debug message.\n\t */\n\tasync debug(\n\t\tmessage: string,\n\t\tcontext?: Record<string, unknown>,\n\t\trequestId?: string,\n\t): Promise<void> {\n\t\treturn this.telescope.debug(message, context, requestId);\n\t}\n\n\t/**\n\t * Log an info message.\n\t */\n\tasync info(\n\t\tmessage: string,\n\t\tcontext?: Record<string, unknown>,\n\t\trequestId?: string,\n\t): Promise<void> {\n\t\treturn this.telescope.info(message, context, requestId);\n\t}\n\n\t/**\n\t * Log a warning message.\n\t */\n\tasync warn(\n\t\tmessage: string,\n\t\tcontext?: Record<string, unknown>,\n\t\trequestId?: string,\n\t): Promise<void> {\n\t\treturn this.telescope.warn(message, context, requestId);\n\t}\n\n\t/**\n\t * Log an error message.\n\t */\n\tasync error(\n\t\tmessage: string,\n\t\tcontext?: Record<string, unknown>,\n\t\trequestId?: string,\n\t): Promise<void> {\n\t\treturn this.telescope.error(message, context, requestId);\n\t}\n\n\t/**\n\t * Record an exception.\n\t */\n\tasync exception(error: Error, requestId?: string): Promise<void> {\n\t\treturn this.telescope.exception(error, requestId);\n\t}\n\n\t/**\n\t * Get requests from storage.\n\t */\n\tasync getRequests(\n\t\toptions?: Parameters<Telescope['getRequests']>[0],\n\t): ReturnType<Telescope['getRequests']> {\n\t\treturn this.telescope.getRequests(options);\n\t}\n\n\t/**\n\t * Get a single request by ID.\n\t */\n\tasync getRequest(id: string): ReturnType<Telescope['getRequest']> {\n\t\treturn this.telescope.getRequest(id);\n\t}\n\n\t/**\n\t * Get exceptions from storage.\n\t */\n\tasync getExceptions(\n\t\toptions?: Parameters<Telescope['getExceptions']>[0],\n\t): ReturnType<Telescope['getExceptions']> {\n\t\treturn this.telescope.getExceptions(options);\n\t}\n\n\t/**\n\t * Get a single exception by ID.\n\t */\n\tasync getException(id: string): ReturnType<Telescope['getException']> {\n\t\treturn this.telescope.getException(id);\n\t}\n\n\t/**\n\t * Get logs from storage.\n\t */\n\tasync getLogs(\n\t\toptions?: Parameters<Telescope['getLogs']>[0],\n\t): ReturnType<Telescope['getLogs']> {\n\t\treturn this.telescope.getLogs(options);\n\t}\n\n\t/**\n\t * Get storage statistics.\n\t */\n\tasync getStats(): ReturnType<Telescope['getStats']> {\n\t\treturn this.telescope.getStats();\n\t}\n\n\t// ============================================\n\t// Public API - Metrics (delegated to Telescope)\n\t// ============================================\n\n\t/**\n\t * Get aggregated request metrics.\n\t */\n\tgetMetrics(\n\t\toptions?: Parameters<Telescope['getMetrics']>[0],\n\t): ReturnType<Telescope['getMetrics']> {\n\t\treturn this.telescope.getMetrics(options);\n\t}\n\n\t/**\n\t * Get metrics grouped by endpoint.\n\t */\n\tgetEndpointMetrics(\n\t\toptions?: Parameters<Telescope['getEndpointMetrics']>[0],\n\t): ReturnType<Telescope['getEndpointMetrics']> {\n\t\treturn this.telescope.getEndpointMetrics(options);\n\t}\n\n\t/**\n\t * Get detailed metrics for a specific endpoint.\n\t */\n\tgetEndpointDetails(\n\t\tmethod: string,\n\t\tpath: string,\n\t\toptions?: Parameters<Telescope['getEndpointDetails']>[2],\n\t): ReturnType<Telescope['getEndpointDetails']> {\n\t\treturn this.telescope.getEndpointDetails(method, path, options);\n\t}\n\n\t/**\n\t * Get HTTP status code distribution.\n\t */\n\tgetStatusDistribution(\n\t\toptions?: Parameters<Telescope['getStatusDistribution']>[0],\n\t): ReturnType<Telescope['getStatusDistribution']> {\n\t\treturn this.telescope.getStatusDistribution(options);\n\t}\n\n\t/**\n\t * Reset all metrics.\n\t */\n\tresetMetrics(): void {\n\t\tthis.telescope.resetMetrics();\n\t}\n\n\t// ============================================\n\t// Public API - WebSocket\n\t// ============================================\n\n\t/**\n\t * Add a WebSocket client for real-time updates.\n\t */\n\taddWsClient(ws: WebSocket): void {\n\t\tthis.wsClients.add(ws);\n\t\t// Also add to Telescope for monitoring events\n\t\tthis.telescope.addWsClient(ws);\n\t}\n\n\t/**\n\t * Remove a WebSocket client.\n\t */\n\tremoveWsClient(ws: WebSocket): void {\n\t\tthis.wsClients.delete(ws);\n\t\tthis.telescope.removeWsClient(ws);\n\t}\n\n\t/**\n\t * Broadcast an event to all connected WebSocket clients.\n\t */\n\tbroadcast(event: StudioEvent): void {\n\t\tconst data = JSON.stringify(event);\n\t\tfor (const client of this.wsClients) {\n\t\t\ttry {\n\t\t\t\tclient.send(data);\n\t\t\t} catch {\n\t\t\t\tthis.wsClients.delete(client);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ============================================\n\t// Public API - Lifecycle\n\t// ============================================\n\n\t/**\n\t * Check if a path should be ignored for request recording.\n\t */\n\tshouldIgnore(path: string): boolean {\n\t\t// Ignore Studio's own routes\n\t\tif (path.startsWith(this.options.path)) {\n\t\t\treturn true;\n\t\t}\n\t\treturn this.telescope.shouldIgnore(path);\n\t}\n\n\t/**\n\t * Manually prune old monitoring entries.\n\t */\n\tasync prune(olderThan: Date): Promise<number> {\n\t\treturn this.telescope.prune(olderThan);\n\t}\n\n\t/**\n\t * Clean up resources.\n\t */\n\tdestroy(): void {\n\t\tthis.telescope.destroy();\n\t\tthis.wsClients.clear();\n\t}\n\n\t// ============================================\n\t// Private Methods\n\t// ============================================\n\n\tprivate normalizeOptions(\n\t\toptions: StudioOptions<DB>,\n\t): NormalizedStudioOptions<DB> {\n\t\tconst path = options.path ?? '/__studio';\n\n\t\treturn {\n\t\t\tmonitoring: {\n\t\t\t\tstorage: options.monitoring.storage,\n\t\t\t\tignorePatterns: options.monitoring.ignorePatterns ?? [],\n\t\t\t\trecordBody: options.monitoring.recordBody ?? true,\n\t\t\t\tmaxBodySize: options.monitoring.maxBodySize ?? 64 * 1024,\n\t\t\t\tpruneAfterHours: options.monitoring.pruneAfterHours ?? 24,\n\t\t\t},\n\t\t\tdata: {\n\t\t\t\tdb: options.data.db,\n\t\t\t\tcursor: options.data.cursor,\n\t\t\t\ttableCursors: options.data.tableCursors ?? {},\n\t\t\t\texcludeTables: options.data.excludeTables ?? [\n\t\t\t\t\t// Kysely\n\t\t\t\t\t'kysely_migration',\n\t\t\t\t\t'kysely_migration_lock',\n\t\t\t\t\t// Prisma\n\t\t\t\t\t'_prisma_migrations',\n\t\t\t\t\t// Rails/Knex\n\t\t\t\t\t'schema_migrations',\n\t\t\t\t\t// Generic\n\t\t\t\t\t'_migrations',\n\t\t\t\t\t'migrations',\n\t\t\t\t],\n\t\t\t\tdefaultPageSize: Math.min(options.data.defaultPageSize ?? 50, 100),\n\t\t\t\tshowBinaryColumns: options.data.showBinaryColumns ?? false,\n\t\t\t},\n\t\t\tpath,\n\t\t\tenabled: options.enabled ?? true,\n\t\t};\n\t}\n}\n"],"mappings":"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"}