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 ​