@geekmidas/studio 9.0.2 → 10.0.0-alpha.1

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 (50) hide show
  1. package/package.json +8 -5
  2. package/CHANGELOG.md +0 -82
  3. package/src/Studio.ts +0 -367
  4. package/src/__tests__/Studio.spec.ts +0 -447
  5. package/src/data/DataBrowser.ts +0 -170
  6. package/src/data/__tests__/DataBrowser.integration.spec.ts +0 -418
  7. package/src/data/__tests__/filtering.integration.spec.ts +0 -741
  8. package/src/data/__tests__/introspection.integration.spec.ts +0 -352
  9. package/src/data/__tests__/pagination.spec.ts +0 -123
  10. package/src/data/filtering.ts +0 -191
  11. package/src/data/index.ts +0 -1
  12. package/src/data/introspection.ts +0 -220
  13. package/src/data/pagination.ts +0 -33
  14. package/src/index.ts +0 -29
  15. package/src/server/__tests__/hono.integration.spec.ts +0 -619
  16. package/src/server/hono.ts +0 -427
  17. package/src/types.ts +0 -278
  18. package/src/ui-assets.ts +0 -37
  19. package/tsconfig.json +0 -9
  20. package/tsdown.config.ts +0 -13
  21. package/ui/CHANGELOG.md +0 -26
  22. package/ui/index.html +0 -12
  23. package/ui/node_modules/.bin/tsc +0 -21
  24. package/ui/node_modules/.bin/tsserver +0 -21
  25. package/ui/node_modules/.bin/vite +0 -21
  26. package/ui/package.json +0 -30
  27. package/ui/src/App.tsx +0 -100
  28. package/ui/src/api.ts +0 -213
  29. package/ui/src/components/FilterPanel.tsx +0 -213
  30. package/ui/src/components/NavRail.tsx +0 -183
  31. package/ui/src/components/RowDetail.tsx +0 -119
  32. package/ui/src/components/StudioHeader.tsx +0 -109
  33. package/ui/src/components/TableList.tsx +0 -58
  34. package/ui/src/components/TableView.tsx +0 -564
  35. package/ui/src/main.tsx +0 -10
  36. package/ui/src/pages/DashboardPage.tsx +0 -500
  37. package/ui/src/pages/DatabasePage.tsx +0 -226
  38. package/ui/src/pages/EndpointDetailsPage.tsx +0 -288
  39. package/ui/src/pages/ExceptionsPage.tsx +0 -268
  40. package/ui/src/pages/LogsPage.tsx +0 -228
  41. package/ui/src/pages/MonitoringPage.tsx +0 -46
  42. package/ui/src/pages/PerformancePage.tsx +0 -307
  43. package/ui/src/pages/RequestsPage.tsx +0 -379
  44. package/ui/src/providers/StudioProvider.tsx +0 -194
  45. package/ui/src/styles.css +0 -105
  46. package/ui/src/types.ts +0 -174
  47. package/ui/src/vite-env.d.ts +0 -1
  48. package/ui/tsconfig.json +0 -21
  49. package/ui/tsconfig.tsbuildinfo +0 -1
  50. package/ui/vite.config.ts +0 -12
@@ -1,220 +0,0 @@
1
- import type { Kysely } from 'kysely';
2
- import type { ColumnInfo, ColumnType, SchemaInfo, TableInfo } from '../types';
3
-
4
- /**
5
- * Introspects the database schema to discover tables and columns.
6
- * Uses PostgreSQL information_schema for metadata.
7
- */
8
- export async function introspectSchema<DB>(
9
- db: Kysely<DB>,
10
- excludeTables: string[],
11
- ): Promise<SchemaInfo> {
12
- // Query tables from information_schema
13
- const excludePlaceholders =
14
- excludeTables.length > 0
15
- ? excludeTables.map((_, i) => `$${i + 1}`).join(', ')
16
- : "''";
17
-
18
- const tablesQuery = `
19
- SELECT
20
- table_name,
21
- table_schema
22
- FROM information_schema.tables
23
- WHERE table_schema = 'public'
24
- AND table_type = 'BASE TABLE'
25
- ${excludeTables.length > 0 ? `AND table_name NOT IN (${excludePlaceholders})` : ''}
26
- ORDER BY table_name
27
- `;
28
-
29
- const tablesResult = await db.executeQuery({
30
- sql: tablesQuery,
31
- parameters: excludeTables,
32
- } as any);
33
-
34
- const tables: TableInfo[] = [];
35
-
36
- for (const row of tablesResult.rows as any[]) {
37
- // Support both snake_case (raw) and camelCase (with CamelCasePlugin)
38
- const tableName = row.table_name ?? row.tableName;
39
- const tableSchema = row.table_schema ?? row.tableSchema;
40
- const tableInfo = await introspectTable(db, tableName, tableSchema);
41
- tables.push(tableInfo);
42
- }
43
-
44
- return {
45
- tables,
46
- updatedAt: new Date(),
47
- };
48
- }
49
-
50
- /**
51
- * Introspects a single table to get column information.
52
- */
53
- export async function introspectTable<DB>(
54
- db: Kysely<DB>,
55
- tableName: string,
56
- schema = 'public',
57
- ): Promise<TableInfo> {
58
- // Query columns
59
- const columnsQuery = `
60
- SELECT
61
- c.column_name,
62
- c.data_type,
63
- c.udt_name,
64
- c.is_nullable,
65
- c.column_default,
66
- CASE WHEN pk.column_name IS NOT NULL THEN true ELSE false END as is_primary_key
67
- FROM information_schema.columns c
68
- LEFT JOIN (
69
- SELECT ku.column_name
70
- FROM information_schema.table_constraints tc
71
- JOIN information_schema.key_column_usage ku
72
- ON tc.constraint_name = ku.constraint_name
73
- AND tc.table_schema = ku.table_schema
74
- WHERE tc.table_name = $1
75
- AND tc.table_schema = $2
76
- AND tc.constraint_type = 'PRIMARY KEY'
77
- ) pk ON c.column_name = pk.column_name
78
- WHERE c.table_name = $1
79
- AND c.table_schema = $2
80
- ORDER BY c.ordinal_position
81
- `;
82
-
83
- const columnsResult = await db.executeQuery({
84
- sql: columnsQuery,
85
- parameters: [tableName, schema],
86
- } as any);
87
-
88
- // Query foreign keys
89
- const fkQuery = `
90
- SELECT
91
- kcu.column_name,
92
- ccu.table_name AS foreign_table,
93
- ccu.column_name AS foreign_column
94
- FROM information_schema.table_constraints tc
95
- JOIN information_schema.key_column_usage kcu
96
- ON tc.constraint_name = kcu.constraint_name
97
- AND tc.table_schema = kcu.table_schema
98
- JOIN information_schema.constraint_column_usage ccu
99
- ON tc.constraint_name = ccu.constraint_name
100
- AND tc.table_schema = ccu.table_schema
101
- WHERE tc.table_name = $1
102
- AND tc.table_schema = $2
103
- AND tc.constraint_type = 'FOREIGN KEY'
104
- `;
105
-
106
- const fkResult = await db.executeQuery({
107
- sql: fkQuery,
108
- parameters: [tableName, schema],
109
- } as any);
110
-
111
- const foreignKeys = new Map<string, { table: string; column: string }>();
112
- for (const row of fkResult.rows as any[]) {
113
- // Support both snake_case (raw) and camelCase (with CamelCasePlugin)
114
- const colName = row.column_name ?? row.columnName;
115
- foreignKeys.set(colName, {
116
- table: row.foreign_table ?? row.foreignTable,
117
- column: row.foreign_column ?? row.foreignColumn,
118
- });
119
- }
120
-
121
- const columns: ColumnInfo[] = (columnsResult.rows as any[]).map((row) => {
122
- // Support both snake_case (raw) and camelCase (with CamelCasePlugin)
123
- const colName = row.column_name ?? row.columnName;
124
- const udtName = row.udt_name ?? row.udtName;
125
- const isNullable = row.is_nullable ?? row.isNullable;
126
- const isPrimaryKey = row.is_primary_key ?? row.isPrimaryKey;
127
- const columnDefault = row.column_default ?? row.columnDefault;
128
-
129
- const fk = foreignKeys.get(colName);
130
- return {
131
- name: colName,
132
- type: mapPostgresType(udtName),
133
- rawType: udtName,
134
- nullable: isNullable === 'YES',
135
- isPrimaryKey: isPrimaryKey,
136
- isForeignKey: !!fk,
137
- foreignKeyTable: fk?.table,
138
- foreignKeyColumn: fk?.column,
139
- defaultValue: columnDefault ?? undefined,
140
- };
141
- });
142
-
143
- const primaryKey = columns.filter((c) => c.isPrimaryKey).map((c) => c.name);
144
-
145
- // Get estimated row count
146
- const countQuery = `
147
- SELECT reltuples::bigint AS estimate
148
- FROM pg_class
149
- WHERE relname = $1
150
- `;
151
-
152
- let estimatedRowCount: number | undefined;
153
- try {
154
- const countResult = await db.executeQuery({
155
- sql: countQuery,
156
- parameters: [tableName],
157
- } as any);
158
- if (countResult.rows.length > 0) {
159
- const estimate = (countResult.rows[0] as any).estimate;
160
- estimatedRowCount = estimate > 0 ? Number(estimate) : undefined;
161
- }
162
- } catch {
163
- // Ignore errors, row count is optional
164
- }
165
-
166
- return {
167
- name: tableName,
168
- schema,
169
- columns,
170
- primaryKey,
171
- estimatedRowCount,
172
- };
173
- }
174
-
175
- /**
176
- * Maps PostgreSQL types to generic column types.
177
- */
178
- function mapPostgresType(udtName: string): ColumnType {
179
- const typeMap: Record<string, ColumnType> = {
180
- // Strings
181
- varchar: 'string',
182
- char: 'string',
183
- text: 'string',
184
- name: 'string',
185
- bpchar: 'string',
186
-
187
- // Numbers
188
- int2: 'number',
189
- int4: 'number',
190
- int8: 'number',
191
- float4: 'number',
192
- float8: 'number',
193
- numeric: 'number',
194
- money: 'number',
195
- serial: 'number',
196
- bigserial: 'number',
197
-
198
- // Boolean
199
- bool: 'boolean',
200
-
201
- // Dates
202
- date: 'date',
203
- timestamp: 'datetime',
204
- timestamptz: 'datetime',
205
- time: 'datetime',
206
- timetz: 'datetime',
207
-
208
- // JSON
209
- json: 'json',
210
- jsonb: 'json',
211
-
212
- // Binary
213
- bytea: 'binary',
214
-
215
- // UUID
216
- uuid: 'uuid',
217
- };
218
-
219
- return typeMap[udtName] ?? 'unknown';
220
- }
@@ -1,33 +0,0 @@
1
- /**
2
- * Cursor encoding/decoding utilities for pagination.
3
- */
4
-
5
- /**
6
- * Encode a cursor value for safe URL transmission.
7
- * Supports various types: string, number, Date, etc.
8
- */
9
- export function encodeCursor(value: unknown): string {
10
- const payload = {
11
- v: value instanceof Date ? value.toISOString() : value,
12
- t: value instanceof Date ? 'date' : typeof value,
13
- };
14
- return Buffer.from(JSON.stringify(payload)).toString('base64url');
15
- }
16
-
17
- /**
18
- * Decode a cursor string back to its original value.
19
- */
20
- export function decodeCursor(cursor: string): unknown {
21
- try {
22
- const json = Buffer.from(cursor, 'base64url').toString('utf-8');
23
- const payload = JSON.parse(json);
24
-
25
- if (payload.t === 'date') {
26
- return new Date(payload.v);
27
- }
28
-
29
- return payload.v;
30
- } catch {
31
- throw new Error('Invalid cursor format');
32
- }
33
- }
package/src/index.ts DELETED
@@ -1,29 +0,0 @@
1
- // Core
2
-
3
- // Re-export Telescope storage types for convenience
4
- // Users should import storage from @geekmidas/studio, not @geekmidas/telescope
5
- export type { TelescopeStorage as MonitoringStorage } from '@geekmidas/telescope';
6
- // Re-export InMemoryStorage as InMemoryMonitoringStorage
7
- export { InMemoryStorage as InMemoryMonitoringStorage } from '@geekmidas/telescope/storage/memory';
8
- export { Studio } from './Studio';
9
- // Types
10
- export {
11
- type ColumnInfo,
12
- type ColumnType,
13
- type CursorConfig,
14
- type DataBrowserOptions,
15
- Direction,
16
- type FilterCondition,
17
- FilterOperator,
18
- type MonitoringOptions,
19
- type NormalizedStudioOptions,
20
- type QueryOptions,
21
- type QueryResult,
22
- type SchemaInfo,
23
- type SortConfig,
24
- type StudioEvent,
25
- type StudioEventType,
26
- type StudioOptions,
27
- type TableCursorConfig,
28
- type TableInfo,
29
- } from './types';