@rebasepro/studio 0.2.3 → 0.2.5

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 (87) hide show
  1. package/dist/{ApiExplorer-BmcdhAX0.js → ApiExplorer-CGHEF1uL.js} +4 -4
  2. package/dist/ApiExplorer-CGHEF1uL.js.map +1 -0
  3. package/dist/{CronJobsView-CNfz0etw.js → CronJobsView-3PM_qR8v.js} +20 -3
  4. package/dist/CronJobsView-3PM_qR8v.js.map +1 -0
  5. package/dist/{JSEditor-Ch8z8lJ4.js → JSEditor-BCSoElPg.js} +26 -36
  6. package/dist/JSEditor-BCSoElPg.js.map +1 -0
  7. package/dist/LogsExplorer-_4sZadKn.js +162 -0
  8. package/dist/LogsExplorer-_4sZadKn.js.map +1 -0
  9. package/dist/{SQLEditor-BELYJQRP.js → SQLEditor-BC0IOUQu.js} +4 -4
  10. package/dist/SQLEditor-BC0IOUQu.js.map +1 -0
  11. package/dist/common/src/collections/default-collections.d.ts +9 -0
  12. package/dist/common/src/collections/index.d.ts +1 -0
  13. package/dist/common/src/util/permissions.d.ts +1 -0
  14. package/dist/core/src/components/LoginView/LoginView.d.ts +25 -1
  15. package/dist/core/src/components/common/types.d.ts +10 -7
  16. package/dist/core/src/components/common/useDebouncedData.d.ts +1 -1
  17. package/dist/core/src/core/RebaseProps.d.ts +13 -2
  18. package/dist/core/src/core/RebaseRouter.d.ts +1 -1
  19. package/dist/core/src/hooks/data/useCollectionFetch.d.ts +12 -1
  20. package/dist/core/src/hooks/index.d.ts +0 -1
  21. package/dist/core/src/util/entity_cache.d.ts +0 -5
  22. package/dist/core/src/util/index.d.ts +0 -2
  23. package/dist/core/src/util/useStorageUploadController.d.ts +2 -2
  24. package/dist/formex/src/utils.d.ts +2 -2
  25. package/dist/index.es.js +23 -5
  26. package/dist/index.es.js.map +1 -1
  27. package/dist/index.umd.js +228 -44
  28. package/dist/index.umd.js.map +1 -1
  29. package/dist/studio/src/components/ApiExplorer/parseSpec.d.ts +1 -1
  30. package/dist/studio/src/components/ApiExplorer/types.d.ts +3 -3
  31. package/dist/studio/src/components/LogsExplorer/LogsExplorer.d.ts +1 -0
  32. package/dist/types/src/controllers/auth.d.ts +4 -26
  33. package/dist/types/src/controllers/client.d.ts +25 -43
  34. package/dist/types/src/controllers/collection_registry.d.ts +1 -1
  35. package/dist/types/src/controllers/data.d.ts +4 -0
  36. package/dist/types/src/controllers/data_driver.d.ts +23 -0
  37. package/dist/types/src/controllers/registry.d.ts +5 -4
  38. package/dist/types/src/rebase_context.d.ts +1 -1
  39. package/dist/types/src/types/auth_adapter.d.ts +5 -60
  40. package/dist/types/src/types/backend.d.ts +2 -2
  41. package/dist/types/src/types/backend_hooks.d.ts +2 -17
  42. package/dist/types/src/types/collections.d.ts +0 -4
  43. package/dist/types/src/types/component_ref.d.ts +1 -1
  44. package/dist/types/src/types/cron.d.ts +1 -1
  45. package/dist/types/src/types/entity_views.d.ts +1 -0
  46. package/dist/types/src/types/export_import.d.ts +1 -1
  47. package/dist/types/src/types/formex.d.ts +2 -2
  48. package/dist/types/src/types/properties.d.ts +9 -7
  49. package/dist/types/src/types/translations.d.ts +28 -12
  50. package/dist/types/src/types/user_management_delegate.d.ts +22 -57
  51. package/dist/types/src/users/index.d.ts +0 -1
  52. package/dist/types/src/users/user.d.ts +0 -1
  53. package/dist/ui/src/components/Button.d.ts +2 -2
  54. package/dist/ui/src/components/ErrorBoundary.d.ts +25 -3
  55. package/dist/ui/src/components/VirtualTable/VirtualTable.d.ts +1 -1
  56. package/dist/ui/src/components/VirtualTable/VirtualTableCell.d.ts +6 -6
  57. package/dist/ui/src/components/VirtualTable/VirtualTableHeader.d.ts +8 -8
  58. package/dist/ui/src/components/VirtualTable/VirtualTableHeaderRow.d.ts +1 -1
  59. package/dist/ui/src/components/VirtualTable/VirtualTableProps.d.ts +11 -11
  60. package/dist/ui/src/components/VirtualTable/VirtualTableRow.d.ts +1 -1
  61. package/dist/ui/src/components/VirtualTable/types.d.ts +9 -9
  62. package/dist/ui/src/hooks/useDebounceCallback.d.ts +1 -1
  63. package/dist/ui/src/util/debounce.d.ts +1 -1
  64. package/package.json +8 -8
  65. package/src/components/ApiExplorer/ApiExplorer.tsx +2 -2
  66. package/src/components/ApiExplorer/EndpointDetail.tsx +1 -1
  67. package/src/components/ApiExplorer/TryItPanel.tsx +5 -5
  68. package/src/components/ApiExplorer/parseSpec.ts +3 -3
  69. package/src/components/ApiExplorer/types.ts +3 -3
  70. package/src/components/CronJobs/CronJobsView.tsx +27 -2
  71. package/src/components/JSEditor/JSEditor.tsx +21 -18
  72. package/src/components/JSEditor/JSMonacoEditor.tsx +6 -19
  73. package/src/components/LogsExplorer/LogsExplorer.tsx +224 -0
  74. package/src/components/RebaseStudio.tsx +10 -1
  75. package/src/components/SQLEditor/SQLEditor.tsx +28 -7
  76. package/src/components/StudioHomePage.tsx +2 -1
  77. package/src/utils/parseSpec.test.ts +274 -0
  78. package/src/utils/pgColumnToProperty.test.ts +1 -0
  79. package/src/utils/pgColumnToProperty.ts +35 -4
  80. package/dist/ApiExplorer-BmcdhAX0.js.map +0 -1
  81. package/dist/CronJobsView-CNfz0etw.js.map +0 -1
  82. package/dist/JSEditor-Ch8z8lJ4.js.map +0 -1
  83. package/dist/SQLEditor-BELYJQRP.js.map +0 -1
  84. package/dist/core/src/hooks/useValidateAuthenticator.d.ts +0 -21
  85. package/dist/core/src/util/icon_synonyms.d.ts +0 -1
  86. package/dist/core/src/util/useTraceUpdate.d.ts +0 -2
  87. package/dist/types/src/users/roles.d.ts +0 -22
package/dist/index.umd.js CHANGED
@@ -31,6 +31,11 @@
31
31
  name: "RLS Policies",
32
32
  description: "Configure Row Level Security for fine-grained data access",
33
33
  icon: "ShieldCheck"
34
+ }, {
35
+ path: "/logs",
36
+ name: "Logs Explorer",
37
+ description: "Real-time system, query, and authentication logs",
38
+ icon: "Activity"
34
39
  }]
35
40
  }, {
36
41
  label: "Compute",
@@ -611,6 +616,9 @@
611
616
  const ApiExplorer$2 = React.lazy(() => Promise.resolve().then(() => ApiExplorer$1).then((m) => ({
612
617
  default: m.ApiExplorer
613
618
  })));
619
+ const LogsExplorer$2 = React.lazy(() => Promise.resolve().then(() => LogsExplorer$1).then((m) => ({
620
+ default: m.LogsExplorer
621
+ })));
614
622
  const DEFAULT_HOME_PAGE = /* @__PURE__ */ jsxRuntime.jsx(StudioHomePage, {});
615
623
  function RebaseStudio({
616
624
  tools,
@@ -620,7 +628,7 @@
620
628
  const resolvedHomePage = homePage ?? DEFAULT_HOME_PAGE;
621
629
  const devViews = React.useMemo(() => {
622
630
  const views = [];
623
- const activeTools = tools ?? ["sql", "js", "rls", "storage", "cron", "schema-visualizer", "branches", "api"];
631
+ const activeTools = tools ?? ["sql", "js", "rls", "storage", "cron", "schema-visualizer", "branches", "api", "logs"];
624
632
  const suspense = (el) => /* @__PURE__ */ jsxRuntime.jsx(React.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(ui.CircularProgressCenter, {}), children: el });
625
633
  if (activeTools.includes("sql")) {
626
634
  views.push({
@@ -702,6 +710,16 @@
702
710
  view: suspense(/* @__PURE__ */ jsxRuntime.jsx(ApiExplorer$2, {}))
703
711
  });
704
712
  }
713
+ if (activeTools.includes("logs")) {
714
+ views.push({
715
+ slug: "logs",
716
+ name: "Logs Explorer",
717
+ group: "Database",
718
+ icon: "Activity",
719
+ description: "Real-time system and query logs",
720
+ view: suspense(/* @__PURE__ */ jsxRuntime.jsx(LogsExplorer$2, {}))
721
+ });
722
+ }
705
723
  return views;
706
724
  }, [tools]);
707
725
  const homePageRef = React.useRef(resolvedHomePage);
@@ -2469,7 +2487,7 @@ WHERE id = ?;`);
2469
2487
  rowIndex: rowIndex_1
2470
2488
  }) => {
2471
2489
  if (column_0.key === "__cms_action__") {
2472
- const rowActions = getRowEntityActions(rowData_2);
2490
+ const rowActions = getRowEntityActions(rowData_2 ?? {});
2473
2491
  if (rowActions.length === 0) {
2474
2492
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full" });
2475
2493
  }
@@ -2504,9 +2522,9 @@ WHERE id = ?;`);
2504
2522
  const value = rowData_2 ? rowData_2[column_0.key] : null;
2505
2523
  const displayValue = typeof value === "object" && value !== null ? JSON.stringify(value) : String(value ?? "");
2506
2524
  if (isEditing) {
2507
- return /* @__PURE__ */ jsxRuntime.jsx(FixedEditorOverlay, { displayValue, onSave: (val_2) => handleCellSave(val_2, rowData_2, column_0.key, rowIndex_1), onCancel: () => setEditingCell(null) });
2525
+ return /* @__PURE__ */ jsxRuntime.jsx(FixedEditorOverlay, { displayValue, onSave: (val_2) => handleCellSave(val_2, rowData_2 ?? {}, column_0.key, rowIndex_1), onCancel: () => setEditingCell(null) });
2508
2526
  }
2509
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-1.5 h-full flex items-center whitespace-nowrap text-[13px] text-text-primary dark:text-text-primary-dark font-mono cursor-text group/cell", onDoubleClick: () => handleDoubleClick(rowIndex_1, column_0.key, displayValue, rowData_2), children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate flex-grow", title: displayValue, children: displayValue === "" ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-text-disabled dark:text-text-disabled-dark italic text-[11px]", children: "NULL" }) : displayValue }) });
2527
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-1.5 h-full flex items-center whitespace-nowrap text-[13px] text-text-primary dark:text-text-primary-dark font-mono cursor-text group/cell", onDoubleClick: () => handleDoubleClick(rowIndex_1, column_0.key, displayValue, rowData_2 ?? {}), children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate flex-grow", title: displayValue, children: displayValue === "" ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-text-disabled dark:text-text-disabled-dark italic text-[11px]", children: "NULL" }) : displayValue }) });
2510
2528
  } }) }),
2511
2529
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cls("p-2 px-4 border-t bg-surface-50 dark:bg-surface-900 flex justify-between items-center shrink-0", ui.defaultBorderMixin), children: [
2512
2530
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex space-x-4", children: [
@@ -2747,7 +2765,7 @@ interface RebaseAuth {
2747
2765
  changePassword(oldPassword: string, newPassword: string): Promise<{ success: boolean; message: string }>;
2748
2766
  sendVerificationEmail(): Promise<{ success: boolean; message: string }>;
2749
2767
  verifyEmail(token: string): Promise<{ success: boolean; message: string }>;
2750
- getSessions(): Promise<any[]>;
2768
+ getSessions(): Promise<RebaseSession[]>;
2751
2769
  revokeSession(sessionId: string): Promise<{ success: boolean }>;
2752
2770
  revokeAllSessions(): Promise<{ success: boolean }>;
2753
2771
  getSession(): RebaseSession | null;
@@ -2765,25 +2783,12 @@ interface AdminUser {
2765
2783
  updatedAt: string;
2766
2784
  }
2767
2785
 
2768
- interface RebaseRole {
2769
- id: string;
2770
- name: string;
2771
- isAdmin: boolean;
2772
- defaultPermissions: Record<string, any> | null;
2773
- config: Record<string, any> | null;
2774
- }
2775
-
2776
2786
  interface RebaseAdmin {
2777
2787
  listUsers(): Promise<{ users: AdminUser[] }>;
2778
2788
  getUser(userId: string): Promise<{ user: AdminUser }>;
2779
2789
  createUser(data: { email: string; displayName?: string; password?: string; roles?: string[] }): Promise<{ user: AdminUser }>;
2780
2790
  updateUser(userId: string, data: { email?: string; displayName?: string; password?: string; roles?: string[] }): Promise<{ user: AdminUser }>;
2781
2791
  deleteUser(userId: string): Promise<{ success: boolean }>;
2782
- listRoles(): Promise<{ roles: RebaseRole[] }>;
2783
- getRole(roleId: string): Promise<{ role: RebaseRole }>;
2784
- createRole(data: { id: string; name: string; isAdmin?: boolean; defaultPermissions?: any; config?: any }): Promise<{ role: RebaseRole }>;
2785
- updateRole(roleId: string, data: { name?: string; isAdmin?: boolean; defaultPermissions?: any; config?: any }): Promise<{ role: RebaseRole }>;
2786
- deleteRole(roleId: string): Promise<{ success: boolean }>;
2787
2792
  bootstrap(): Promise<{ success: boolean; message: string; user: { uid: string; roles: string[] } }>;
2788
2793
  }
2789
2794
 
@@ -2791,7 +2796,7 @@ interface UploadFileProps {
2791
2796
  file: FileIcon;
2792
2797
  fileName?: string;
2793
2798
  path?: string;
2794
- metadata?: Record<string, any>;
2799
+ metadata?: Record<string, unknown>;
2795
2800
  bucket?: string;
2796
2801
  }
2797
2802
 
@@ -2804,7 +2809,7 @@ interface UploadFileResult {
2804
2809
  interface DownloadConfig {
2805
2810
  url: string | null;
2806
2811
  fileNotFound?: boolean;
2807
- metadata?: any;
2812
+ metadata?: Record<string, unknown>;
2808
2813
  }
2809
2814
 
2810
2815
  interface StorageSource {
@@ -2812,7 +2817,7 @@ interface StorageSource {
2812
2817
  getSignedUrl(pathOrUrl: string, bucket?: string): Promise<DownloadConfig>;
2813
2818
  getObject(path: string, bucket?: string): Promise<FileIcon | null>;
2814
2819
  deleteObject(path: string, bucket?: string): Promise<void>;
2815
- listObjects(path: string, options?: { bucket?: string; maxResults?: number; pageToken?: string }): Promise<any>;
2820
+ listObjects(path: string, options?: { bucket?: string; maxResults?: number; pageToken?: string }): Promise<unknown>;
2816
2821
  }
2817
2822
 
2818
2823
  type RebaseData = {
@@ -2856,9 +2861,9 @@ interface RebaseClient {
2856
2861
  /** Storage operations */
2857
2862
  storage?: StorageSource;
2858
2863
  /** Call a custom server-side endpoint */
2859
- call<T = any>(endpoint: string, payload?: any): Promise<T>;
2864
+ call<T = unknown>(endpoint: string, payload?: unknown): Promise<T>;
2860
2865
  /** Direct collection access (shorthand) */
2861
- [collectionSlug: string]: any;
2866
+ [collectionSlug: string]: unknown;
2862
2867
  }
2863
2868
 
2864
2869
  /** The pre-configured client instance. Already authenticated with the current user session. */
@@ -3428,8 +3433,9 @@ return result;
3428
3433
  }
3429
3434
  if (mentionedSlugs.size === 0) return [];
3430
3435
  let rows = [];
3431
- if (resultValue?.data && Array.isArray(resultValue.data)) {
3432
- rows = resultValue.data;
3436
+ const rv = resultValue;
3437
+ if (rv?.data && Array.isArray(rv.data)) {
3438
+ rows = rv.data;
3433
3439
  } else if (Array.isArray(resultValue)) {
3434
3440
  rows = resultValue;
3435
3441
  }
@@ -3691,7 +3697,8 @@ return result;
3691
3697
  duration: duration_0,
3692
3698
  timestamp: Date.now()
3693
3699
  });
3694
- if (value?.data && Array.isArray(value.data)) {
3700
+ const resultObj = value;
3701
+ if (resultObj?.data && Array.isArray(resultObj.data)) {
3695
3702
  setResultView("table");
3696
3703
  } else if (consoleEntries.length > 0 && value === void 0) {
3697
3704
  setResultView("console");
@@ -3756,10 +3763,11 @@ return result;
3756
3763
  data: []
3757
3764
  };
3758
3765
  let rows = [];
3759
- if (result.value?.data && Array.isArray(result.value.data)) {
3760
- rows = result.value.data.map((entity) => ({
3766
+ const val = result.value;
3767
+ if (val?.data && Array.isArray(val.data)) {
3768
+ rows = val.data.map((entity) => ({
3761
3769
  id: entity.id,
3762
- ...entity.values,
3770
+ ...entity.values ?? {},
3763
3771
  ...entity.values ? {} : entity
3764
3772
  }));
3765
3773
  } else if (Array.isArray(result.value)) {
@@ -3800,8 +3808,8 @@ return result;
3800
3808
  if (tableData.data.length === 0) return;
3801
3809
  const headers = tableData.columns.map((c_0) => c_0.key).join(",");
3802
3810
  const rows_0 = tableData.data.map((row_0) => tableData.columns.map((c_1) => {
3803
- const val = row_0[c_1.key];
3804
- const str = val === null || val === void 0 ? "" : String(val);
3811
+ const val_0 = row_0[c_1.key];
3812
+ const str = val_0 === null || val_0 === void 0 ? "" : String(val_0);
3805
3813
  return str.includes(",") ? `"${str}"` : str;
3806
3814
  }).join(","));
3807
3815
  const csv = [headers, ...rows_0].join("\n");
@@ -3821,9 +3829,9 @@ return result;
3821
3829
  const headerRow = `| ${headers_0.join(" | ")} |`;
3822
3830
  const dividerRow = `| ${headers_0.map(() => "---").join(" | ")} |`;
3823
3831
  const dataRows = tableData.data.map((row_1) => `| ${headers_0.map((h_0) => {
3824
- const val_0 = row_1[h_0];
3825
- if (val_0 === null || val_0 === void 0) return "";
3826
- return String(val_0).replace(/\|/g, "\\|").replace(/\n/g, " ");
3832
+ const val_1 = row_1[h_0];
3833
+ if (val_1 === null || val_1 === void 0) return "";
3834
+ return String(val_1).replace(/\|/g, "\\|").replace(/\n/g, " ");
3827
3835
  }).join(" | ")} |`);
3828
3836
  const markdown = [headerRow, dividerRow, ...dataRows].join("\n");
3829
3837
  navigator.clipboard.writeText(markdown).then(() => {
@@ -3857,7 +3865,7 @@ return result;
3857
3865
  setSnippetName("");
3858
3866
  setShowSaveDialog(true);
3859
3867
  }, disabled: !activeTab?.code.trim(), children: /* @__PURE__ */ jsxRuntime.jsx(ui.SaveIcon, { size: ui.iconSize.smallest }) }) }),
3860
- result?.value && /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "Export result as JSON", children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: exportResult, children: /* @__PURE__ */ jsxRuntime.jsx(ui.DownloadIcon, { size: ui.iconSize.smallest }) }) }),
3868
+ result?.value != null && /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { title: "Export result as JSON", children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", onClick: exportResult, children: /* @__PURE__ */ jsxRuntime.jsx(ui.DownloadIcon, { size: ui.iconSize.smallest }) }) }),
3861
3869
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", color: "primary", disabled: isRunning || !activeTab?.code.trim(), onClick: () => executeCode(), children: [
3862
3870
  isRunning ? /* @__PURE__ */ jsxRuntime.jsx(ui.CircularProgress, { size: "smallest", className: "mr-2" }) : /* @__PURE__ */ jsxRuntime.jsx(ui.PlayIcon, { size: ui.iconSize.smallest, className: "mr-2" }),
3863
3871
  "Run"
@@ -3872,7 +3880,7 @@ return result;
3872
3880
  /* @__PURE__ */ jsxRuntime.jsx(ui.Typography, { variant: "caption", className: "font-bold text-text-disabled dark:text-text-disabled-dark uppercase tracking-widest text-[10px]", children: t("studio_sql_query_results") }),
3873
3881
  result && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3874
3882
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-grow" }),
3875
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Tabs, { value: resultView, onValueChange: (val_1) => setResultView(val_1), variant: "pill", className: "w-[unset] mr-2", children: [
3883
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Tabs, { value: resultView, onValueChange: (val_2) => setResultView(val_2), variant: "pill", className: "w-[unset] mr-2", children: [
3876
3884
  /* @__PURE__ */ jsxRuntime.jsx(ui.Tab, { value: "json", children: "JSON" }),
3877
3885
  tableData.data.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.Tab, { value: "table", children: "Table" }),
3878
3886
  result.console.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(ui.Tab, { value: "console", children: [
@@ -3921,7 +3929,7 @@ return result;
3921
3929
  rowIndex
3922
3930
  }) => {
3923
3931
  if (column.key === "__entity_action__") {
3924
- const rowActions = getRowEntityActions(rowData_0);
3932
+ const rowActions = getRowEntityActions(rowData_0 ?? {});
3925
3933
  if (rowActions.length === 0) return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full" });
3926
3934
  if (rowActions.length === 1) {
3927
3935
  const ra = rowActions[0];
@@ -3951,8 +3959,8 @@ return result;
3951
3959
  }) }, ra_0.collection.collectionSlug)) }) });
3952
3960
  }
3953
3961
  if (!rowData_0) return null;
3954
- const val_2 = rowData_0[column.key];
3955
- const displayValue = typeof val_2 === "object" && val_2 !== null ? JSON.stringify(val_2) : String(val_2 ?? "");
3962
+ const val_3 = rowData_0[column.key];
3963
+ const displayValue = typeof val_3 === "object" && val_3 !== null ? JSON.stringify(val_3) : String(val_3 ?? "");
3956
3964
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-1.5 h-full flex items-center whitespace-nowrap text-[13px] text-text-primary dark:text-text-primary-dark font-mono", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate flex-grow", title: displayValue, children: displayValue === "" ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-text-disabled dark:text-text-disabled-dark italic text-[11px]", children: "NULL" }) : displayValue }) });
3957
3965
  } }) })
3958
3966
  ] }),
@@ -6842,10 +6850,27 @@ return result;
6842
6850
  }
6843
6851
  }
6844
6852
  load();
6845
- const t = setInterval(load, 15e3);
6853
+ let timeoutId = null;
6854
+ const scheduleNext = () => {
6855
+ if (cancelled) return;
6856
+ timeoutId = setTimeout(async () => {
6857
+ if (document.visibilityState === "visible") {
6858
+ await load();
6859
+ }
6860
+ scheduleNext();
6861
+ }, 15e3);
6862
+ };
6863
+ scheduleNext();
6864
+ const handleVisibility = () => {
6865
+ if (document.visibilityState === "visible") {
6866
+ load();
6867
+ }
6868
+ };
6869
+ document.addEventListener("visibilitychange", handleVisibility);
6846
6870
  return () => {
6847
6871
  cancelled = true;
6848
- clearInterval(t);
6872
+ if (timeoutId) clearTimeout(timeoutId);
6873
+ document.removeEventListener("visibilitychange", handleVisibility);
6849
6874
  };
6850
6875
  }, []);
6851
6876
  React.useEffect(() => {
@@ -9138,7 +9163,7 @@ return result;
9138
9163
  try {
9139
9164
  JSON.parse(body);
9140
9165
  } catch (err) {
9141
- setValidationError(`Invalid JSON: ${err.message}`);
9166
+ setValidationError(`Invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
9142
9167
  return;
9143
9168
  }
9144
9169
  }
@@ -9183,7 +9208,7 @@ return result;
9183
9208
  setResponse({
9184
9209
  status: 0,
9185
9210
  statusText: "Network Error",
9186
- body: err_0.message ?? "Request failed",
9211
+ body: err_0 instanceof Error ? err_0.message : "Request failed",
9187
9212
  time: Math.round(performance.now() - start)
9188
9213
  });
9189
9214
  } finally {
@@ -9511,7 +9536,7 @@ return result;
9511
9536
  }
9512
9537
  } catch (err) {
9513
9538
  if (!cancelled) {
9514
- setError(err.message ?? "Failed to load API spec");
9539
+ setError(err instanceof Error ? err.message : "Failed to load API spec");
9515
9540
  setLoading(false);
9516
9541
  }
9517
9542
  }
@@ -9617,6 +9642,165 @@ return result;
9617
9642
  __proto__: null,
9618
9643
  ApiExplorer
9619
9644
  }, Symbol.toStringTag, { value: "Module" }));
9645
+ const LEVEL_COLORS = {
9646
+ debug: "#6c7086",
9647
+ info: "#89b4fa",
9648
+ warn: "#f9e2af",
9649
+ error: "#f38ba8"
9650
+ };
9651
+ const SOURCE_COLORS = {
9652
+ api: "#74c7ec",
9653
+ auth: "#cba6f7",
9654
+ storage: "#a6e3a1",
9655
+ realtime: "#fab387",
9656
+ system: "#6c7086"
9657
+ };
9658
+ function LogsExplorer() {
9659
+ const [logs, setLogs] = React.useState([]);
9660
+ const [level, setLevel] = React.useState("");
9661
+ const [source, setSource] = React.useState("");
9662
+ const [search, setSearch] = React.useState("");
9663
+ const [autoScroll, setAutoScroll] = React.useState(true);
9664
+ const containerRef = React.useRef(null);
9665
+ const fetchLogs = React.useCallback(async () => {
9666
+ try {
9667
+ const params = new URLSearchParams();
9668
+ if (level) params.set("level", level);
9669
+ if (source) params.set("source", source);
9670
+ if (search) params.set("search", search);
9671
+ params.set("limit", "200");
9672
+ const resp = await fetch(`/api/logs?${params}`);
9673
+ if (resp.ok) {
9674
+ const data = await resp.json();
9675
+ setLogs(data.entries || []);
9676
+ }
9677
+ } catch {
9678
+ }
9679
+ }, [level, source, search]);
9680
+ React.useEffect(() => {
9681
+ let timeoutId = null;
9682
+ let cancelled = false;
9683
+ fetchLogs();
9684
+ const scheduleNext = () => {
9685
+ if (cancelled) return;
9686
+ timeoutId = setTimeout(async () => {
9687
+ if (document.visibilityState === "visible") {
9688
+ await fetchLogs();
9689
+ }
9690
+ scheduleNext();
9691
+ }, 3e3);
9692
+ };
9693
+ scheduleNext();
9694
+ const handleVisibility = () => {
9695
+ if (document.visibilityState === "visible") {
9696
+ fetchLogs();
9697
+ }
9698
+ };
9699
+ document.addEventListener("visibilitychange", handleVisibility);
9700
+ return () => {
9701
+ cancelled = true;
9702
+ if (timeoutId) clearTimeout(timeoutId);
9703
+ document.removeEventListener("visibilitychange", handleVisibility);
9704
+ };
9705
+ }, [fetchLogs]);
9706
+ React.useEffect(() => {
9707
+ if (autoScroll && containerRef.current) {
9708
+ containerRef.current.scrollTop = containerRef.current.scrollHeight;
9709
+ }
9710
+ }, [logs, autoScroll]);
9711
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
9712
+ display: "flex",
9713
+ flexDirection: "column",
9714
+ height: "calc(100vh - 64px)",
9715
+ background: "#1e1e2e",
9716
+ color: "#cdd6f4"
9717
+ }, children: [
9718
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
9719
+ display: "flex",
9720
+ gap: 8,
9721
+ padding: "8px 16px",
9722
+ borderBottom: "1px solid #313244",
9723
+ alignItems: "center",
9724
+ flexWrap: "wrap"
9725
+ }, children: [
9726
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Select, { value: level, onValueChange: setLevel, size: "small", placeholder: "All Levels", children: [
9727
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "", children: "All Levels" }),
9728
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "debug", children: "Debug" }),
9729
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "info", children: "Info" }),
9730
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "warn", children: "Warn" }),
9731
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "error", children: "Error" })
9732
+ ] }),
9733
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Select, { value: source, onValueChange: setSource, size: "small", placeholder: "All Sources", children: [
9734
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "", children: "All Sources" }),
9735
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "api", children: "API" }),
9736
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "auth", children: "Auth" }),
9737
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "storage", children: "Storage" }),
9738
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "realtime", children: "Realtime" }),
9739
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "system", children: "System" })
9740
+ ] }),
9741
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TextField, { size: "small", placeholder: "Search logs...", value: search, onChange: (e) => setSearch(e.target.value), className: "flex-1 min-w-[200px]" }),
9742
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 cursor-pointer", children: [
9743
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Checkbox, { id: "auto-scroll", checked: autoScroll, onCheckedChange: setAutoScroll, size: "small", padding: false }),
9744
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "auto-scroll", className: "text-xs select-none cursor-pointer", children: "Auto-scroll" })
9745
+ ] }),
9746
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: {
9747
+ fontSize: 12,
9748
+ color: "#6c7086"
9749
+ }, children: [
9750
+ logs.length,
9751
+ " entries"
9752
+ ] })
9753
+ ] }),
9754
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, style: {
9755
+ flex: 1,
9756
+ overflow: "auto",
9757
+ fontFamily: "monospace",
9758
+ fontSize: 12,
9759
+ padding: "8px 0"
9760
+ }, children: [
9761
+ logs.map((log) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
9762
+ padding: "2px 16px",
9763
+ display: "flex",
9764
+ gap: 8,
9765
+ borderBottom: "1px solid #181825"
9766
+ }, children: [
9767
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
9768
+ color: "#6c7086",
9769
+ flexShrink: 0
9770
+ }, children: new Date(log.timestamp).toLocaleTimeString() }),
9771
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
9772
+ color: LEVEL_COLORS[log.level] || "#cdd6f4",
9773
+ width: 40,
9774
+ flexShrink: 0,
9775
+ textTransform: "uppercase",
9776
+ fontWeight: 600
9777
+ }, children: log.level }),
9778
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: {
9779
+ color: SOURCE_COLORS[log.source] || "#cdd6f4",
9780
+ width: 64,
9781
+ flexShrink: 0
9782
+ }, children: [
9783
+ "[",
9784
+ log.source,
9785
+ "]"
9786
+ ] }),
9787
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
9788
+ color: "#cdd6f4",
9789
+ flex: 1
9790
+ }, children: log.message })
9791
+ ] }, log.id)),
9792
+ logs.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
9793
+ padding: 32,
9794
+ textAlign: "center",
9795
+ color: "#6c7086"
9796
+ }, children: "No log entries yet. Logs will appear here as requests come in." })
9797
+ ] })
9798
+ ] });
9799
+ }
9800
+ const LogsExplorer$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
9801
+ __proto__: null,
9802
+ LogsExplorer
9803
+ }, Symbol.toStringTag, { value: "Module" }));
9620
9804
  Object.defineProperty(exports2, "StudioBridgeContext", {
9621
9805
  enumerable: true,
9622
9806
  get: () => core.StudioBridgeContext