@rebasepro/studio 0.8.0 → 0.9.1-canary.09aaf62

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 (78) hide show
  1. package/README.md +4 -4
  2. package/dist/{ApiExplorer-CdIwR9Ga.js → ApiExplorer-B9M9-uy_.js} +3 -3
  3. package/dist/ApiExplorer-B9M9-uy_.js.map +1 -0
  4. package/dist/{ApiKeysView-D-_FSlNL.js → ApiKeysView-vQKqt2wl.js} +45 -3
  5. package/dist/ApiKeysView-vQKqt2wl.js.map +1 -0
  6. package/dist/{AuthSimulationSelector-iEZ-Or_1.js → AuthSimulationSelector-Bougd521.js} +2 -2
  7. package/dist/AuthSimulationSelector-Bougd521.js.map +1 -0
  8. package/dist/BackupsView-DNS6LdVg.js +227 -0
  9. package/dist/BackupsView-DNS6LdVg.js.map +1 -0
  10. package/dist/{BranchesView-Dlg78EQ8.js → BranchesView-DH0qnU9J.js} +2 -2
  11. package/dist/BranchesView-DH0qnU9J.js.map +1 -0
  12. package/dist/{CronJobsView-4gdtJvoe.js → CronJobsView-B59i3Mis.js} +2 -2
  13. package/dist/CronJobsView-B59i3Mis.js.map +1 -0
  14. package/dist/{JSEditor-Ca4XYGRp.js → JSEditor-BeHHuxhA.js} +28 -32
  15. package/dist/JSEditor-BeHHuxhA.js.map +1 -0
  16. package/dist/LogsExplorer-BCXoGREr.js +298 -0
  17. package/dist/LogsExplorer-BCXoGREr.js.map +1 -0
  18. package/dist/{MonacoEditor-COZqrIJ1.js → MonacoEditor-D0_QljcX.js} +2 -2
  19. package/dist/MonacoEditor-D0_QljcX.js.map +1 -0
  20. package/dist/{RLSEditor-BM64laoW.js → RLSEditor-D6adwB6e.js} +38 -34
  21. package/dist/RLSEditor-D6adwB6e.js.map +1 -0
  22. package/dist/{SQLEditor-CuAhR-zr.js → SQLEditor-_dCqVAN_.js} +8 -8
  23. package/dist/SQLEditor-_dCqVAN_.js.map +1 -0
  24. package/dist/{SchemaVisualizer-OibKoD3g.js → SchemaVisualizer-C_ErehfH.js} +11 -11
  25. package/dist/SchemaVisualizer-C_ErehfH.js.map +1 -0
  26. package/dist/{StorageView-BMhD29YO.js → StorageView-UvyM2xdW.js} +2 -2
  27. package/dist/StorageView-UvyM2xdW.js.map +1 -0
  28. package/dist/components/AuthSimulationSelector.d.ts +1 -1
  29. package/dist/components/Backups/BackupsView.d.ts +2 -0
  30. package/dist/components/SchemaVisualizer/useSchemaGraph.d.ts +2 -2
  31. package/dist/index.d.ts +2 -2
  32. package/dist/index.es.js +74 -111
  33. package/dist/index.es.js.map +1 -1
  34. package/dist/utils/pgColumnToProperty.d.ts +3 -3
  35. package/dist/utils/sql_utils.d.ts +3 -3
  36. package/package.json +11 -12
  37. package/src/components/ApiExplorer/ApiExplorer.tsx +1 -1
  38. package/src/components/ApiExplorer/TryItPanel.tsx +1 -1
  39. package/src/components/ApiKeys/ApiKeysView.tsx +43 -3
  40. package/src/components/AuthSimulationSelector.tsx +1 -1
  41. package/src/components/Backups/BackupsView.tsx +185 -0
  42. package/src/components/Branches/BranchesView.tsx +1 -1
  43. package/src/components/CronJobs/CronJobsView.tsx +1 -1
  44. package/src/components/JSEditor/JSEditor.tsx +12 -12
  45. package/src/components/JSEditor/JSMonacoEditor.tsx +21 -25
  46. package/src/components/LogsExplorer/LogsExplorer.tsx +168 -46
  47. package/src/components/RLSEditor/PolicyEditor.tsx +5 -3
  48. package/src/components/RLSEditor/RLSEditor.tsx +51 -34
  49. package/src/components/RebaseStudio.tsx +12 -3
  50. package/src/components/SQLEditor/MonacoEditor.tsx +1 -1
  51. package/src/components/SQLEditor/SQLEditor.tsx +6 -6
  52. package/src/components/SQLEditor/SQLEditorSidebar.tsx +1 -1
  53. package/src/components/SQLEditor/SchemaBrowser.tsx +3 -3
  54. package/src/components/SchemaVisualizer/SchemaVisualizer.tsx +10 -9
  55. package/src/components/SchemaVisualizer/TableNode.tsx +1 -1
  56. package/src/components/SchemaVisualizer/useSchemaGraph.ts +11 -11
  57. package/src/components/StorageView/StorageView.tsx +1 -1
  58. package/src/components/StudioHomePage.tsx +62 -87
  59. package/src/index.ts +4 -4
  60. package/src/utils/pgColumnToProperty.ts +3 -3
  61. package/src/utils/sql_utils.test.ts +6 -6
  62. package/src/utils/sql_utils.ts +3 -3
  63. package/dist/ApiExplorer-CdIwR9Ga.js.map +0 -1
  64. package/dist/ApiKeysView-D-_FSlNL.js.map +0 -1
  65. package/dist/AuthSimulationSelector-iEZ-Or_1.js.map +0 -1
  66. package/dist/BranchesView-Dlg78EQ8.js.map +0 -1
  67. package/dist/CronJobsView-4gdtJvoe.js.map +0 -1
  68. package/dist/JSEditor-Ca4XYGRp.js.map +0 -1
  69. package/dist/LogsExplorer-J4xfsuv3.js +0 -206
  70. package/dist/LogsExplorer-J4xfsuv3.js.map +0 -1
  71. package/dist/MonacoEditor-COZqrIJ1.js.map +0 -1
  72. package/dist/RLSEditor-BM64laoW.js.map +0 -1
  73. package/dist/SQLEditor-CuAhR-zr.js.map +0 -1
  74. package/dist/SchemaVisualizer-OibKoD3g.js.map +0 -1
  75. package/dist/StorageView-BMhD29YO.js.map +0 -1
  76. package/dist/index.umd.js +0 -11491
  77. package/dist/index.umd.js.map +0 -1
  78. package/src/vite-env.d.ts +0 -1
@@ -28,9 +28,9 @@ import {
28
28
  import {
29
29
  useStudioCollectionRegistry,
30
30
  IconForView
31
- } from "@rebasepro/core";
32
- import type { EntityCollection } from "@rebasepro/types";
33
- import { isPostgresCollection } from "@rebasepro/types";
31
+ } from "@rebasepro/app";
32
+ import type { CollectionConfig } from "@rebasepro/types";
33
+ import { isPostgresCollectionConfig } from "@rebasepro/types";
34
34
  import { useSchemaGraph } from "./useSchemaGraph";
35
35
  import type { TableNodeData } from "./useSchemaGraph";
36
36
  import { TableNode } from "./TableNode";
@@ -52,7 +52,7 @@ const edgeTypes = {
52
52
  function SchemaVisualizerCanvas({
53
53
  collections
54
54
  }: {
55
- collections: EntityCollection[];
55
+ collections: CollectionConfig[];
56
56
  }) {
57
57
  const reactFlowInstance = useReactFlow();
58
58
  const {
@@ -152,7 +152,7 @@ duration: 400 }
152
152
 
153
153
  // Group collections for sidebar
154
154
  const postgresCollections = useMemo(
155
- () => collections.filter(isPostgresCollection),
155
+ () => collections.filter(isPostgresCollectionConfig),
156
156
  [collections]
157
157
  );
158
158
 
@@ -184,7 +184,7 @@ duration: 400 }
184
184
  junctions: junctionNodes.length,
185
185
  withRls: postgresCollections.filter(
186
186
  (c) =>
187
- isPostgresCollection(c) &&
187
+ isPostgresCollectionConfig(c) &&
188
188
  c.securityRules &&
189
189
  c.securityRules.length > 0
190
190
  ).length
@@ -293,7 +293,7 @@ duration: 400 }
293
293
  )}
294
294
  </div>
295
295
  <div className="flex items-center gap-1 shrink-0 ml-1">
296
- {isPostgresCollection(collection) &&
296
+ {isPostgresCollectionConfig(collection) &&
297
297
  collection.securityRules &&
298
298
  collection.securityRules
299
299
  .length > 0 && (
@@ -543,7 +543,8 @@ duration: 400 }
543
543
  />
544
544
  <Controls
545
545
  showInteractive={false}
546
- className="!bg-white dark:!bg-surface-900 !border !border-surface-200/40 dark:!border-surface-700/40 !shadow-sm !rounded-lg"
546
+ // mb clears the legend overlay pinned at bottom-left
547
+ className="!mb-16 !bg-white dark:!bg-surface-900 !border !border-surface-200/40 dark:!border-surface-700/40 !shadow-sm !rounded-lg dark:[--xy-controls-button-background-color:var(--color-surface-900)] dark:[--xy-controls-button-background-color-hover:var(--color-surface-800)] dark:[--xy-controls-button-color:var(--color-surface-300)] dark:[--xy-controls-button-color-hover:var(--color-surface-50)] dark:[--xy-controls-button-border-color:var(--color-surface-700)]"
547
548
  />
548
549
  <MiniMap
549
550
  nodeStrokeColor={(n) => {
@@ -629,7 +630,7 @@ duration: 400 }
629
630
  export const SchemaVisualizer = () => {
630
631
  const { collections: registryCollections } =
631
632
  useStudioCollectionRegistry() as {
632
- collections?: EntityCollection[];
633
+ collections?: CollectionConfig[];
633
634
  };
634
635
 
635
636
  // Merge registry collections with any passed collections
@@ -2,7 +2,7 @@ import React, { memo, useMemo } from "react";
2
2
  import { Handle, Position } from "@xyflow/react";
3
3
  import type { NodeProps } from "@xyflow/react";
4
4
  import { Typography, Chip, Tooltip, cls } from "@rebasepro/ui";
5
- import { IconForView } from "@rebasepro/core";
5
+ import { IconForView } from "@rebasepro/app";
6
6
  import type { TableNodeData, ColumnInfo } from "./useSchemaGraph";
7
7
  import { getColumnRowY, getHeaderHeight } from "./schema-visualizer.utils";
8
8
 
@@ -1,8 +1,8 @@
1
1
  import { useMemo, useState, useCallback, useEffect } from "react";
2
2
  import type { Node, Edge } from "@xyflow/react";
3
3
  import { MarkerType } from "@xyflow/react";
4
- import { isPostgresCollection } from "@rebasepro/types";
5
- import type { EntityCollection, PostgresCollection, Relation } from "@rebasepro/types";
4
+ import { isPostgresCollectionConfig } from "@rebasepro/types";
5
+ import type { CollectionConfig, PostgresCollectionConfig, Relation } from "@rebasepro/types";
6
6
  import { resolveCollectionRelations } from "@rebasepro/common";
7
7
  import { getLayoutedElements, getCardinalityLabel, getTypeLabel, NODE_WIDTH } from "./schema-visualizer.utils";
8
8
  import type { LayoutDirection, RelationEdgeData } from "./schema-visualizer.utils";
@@ -36,9 +36,9 @@ export interface TableNodeData {
36
36
  [key: string]: unknown;
37
37
  }
38
38
 
39
- // ─── Extract columns from an EntityCollection ─────────────────────────
39
+ // ─── Extract columns from a CollectionConfig ─────────────────────────
40
40
 
41
- const extractColumns = (collection: EntityCollection): ColumnInfo[] => {
41
+ const extractColumns = (collection: CollectionConfig): ColumnInfo[] => {
42
42
  const columns: ColumnInfo[] = [];
43
43
  const properties = collection.properties ?? {};
44
44
 
@@ -79,7 +79,7 @@ const extractColumns = (collection: EntityCollection): ColumnInfo[] => {
79
79
  }
80
80
 
81
81
  // Add FK columns from owning relations
82
- if (isPostgresCollection(collection)) {
82
+ if (isPostgresCollectionConfig(collection)) {
83
83
  try {
84
84
  const resolvedRelations = resolveCollectionRelations(collection);
85
85
  for (const rel of Object.values(resolvedRelations)) {
@@ -117,7 +117,7 @@ const extractColumns = (collection: EntityCollection): ColumnInfo[] => {
117
117
  // ─── Build graph from collections ─────────────────────────────────────
118
118
 
119
119
  const buildGraph = (
120
- collections: EntityCollection[],
120
+ collections: CollectionConfig[],
121
121
  direction: LayoutDirection
122
122
  ): { nodes: Node[]; edges: Edge[] } => {
123
123
  const nodes: Node[] = [];
@@ -143,7 +143,7 @@ const buildGraph = (
143
143
 
144
144
  // 1. Create nodes for each collection
145
145
  for (const collection of collections) {
146
- if (!isPostgresCollection(collection)) continue;
146
+ if (!isPostgresCollectionConfig(collection)) continue;
147
147
 
148
148
  const tableName = collection.table ?? collection.slug;
149
149
  const nodeId = `table-${tableName}`;
@@ -177,7 +177,7 @@ y: 0 },
177
177
  const processedJunctions = new Set<string>();
178
178
 
179
179
  for (const collection of collections) {
180
- if (!isPostgresCollection(collection)) continue;
180
+ if (!isPostgresCollectionConfig(collection)) continue;
181
181
 
182
182
  const tableName = collection.table ?? collection.slug;
183
183
  const sourceNodeId = tableToNodeId.get(tableName);
@@ -191,14 +191,14 @@ y: 0 },
191
191
  }
192
192
 
193
193
  for (const [relationKey, rel] of Object.entries(resolvedRelations)) {
194
- let targetCollection: EntityCollection;
194
+ let targetCollection: CollectionConfig;
195
195
  try {
196
196
  targetCollection = rel.target();
197
197
  } catch {
198
198
  continue;
199
199
  }
200
200
 
201
- if (!isPostgresCollection(targetCollection)) continue;
201
+ if (!isPostgresCollectionConfig(targetCollection)) continue;
202
202
 
203
203
  const targetTable = targetCollection.table ?? targetCollection.slug;
204
204
  const targetNodeId = tableToNodeId.get(targetTable);
@@ -356,7 +356,7 @@ export interface UseSchemaGraphResult {
356
356
  }
357
357
 
358
358
  export const useSchemaGraph = (
359
- collections: EntityCollection[] | undefined
359
+ collections: CollectionConfig[] | undefined
360
360
  ): UseSchemaGraphResult => {
361
361
  const [direction, setDirection] = useState<LayoutDirection>("LR");
362
362
  const [version, setVersion] = useState(0);
@@ -41,7 +41,7 @@ import {
41
41
  VideoIcon,
42
42
  XIcon
43
43
  } from "@rebasepro/ui";
44
- import { useStorageSource, useStorageSources, useSnackbarController, ErrorView, useApiConfig } from "@rebasepro/core";
44
+ import { useStorageSource, useStorageSources, useSnackbarController, ErrorView, useApiConfig } from "@rebasepro/app";
45
45
  import { DEFAULT_STORAGE_SOURCE_KEY, type StorageListResult } from "@rebasepro/types";
46
46
  import { useSearchParams } from "react-router-dom";
47
47
  import { useDropzone } from "react-dropzone";
@@ -1,19 +1,19 @@
1
- import type { HomePageSection, PluginGenericProps } from "@rebasepro/types";
1
+ import type { AppView, HomePageSection, PluginGenericProps } from "@rebasepro/types";
2
2
  import React, { useEffect, useMemo, useState } from "react";
3
3
  import { Card, cls, Container, ExpandablePanel, Typography } from "@rebasepro/ui";
4
- import { IconForView, useRebaseContext, useRestoreScroll, useSlot } from "@rebasepro/core";
4
+ import { IconForView, useRebaseContext, useRebaseRegistry, useRestoreScroll, useSlot } from "@rebasepro/app";
5
5
  import { useNavigate } from "react-router-dom";
6
- import { useStudioBreadcrumbs, SchemaDriftBanner } from "@rebasepro/core";
6
+ import { useStudioBreadcrumbs, SchemaDriftBanner } from "@rebasepro/app";
7
7
 
8
8
  /* ═══════════════════════════════════════════════════════════════
9
- Static studio tool definitions
9
+ Studio tool sections, derived from the registered Studio views
10
10
  ═══════════════════════════════════════════════════════════════ */
11
11
 
12
12
  interface StudioTool {
13
13
  path: string;
14
14
  name: string;
15
15
  description: string;
16
- icon: string;
16
+ icon?: string | React.ReactNode;
17
17
  }
18
18
 
19
19
  interface StudioSection {
@@ -21,85 +21,44 @@ interface StudioSection {
21
21
  tools: StudioTool[];
22
22
  }
23
23
 
24
- const SECTIONS: StudioSection[] = [
25
- {
26
- label: "Database",
27
- tools: [
28
- { path: "/schema",
29
- name: "Collections",
30
- description: "Define and manage your data model and collection schemas",
31
- icon: "LayoutList" },
32
- { path: "/schema-visualizer",
33
- name: "Schema Visualizer",
34
- description: "Interactive ERD showing tables, columns, and relationships",
35
- icon: "Network" },
36
- { path: "/sql",
37
- name: "SQL Console",
38
- description: "Execute raw SQL queries directly against your database",
39
- icon: "terminal" },
40
- { path: "/branches",
41
- name: "Branches",
42
- description: "Create and manage isolated database copies for development",
43
- icon: "GitBranch" },
44
- { path: "/rls",
45
- name: "RLS Policies",
46
- description: "Configure Row Level Security for fine-grained data access",
47
- icon: "ShieldCheck" },
48
- { path: "/logs",
49
- name: "Logs Explorer",
50
- description: "Real-time system, query, and authentication logs",
51
- icon: "Activity" }
52
- ]
53
- },
54
- {
55
- label: "Compute",
56
- tools: [
57
- { path: "/js",
58
- name: "JS Console",
59
- description: "Run JavaScript with the Rebase SDK in a live sandbox",
60
- icon: "code" },
61
- { path: "/cron",
62
- name: "Cron Jobs",
63
- description: "Monitor and manage scheduled background tasks",
64
- icon: "Clock" }
65
- ]
66
- },
67
- {
68
- label: "API",
69
- tools: [
70
- { path: "/api",
71
- name: "API Explorer",
72
- description: "Interactive API documentation with live request testing",
73
- icon: "BookOpen" }
74
- ]
75
- },
76
- {
77
- label: "Storage",
78
- tools: [
79
- { path: "/storage",
80
- name: "Storage",
81
- description: "Browse, upload, and manage files in your storage bucket",
82
- icon: "HardDrive" }
83
- ]
84
- },
85
- {
86
- label: "Access Control",
87
- tools: [
88
- { path: "/users",
89
- name: "Users",
90
- description: "Manage developers and assign roles in your workspace",
91
- icon: "group" },
92
- { path: "/roles",
93
- name: "Roles",
94
- description: "Create and configure fine-grained access permissions",
95
- icon: "ShieldEllipsis" },
96
- { path: "/api-keys",
97
- name: "API Keys",
98
- description: "Create and manage scoped keys for machine-to-machine access",
99
- icon: "KeyRound" }
100
- ]
24
+ /** The view metadata the cards need — not the rendered `view` itself. */
25
+ type StudioViewMeta = Pick<AppView, "slug" | "name" | "group" | "description" | "icon" | "hideFromNavigation">;
26
+
27
+ /** Group order for the home page; unknown groups are appended in view order. */
28
+ const GROUP_ORDER = ["Database", "Compute", "Storage", "API", "Access Control"];
29
+
30
+ const UNGROUPED_LABEL = "Tools";
31
+
32
+ /**
33
+ * Build the home page sections from the Studio views that are actually
34
+ * registered, so a card exists if and only if its route does. A hand-written
35
+ * list drifts: it used to advertise Users and Roles pages that 404, while
36
+ * omitting the Backups view that does exist.
37
+ */
38
+ function buildSections(views: StudioViewMeta[]): StudioSection[] {
39
+ const byGroup = new Map<string, StudioTool[]>();
40
+
41
+ for (const view of views) {
42
+ if (view.hideFromNavigation) continue;
43
+ const label = view.group ?? UNGROUPED_LABEL;
44
+ const tools = byGroup.get(label) ?? [];
45
+ tools.push({
46
+ path: `/${view.slug}`,
47
+ name: view.name,
48
+ description: view.description ?? "",
49
+ icon: view.icon
50
+ });
51
+ byGroup.set(label, tools);
101
52
  }
102
- ];
53
+
54
+ const ordered = [
55
+ ...GROUP_ORDER.filter(g => byGroup.has(g)),
56
+ ...[...byGroup.keys()].filter(g => !GROUP_ORDER.includes(g))
57
+ ];
58
+
59
+ return ordered.map(label => ({ label,
60
+ tools: byGroup.get(label)! }));
61
+ }
103
62
 
104
63
  /* ═══════════════════════════════════════════════════════════════ */
105
64
 
@@ -151,6 +110,7 @@ export function StudioHomePage({
151
110
  const context = useRebaseContext();
152
111
  const breadcrumbs = useStudioBreadcrumbs();
153
112
  const navigate = useNavigate();
113
+ const registry = useRebaseRegistry();
154
114
 
155
115
  useEffect(() => {
156
116
  breadcrumbs.set({ breadcrumbs: [] });
@@ -162,10 +122,25 @@ export function StudioHomePage({
162
122
 
163
123
  const pluginActions = useSlot("home.actions", sectionProps);
164
124
 
165
- const filteredSections = useMemo(
166
- () => SECTIONS.filter(s => !hiddenGroups?.includes(s.label)),
167
- [hiddenGroups]
168
- );
125
+ // The collection editor ("schema") is not part of `devViews` — RebaseNavigation
126
+ // injects it when the CMS enables a collection editor. Mirror that condition so
127
+ // the card tracks the route.
128
+ const schemaEnabled = Boolean(registry.studioConfig && registry.cmsConfig?.collectionEditor);
129
+
130
+ const filteredSections = useMemo(() => {
131
+ const views: StudioViewMeta[] = [];
132
+ if (schemaEnabled) {
133
+ views.push({
134
+ slug: "schema",
135
+ name: "Collections",
136
+ group: "Database",
137
+ icon: "LayoutList",
138
+ description: "Define and manage your data model and collection schemas"
139
+ });
140
+ }
141
+ views.push(...(registry.studioConfig?.devViews ?? []));
142
+ return buildSections(views).filter(s => !hiddenGroups?.includes(s.label));
143
+ }, [registry.studioConfig?.devViews, schemaEnabled, hiddenGroups]);
169
144
 
170
145
  const groupNames = useMemo(
171
146
  () => filteredSections.map(s => s.label),
package/src/index.ts CHANGED
@@ -1,21 +1,21 @@
1
1
  // ─── Bridge ─────────────────────────────────────────────────────────
2
- // Re-export the Studio Bridge from @rebasepro/core.
2
+ // Re-export the Studio Bridge from @rebasepro/app.
3
3
  // The bridge lives in core so both studio and CMS can access it
4
4
  // without circular dependencies.
5
5
  export {
6
6
  StudioBridgeProvider,
7
7
  StudioBridgeContext,
8
8
  useStudioCollectionRegistry,
9
- useStudioSideEntityController,
9
+ useStudioSidePanelController,
10
10
  useStudioUrlController,
11
11
  useStudioNavigationState,
12
12
  useStudioBreadcrumbs
13
- } from "@rebasepro/core";
13
+ } from "@rebasepro/app";
14
14
  export type {
15
15
  StudioBridge,
16
16
  BreadcrumbEntry,
17
17
  BreadcrumbsController
18
- } from "@rebasepro/core";
18
+ } from "@rebasepro/app";
19
19
 
20
20
  // ─── Studio Entry Point ─────────────────────────────────────────────
21
21
  // Only export the lightweight orchestrator & home page.
@@ -1,4 +1,4 @@
1
- import type { EntityCollection, PostgresProperties, Property, StringProperty, NumberProperty, ArrayProperty, TableColumnInfo, TableMetadata, SecurityOperation, SecurityRule } from "@rebasepro/types";
1
+ import type { CollectionConfig, PostgresProperties, Property, StringProperty, NumberProperty, ArrayProperty, TableColumnInfo, TableMetadata, SecurityOperation, SecurityRule } from "@rebasepro/types";
2
2
 
3
3
  /**
4
4
  * Maps a PostgreSQL column data type to a Rebase property type.
@@ -194,13 +194,13 @@ label: v.replace(/_/g, " ").replace(/\b\w/g, (c: string) => c.toUpperCase()) }))
194
194
  }
195
195
 
196
196
  /**
197
- * Builds a partial EntityCollection from PostgreSQL table metadata.
197
+ * Builds a partial CollectionConfig from PostgreSQL table metadata.
198
198
  * This is used when creating a new collection from an existing database table.
199
199
  */
200
200
  export function buildCollectionFromTableMetadata(
201
201
  tableName: string,
202
202
  metadata: TableMetadata
203
- ): Partial<EntityCollection> {
203
+ ): Partial<CollectionConfig> {
204
204
  const properties: Record<string, Property> = {};
205
205
  const propertiesOrder: string[] = [];
206
206
  const relations: Array<{
@@ -2,7 +2,7 @@
2
2
  import { describe, it, expect } from "@jest/globals";
3
3
  import { determineTableAndPK, extractTablesFromQuery, resolveQueryCollections } from "./sql_utils";
4
4
  import { TableInfo } from "../components/SQLEditor/SQLEditor";
5
- import { EntityCollection } from "@rebasepro/types";
5
+ import { CollectionConfig } from "@rebasepro/types";
6
6
 
7
7
  const mockSchemas: Record<string, TableInfo[]> = {
8
8
  "public": [
@@ -81,31 +81,31 @@ isPrimaryKey: false }
81
81
  ]
82
82
  };
83
83
 
84
- const mockCollections: EntityCollection[] = [
84
+ const mockCollections: CollectionConfig[] = [
85
85
  {
86
86
  slug: "users",
87
87
  name: "Users",
88
88
  table: "users",
89
89
  properties: {}
90
- } as EntityCollection,
90
+ } as CollectionConfig,
91
91
  {
92
92
  slug: "roles",
93
93
  name: "Roles",
94
94
  table: "roles",
95
95
  properties: {}
96
- } as EntityCollection,
96
+ } as CollectionConfig,
97
97
  {
98
98
  slug: "blogPosts",
99
99
  name: "Blog Posts",
100
100
  table: "blog_posts",
101
101
  properties: {}
102
- } as EntityCollection,
102
+ } as CollectionConfig,
103
103
  {
104
104
  slug: "blog-entries", // slug with hyphen, no table → falls back to snake_case "blog_entries"
105
105
  name: "Blog Entries",
106
106
  table: "",
107
107
  properties: {}
108
- } as EntityCollection
108
+ } as CollectionConfig
109
109
  ];
110
110
 
111
111
  describe("determineTableAndPK", () => {
@@ -1,6 +1,6 @@
1
1
  import { parseFirst } from "pgsql-ast-parser";
2
2
  import { TableInfo } from "../components/SQLEditor/SQLEditor";
3
- import { EntityCollection } from "@rebasepro/types";
3
+ import { CollectionConfig } from "@rebasepro/types";
4
4
 
5
5
  /**
6
6
  * A table extracted from a SQL query's FROM/JOIN clauses.
@@ -19,7 +19,7 @@ export interface ResolvedQueryCollection {
19
19
  /** SQL alias if present (e.g. "bp") */
20
20
  tableAlias?: string;
21
21
  /** The matched collection */
22
- collection: EntityCollection;
22
+ collection: CollectionConfig;
23
23
  /** Columns from this table that are present in the result set */
24
24
  columns: string[];
25
25
  /** The result column name that holds the primary key for this table (e.g. "id", "author_id") */
@@ -77,7 +77,7 @@ import { toSnakeCase } from "@rebasepro/utils";
77
77
  export function resolveQueryCollections(
78
78
  sqlString: string,
79
79
  schemas: Record<string, TableInfo[]>,
80
- collections: EntityCollection[],
80
+ collections: CollectionConfig[],
81
81
  resultColumns?: string[]
82
82
  ): ResolvedQueryCollection[] {
83
83
  const tables = extractTablesFromQuery(sqlString);