Skip to content

@geekmidas/studio

Unified development dashboard combining request monitoring and database browsing capabilities.

Installation

bash
pnpm add @geekmidas/studio

Overview

Studio provides a comprehensive development dashboard that combines:

  • Request/exception monitoring (via Telescope integration)
  • Database schema browsing and data inspection
  • Real-time WebSocket updates

Features

  • Wraps @geekmidas/telescope for request/exception monitoring
  • Database schema introspection via Kysely
  • Cursor-based pagination for efficient data browsing
  • Filtering and sorting with multiple operators
  • WebSocket real-time updates
  • Configurable table exclusions
  • Binary column handling options

Usage

Basic Setup

typescript
import { Studio, InMemoryStorage } from '@geekmidas/studio';
import { createMiddleware, createUI } from '@geekmidas/studio/server/hono';
import { Hono } from 'hono';
import type { Database } from './db';

const studio = new Studio<Database>({
  storage: new InMemoryStorage(),
  db: kyselyInstance,
  enabled: process.env.NODE_ENV === 'development',
  excludeTables: ['migrations', 'sessions'],
});

const app = new Hono();

// Add middleware to capture requests
app.use('*', createMiddleware(studio));

// Mount the dashboard
app.route('/__studio', createUI(studio));

// Access dashboard at http://localhost:3000/__studio

With CLI Configuration

typescript
// gkm.config.ts
import { defineConfig } from '@geekmidas/cli/config';

export default defineConfig({
  routes: './src/endpoints/**/*.ts',
  envParser: './src/config/env',
  logger: './src/logger',
  studio: {
    enabled: true,
    path: '/__studio',
  },
});

// Run: gkm dev
// Studio available at http://localhost:3000/__studio

Configuration Options

typescript
interface StudioOptions<DB> {
  // Storage backend for request/exception data
  storage: TelescopeStorage;

  // Kysely database instance for browsing
  db: Kysely<DB>;

  // Enable/disable Studio
  enabled?: boolean;

  // Tables to exclude from browser
  excludeTables?: string[];

  // Maximum body size to record (bytes)
  maxBodySize?: number;

  // Auto-prune entries older than (hours)
  pruneAfterHours?: number;

  // URL patterns to ignore
  ignorePatterns?: string[];
}

Database Browser

Schema Introspection

Studio automatically discovers your database schema:

  • Table names and structure
  • Column names and types
  • Primary keys for pagination

Filtering

Support for multiple filter operators:

OperatorDescriptionExample
eqEqualsstatus eq 'active'
neqNot equalsstatus neq 'deleted'
gtGreater thanage gt 18
gteGreater or equalage gte 21
ltLess thanprice lt 100
lteLess or equalprice lte 50
containsContains stringname contains 'john'
startsWithStarts withemail startsWith 'admin'
endsWithEnds withemail endsWith '@example.com'
isNullIs nulldeleted_at isNull
isNotNullIs not nullverified_at isNotNull

Sorting

Click column headers to sort, or use the API:

GET /__studio/api/tables/users?sort=created_at&order=desc

Pagination

Cursor-based pagination for efficient large dataset handling:

GET /__studio/api/tables/users?cursor=abc123&limit=50

API Endpoints

Request Monitoring

EndpointDescription
GET /api/requestsList recorded requests
GET /api/requests/:idGet request details
GET /api/exceptionsList recorded exceptions
GET /api/exceptions/:idGet exception details
GET /api/logsList recorded logs
GET /api/statsGet summary statistics

Database Browser

EndpointDescription
GET /api/schemaGet database schema
GET /api/tables/:nameBrowse table data
GET /api/tables/:name/:idGet single record

WebSocket

Connect to /ws for real-time updates:

typescript
const ws = new WebSocket('ws://localhost:3000/__studio/ws');

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  // { type: 'request' | 'exception' | 'log', payload: ... }
};

Components

Studio Class

Main orchestrator that combines Telescope and DataBrowser:

typescript
const studio = new Studio<Database>({
  storage: new InMemoryStorage(),
  db: kyselyInstance,
});

// Record a request manually
studio.recordRequest(requestEntry);

// Record an exception
studio.recordException(exceptionEntry);

// Get database schema
const schema = await studio.getSchema();

// Browse table data
const users = await studio.browseTable('users', {
  limit: 50,
  filters: [{ column: 'status', operator: 'eq', value: 'active' }],
});

DataBrowser

Standalone database browsing component:

typescript
import { DataBrowser } from '@geekmidas/studio/data';

const browser = new DataBrowser<Database>({
  db: kyselyInstance,
  excludeTables: ['migrations'],
  schemaCacheTtl: 60000, // 1 minute
});

const tables = await browser.getTables();
const columns = await browser.getColumns('users');
const data = await browser.query('users', { limit: 100 });

See Also