@rebasepro/studio 0.17.3 → 0.18.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 (81) hide show
  1. package/LICENSE +0 -1
  2. package/README.md +12 -4
  3. package/dist/{ApiKeysView-DiCurTEU.js → ApiKeysView-EIvegrUk.js} +54 -39
  4. package/dist/ApiKeysView-EIvegrUk.js.map +1 -0
  5. package/dist/{BackupsView-DNS6LdVg.js → BackupsView-DVkKzaPR.js} +29 -31
  6. package/dist/BackupsView-DVkKzaPR.js.map +1 -0
  7. package/dist/{BranchesView-CM3B-ER3.js → BranchesView-Df8hQ8wE.js} +85 -24
  8. package/dist/BranchesView-Df8hQ8wE.js.map +1 -0
  9. package/dist/{CronJobsView-BHtJZeJZ.js → CronJobsView-CLOGjb-L.js} +32 -27
  10. package/dist/CronJobsView-CLOGjb-L.js.map +1 -0
  11. package/dist/{RLSEditor-CBX4uD66.js → RLSEditor-Sa1D34ny.js} +724 -615
  12. package/dist/RLSEditor-Sa1D34ny.js.map +1 -0
  13. package/dist/{SQLEditor-ByecwX8B.js → SQLEditor-BfNA8xM3.js} +9 -4
  14. package/dist/{SQLEditor-ByecwX8B.js.map → SQLEditor-BfNA8xM3.js.map} +1 -1
  15. package/dist/{SchemaVisualizer-D6tMZgeC.js → SchemaVisualizer-DTDMYL6o.js} +84 -110
  16. package/dist/SchemaVisualizer-DTDMYL6o.js.map +1 -0
  17. package/dist/{StorageView-BGDeC5GI.js → StorageView-Ed9Q_VlB.js} +5 -32
  18. package/dist/StorageView-Ed9Q_VlB.js.map +1 -0
  19. package/dist/components/RLSEditor/saveRules.d.ts +38 -0
  20. package/dist/components/RebaseStudio.d.ts +1 -1
  21. package/dist/components/SchemaVisualizer/schema-visualizer.utils.d.ts +5 -2
  22. package/dist/components/SchemaVisualizer/useSchemaGraph.d.ts +0 -4
  23. package/dist/components/load-failure-view.d.ts +17 -0
  24. package/dist/components/load-failure.d.ts +47 -0
  25. package/dist/index.es.js +56 -36
  26. package/dist/index.es.js.map +1 -1
  27. package/dist/load-failure-C6OMJSGC.js +31 -0
  28. package/dist/load-failure-C6OMJSGC.js.map +1 -0
  29. package/dist/load-failure-view-CBTB_h-h.js +48 -0
  30. package/dist/load-failure-view-CBTB_h-h.js.map +1 -0
  31. package/package.json +36 -21
  32. package/dist/ApiKeysView-DiCurTEU.js.map +0 -1
  33. package/dist/BackupsView-DNS6LdVg.js.map +0 -1
  34. package/dist/BranchesView-CM3B-ER3.js.map +0 -1
  35. package/dist/CronJobsView-BHtJZeJZ.js.map +0 -1
  36. package/dist/RLSEditor-CBX4uD66.js.map +0 -1
  37. package/dist/SchemaVisualizer-D6tMZgeC.js.map +0 -1
  38. package/dist/StorageView-BGDeC5GI.js.map +0 -1
  39. package/dist/components/StorageView/storage-failure.d.ts +0 -34
  40. package/src/components/ApiExplorer/ApiExplorer.tsx +0 -299
  41. package/src/components/ApiExplorer/EndpointDetail.tsx +0 -279
  42. package/src/components/ApiExplorer/TryItPanel.tsx +0 -499
  43. package/src/components/ApiExplorer/parseSpec.ts +0 -104
  44. package/src/components/ApiExplorer/types.ts +0 -84
  45. package/src/components/ApiKeys/ApiKeysView.tsx +0 -479
  46. package/src/components/ApiKeys/CreateApiKeyDialog.tsx +0 -711
  47. package/src/components/ApiKeys/permissions.ts +0 -145
  48. package/src/components/AuthSimulationSelector.tsx +0 -72
  49. package/src/components/Backups/BackupsView.tsx +0 -185
  50. package/src/components/Branches/BranchesView.tsx +0 -386
  51. package/src/components/CronJobs/CronJobsView.tsx +0 -413
  52. package/src/components/JSEditor/JSEditor.tsx +0 -1100
  53. package/src/components/JSEditor/JSEditorSidebar.tsx +0 -350
  54. package/src/components/JSEditor/JSMonacoEditor.tsx +0 -410
  55. package/src/components/LogsExplorer/LogsExplorer.tsx +0 -273
  56. package/src/components/LogsExplorer/useLogTail.ts +0 -356
  57. package/src/components/RLSEditor/PolicyEditor.tsx +0 -399
  58. package/src/components/RLSEditor/RLSEditor.tsx +0 -1128
  59. package/src/components/RLSEditor/index.ts +0 -1
  60. package/src/components/RLSEditor/policy-presets.ts +0 -176
  61. package/src/components/RLSEditor/saveSecurityRules.ts +0 -48
  62. package/src/components/RebaseStudio.tsx +0 -174
  63. package/src/components/SQLEditor/ExplainVisualizer.tsx +0 -128
  64. package/src/components/SQLEditor/MonacoEditor.tsx +0 -203
  65. package/src/components/SQLEditor/SQLEditor.tsx +0 -1518
  66. package/src/components/SQLEditor/SQLEditorSidebar.tsx +0 -173
  67. package/src/components/SQLEditor/SchemaBrowser.tsx +0 -168
  68. package/src/components/SQLEditor/sql_editor_types.ts +0 -18
  69. package/src/components/SchemaVisualizer/RelationEdge.tsx +0 -102
  70. package/src/components/SchemaVisualizer/SchemaVisualizer.tsx +0 -710
  71. package/src/components/SchemaVisualizer/TableNode.tsx +0 -257
  72. package/src/components/SchemaVisualizer/schema-visualizer.utils.ts +0 -140
  73. package/src/components/SchemaVisualizer/useLiveRls.ts +0 -86
  74. package/src/components/SchemaVisualizer/useSchemaGraph.ts +0 -426
  75. package/src/components/StorageView/StorageView.tsx +0 -1588
  76. package/src/components/StorageView/storage-failure.ts +0 -63
  77. package/src/components/StudioHomePage.tsx +0 -430
  78. package/src/index.ts +0 -31
  79. package/src/utils/parseSpec.test.ts +0 -309
  80. package/src/utils/sql_utils.test.ts +0 -265
  81. package/src/utils/sql_utils.ts +0 -291
@@ -1,291 +0,0 @@
1
- import { parseFirst } from "pgsql-ast-parser";
2
- import type { TableInfo } from "../components/SQLEditor/sql_editor_types";
3
-
4
- /**
5
- * A table extracted from a SQL query's FROM/JOIN clauses.
6
- */
7
- export interface ExtractedTable {
8
- name: string;
9
- alias?: string;
10
- }
11
-
12
- /**
13
- * A collection matched to a table in a SQL query.
14
- */
15
- export interface ResolvedQueryCollection {
16
- /** DB table name from the SQL AST (e.g. "blog_posts") */
17
- tableName: string;
18
- /** SQL alias if present (e.g. "bp") */
19
- tableAlias?: string;
20
- /** The matched collection */
21
- collection: AdminCollection;
22
- /** Columns from this table that are present in the result set */
23
- columns: string[];
24
- /** The result column name that holds the primary key for this table (e.g. "id", "author_id") */
25
- pkColumn?: string;
26
- }
27
-
28
- /**
29
- * Extract all tables referenced in a SQL query's FROM and JOIN clauses.
30
- * Returns an empty array for non-SELECT queries or parse failures.
31
- */
32
- export function extractTablesFromQuery(sqlString: string): ExtractedTable[] {
33
- try {
34
- const ast = parseFirst(sqlString);
35
- if (ast.type !== "select") return [];
36
-
37
- const tables: ExtractedTable[] = [];
38
-
39
- // pgsql-ast-parser From items — tables and joins with left/right branches
40
- type FromNode = { type: string; name?: { name: string; alias?: string }; left?: FromNode; right?: FromNode };
41
- const processFrom = (fromItems: FromNode[]) => {
42
- for (const item of fromItems) {
43
- if (item.type === "table" && item.name) {
44
- tables.push({ name: item.name.name,
45
- alias: item.name.alias });
46
- }
47
- if (item.type === "join") {
48
- if (item.left) processFrom([item.left]);
49
- if (item.right) processFrom([item.right]);
50
- }
51
- }
52
- };
53
-
54
- if (ast.from) {
55
- processFrom(ast.from);
56
- }
57
-
58
- return tables;
59
- } catch {
60
- return [];
61
- }
62
- }
63
-
64
- import { toSnakeCase } from "@rebasepro/utils";
65
- import type { AdminCollection } from "@rebasepro/cms-types";
66
-
67
- /**
68
- * Resolve which collections are referenced by a SQL query.
69
- *
70
- * Parses the SQL, extracts table names, and matches each against
71
- * registered collections via `collection.table` (falling back to
72
- * snake_case of `collection.slug`).
73
- *
74
- * For each matched collection, determines which result columns
75
- * belong to that table using the database schema information.
76
- */
77
- export function resolveQueryCollections(
78
- sqlString: string,
79
- schemas: Record<string, TableInfo[]>,
80
- collections: AdminCollection[],
81
- resultColumns?: string[]
82
- ): ResolvedQueryCollection[] {
83
- const tables = extractTablesFromQuery(sqlString);
84
- if (tables.length === 0) return [];
85
-
86
- // Parse the AST to resolve SELECT column aliases
87
- const selectColumns: { table?: string; column: string; alias?: string }[] = [];
88
- try {
89
- const ast = parseFirst(sqlString);
90
- if (ast.type === "select" && ast.columns) {
91
- for (const col of ast.columns) {
92
- if (col.expr?.type === "ref") {
93
- selectColumns.push({
94
- table: col.expr.table?.name,
95
- column: col.expr.name,
96
- alias: col.alias?.name
97
- });
98
- }
99
- }
100
- }
101
- } catch { /* parse failure is ok, we'll fall back */ }
102
-
103
- const results: ResolvedQueryCollection[] = [];
104
-
105
- for (const table of tables) {
106
- // Match table name against collection table or slug->snake_case
107
- const matched = collections.find(c => {
108
- const tableName = ("table" in c ? c.table : undefined) || toSnakeCase(c.slug);
109
- return tableName === table.name;
110
- });
111
-
112
- if (!matched) continue;
113
-
114
- // Find columns belonging to this table from the schema
115
- const tableColumns: string[] = [];
116
- for (const schemaEntries of Object.values(schemas)) {
117
- const tableInfo = schemaEntries.find(t => t.tableName === table.name);
118
- if (tableInfo) {
119
- tableColumns.push(...tableInfo.columns.map(c => c.name));
120
- break;
121
- }
122
- }
123
-
124
- // Determine which result column holds the PK ("id") for this table.
125
- // 1. Check parsed SELECT columns for an explicit "id" column from this table (by name or alias)
126
- // 2. Fall back to checking if result columns contain "id"
127
- let pkColumn: string | undefined;
128
-
129
- // Look in the AST select columns for `table.id` or `alias.id`
130
- const tableRef = table.alias || table.name;
131
- const idSelectCol = selectColumns.find(
132
- sc => sc.column === "id" && (!sc.table || sc.table === tableRef || sc.table === table.name)
133
- );
134
- if (idSelectCol) {
135
- pkColumn = idSelectCol.alias || idSelectCol.column; // use alias if present
136
- }
137
-
138
- // If we didn't find it from the AST (e.g. SELECT *), check if result columns have "id"
139
- if (!pkColumn && resultColumns) {
140
- if (resultColumns.includes("id")) {
141
- pkColumn = "id";
142
- }
143
- }
144
-
145
- // If still not found, fall back to checking tableColumns
146
- if (!pkColumn && tableColumns.includes("id")) {
147
- pkColumn = "id";
148
- }
149
-
150
- results.push({
151
- tableName: table.name,
152
- tableAlias: table.alias,
153
- collection: matched,
154
- columns: tableColumns,
155
- pkColumn
156
- });
157
- }
158
-
159
- return results;
160
- }
161
-
162
- export interface PKMapping {
163
- /** The actual column name in the database table */
164
- dbColumn: string;
165
- /** The column name as it appears in the query result set (may be aliased) */
166
- resultColumn: string;
167
- }
168
-
169
- export interface TableAndPKResult {
170
- tableName?: string;
171
- primaryKeys?: PKMapping[];
172
- error?: string;
173
- }
174
-
175
- export function determineTableAndPK(sqlString: string, columnKey: string, schemas: Record<string, TableInfo[]>): TableAndPKResult {
176
- try {
177
- const tables = extractTablesFromQuery(sqlString);
178
-
179
- const ast = parseFirst(sqlString);
180
- if (ast.type !== "select") {
181
- return { error: "Inline editing is only supported for SELECT queries." };
182
- }
183
-
184
- if (tables.length === 0) {
185
- return { error: "Could not find any tables in the query." };
186
- }
187
-
188
- // Parse SELECT columns to resolve aliases
189
- const selectColumns: { table?: string; column: string; alias?: string }[] = [];
190
- if (ast.columns) {
191
- for (const col of ast.columns) {
192
- if (col.expr?.type === "ref") {
193
- selectColumns.push({
194
- table: col.expr.table?.name,
195
- column: col.expr.name,
196
- alias: col.alias?.name
197
- });
198
- }
199
- }
200
- }
201
-
202
- // Resolve which DB column `columnKey` refers to (it might be aliased)
203
- const resolvedColumn = selectColumns.find(
204
- sc => (sc.alias === columnKey) || (!sc.alias && sc.column === columnKey)
205
- );
206
- const actualDbColumnName = resolvedColumn?.column ?? columnKey;
207
- const columnTableRef = resolvedColumn?.table; // e.g. "p" or "posts"
208
-
209
- // Resolve the table for the edited column
210
- let resolvedTableName: string | null = null;
211
-
212
- if (tables.length === 1) {
213
- resolvedTableName = tables[0].name;
214
- } else {
215
- // If the AST tells us which table, use that
216
- if (columnTableRef) {
217
- const matchedTable = tables.find(
218
- t => t.alias === columnTableRef || t.name === columnTableRef
219
- );
220
- if (matchedTable) {
221
- resolvedTableName = matchedTable.name;
222
- }
223
- }
224
-
225
- // Otherwise, look up which schema table has this column
226
- if (!resolvedTableName) {
227
- const matchedTables = tables.filter(t => {
228
- for (const schema of Object.values(schemas)) {
229
- const tableInfo = schema.find(ti => ti.tableName === t.name);
230
- if (tableInfo && tableInfo.columns.some(c => c.name === actualDbColumnName)) {
231
- return true;
232
- }
233
- }
234
- return false;
235
- });
236
-
237
- if (matchedTables.length === 1) {
238
- resolvedTableName = matchedTables[0].name;
239
- } else if (matchedTables.length > 1) {
240
- return { error: `Ambiguous column "${columnKey}": Found in multiple queried tables.` };
241
- } else {
242
- return { error: `Could not find column "${columnKey}" in the queried tables.` };
243
- }
244
- }
245
- }
246
-
247
- if (!resolvedTableName) {
248
- return { error: "Could not resolve the target table." };
249
- }
250
-
251
- // Find the table's actual primary key columns from the schema
252
- let pkDbColumns: string[] = [];
253
- for (const schema of Object.values(schemas)) {
254
- const tableInfo = schema.find(t => t.tableName === resolvedTableName);
255
- if (tableInfo) {
256
- pkDbColumns = tableInfo.columns
257
- .filter(c => c.isPrimaryKey)
258
- .map(c => c.name);
259
- break;
260
- }
261
- }
262
-
263
- if (pkDbColumns.length === 0) {
264
- return { error: `Table "${resolvedTableName}" has no primary key defined.` };
265
- }
266
-
267
- // Find the table's alias in the query (for resolving PK result column names)
268
- const tableEntry = tables.find(t => t.name === resolvedTableName);
269
- const tableAlias = tableEntry?.alias;
270
-
271
- // Map each PK db column to its result column name (resolving aliases)
272
- const primaryKeys: PKMapping[] = pkDbColumns.map(dbCol => {
273
- // Find the SELECT column for this PK
274
- const selectCol = selectColumns.find(
275
- sc => sc.column === dbCol &&
276
- (!sc.table || sc.table === (tableAlias || resolvedTableName))
277
- );
278
- return {
279
- dbColumn: dbCol,
280
- resultColumn: selectCol?.alias || selectCol?.column || dbCol
281
- };
282
- });
283
-
284
- return { tableName: resolvedTableName,
285
- primaryKeys };
286
- } catch (e: unknown) {
287
- console.warn("Failed to parse SQL AST:", e);
288
- const message = e instanceof Error ? e.message : String(e);
289
- return { error: `Could not safely parse query for inline editing: ${message}` };
290
- }
291
- }