@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.
- package/package.json +8 -5
- package/CHANGELOG.md +0 -82
- package/src/Studio.ts +0 -367
- package/src/__tests__/Studio.spec.ts +0 -447
- package/src/data/DataBrowser.ts +0 -170
- package/src/data/__tests__/DataBrowser.integration.spec.ts +0 -418
- package/src/data/__tests__/filtering.integration.spec.ts +0 -741
- package/src/data/__tests__/introspection.integration.spec.ts +0 -352
- package/src/data/__tests__/pagination.spec.ts +0 -123
- package/src/data/filtering.ts +0 -191
- package/src/data/index.ts +0 -1
- package/src/data/introspection.ts +0 -220
- package/src/data/pagination.ts +0 -33
- package/src/index.ts +0 -29
- package/src/server/__tests__/hono.integration.spec.ts +0 -619
- package/src/server/hono.ts +0 -427
- package/src/types.ts +0 -278
- package/src/ui-assets.ts +0 -37
- package/tsconfig.json +0 -9
- package/tsdown.config.ts +0 -13
- package/ui/CHANGELOG.md +0 -26
- package/ui/index.html +0 -12
- package/ui/node_modules/.bin/tsc +0 -21
- package/ui/node_modules/.bin/tsserver +0 -21
- package/ui/node_modules/.bin/vite +0 -21
- package/ui/package.json +0 -30
- package/ui/src/App.tsx +0 -100
- package/ui/src/api.ts +0 -213
- package/ui/src/components/FilterPanel.tsx +0 -213
- package/ui/src/components/NavRail.tsx +0 -183
- package/ui/src/components/RowDetail.tsx +0 -119
- package/ui/src/components/StudioHeader.tsx +0 -109
- package/ui/src/components/TableList.tsx +0 -58
- package/ui/src/components/TableView.tsx +0 -564
- package/ui/src/main.tsx +0 -10
- package/ui/src/pages/DashboardPage.tsx +0 -500
- package/ui/src/pages/DatabasePage.tsx +0 -226
- package/ui/src/pages/EndpointDetailsPage.tsx +0 -288
- package/ui/src/pages/ExceptionsPage.tsx +0 -268
- package/ui/src/pages/LogsPage.tsx +0 -228
- package/ui/src/pages/MonitoringPage.tsx +0 -46
- package/ui/src/pages/PerformancePage.tsx +0 -307
- package/ui/src/pages/RequestsPage.tsx +0 -379
- package/ui/src/providers/StudioProvider.tsx +0 -194
- package/ui/src/styles.css +0 -105
- package/ui/src/types.ts +0 -174
- package/ui/src/vite-env.d.ts +0 -1
- package/ui/tsconfig.json +0 -21
- package/ui/tsconfig.tsbuildinfo +0 -1
- 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
|
-
}
|
package/src/data/pagination.ts
DELETED
|
@@ -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';
|