@rebasepro/studio 0.2.3 → 0.3.0

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 (80) 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-Br4ke-J4.js} +30 -27
  6. package/dist/JSEditor-Br4ke-J4.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 +12 -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 +17 -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/index.d.ts +0 -1
  20. package/dist/core/src/util/entity_cache.d.ts +0 -5
  21. package/dist/core/src/util/index.d.ts +0 -2
  22. package/dist/core/src/util/useStorageUploadController.d.ts +2 -2
  23. package/dist/formex/src/utils.d.ts +2 -2
  24. package/dist/index.es.js +23 -5
  25. package/dist/index.es.js.map +1 -1
  26. package/dist/index.umd.js +232 -35
  27. package/dist/index.umd.js.map +1 -1
  28. package/dist/studio/src/components/ApiExplorer/parseSpec.d.ts +1 -1
  29. package/dist/studio/src/components/ApiExplorer/types.d.ts +3 -3
  30. package/dist/studio/src/components/LogsExplorer/LogsExplorer.d.ts +1 -0
  31. package/dist/types/src/controllers/auth.d.ts +2 -24
  32. package/dist/types/src/controllers/client.d.ts +0 -3
  33. package/dist/types/src/controllers/collection_registry.d.ts +1 -1
  34. package/dist/types/src/controllers/data_driver.d.ts +18 -0
  35. package/dist/types/src/controllers/registry.d.ts +5 -4
  36. package/dist/types/src/rebase_context.d.ts +1 -1
  37. package/dist/types/src/types/auth_adapter.d.ts +2 -4
  38. package/dist/types/src/types/collections.d.ts +0 -4
  39. package/dist/types/src/types/component_ref.d.ts +1 -1
  40. package/dist/types/src/types/cron.d.ts +1 -1
  41. package/dist/types/src/types/entity_views.d.ts +1 -0
  42. package/dist/types/src/types/export_import.d.ts +1 -1
  43. package/dist/types/src/types/formex.d.ts +2 -2
  44. package/dist/types/src/types/properties.d.ts +2 -2
  45. package/dist/types/src/types/translations.d.ts +28 -12
  46. package/dist/types/src/types/user_management_delegate.d.ts +6 -4
  47. package/dist/types/src/users/roles.d.ts +0 -8
  48. package/dist/ui/src/components/Button.d.ts +2 -2
  49. package/dist/ui/src/components/ErrorBoundary.d.ts +25 -3
  50. package/dist/ui/src/components/VirtualTable/VirtualTable.d.ts +1 -1
  51. package/dist/ui/src/components/VirtualTable/VirtualTableCell.d.ts +6 -6
  52. package/dist/ui/src/components/VirtualTable/VirtualTableHeader.d.ts +8 -8
  53. package/dist/ui/src/components/VirtualTable/VirtualTableHeaderRow.d.ts +1 -1
  54. package/dist/ui/src/components/VirtualTable/VirtualTableProps.d.ts +11 -11
  55. package/dist/ui/src/components/VirtualTable/VirtualTableRow.d.ts +1 -1
  56. package/dist/ui/src/components/VirtualTable/types.d.ts +9 -9
  57. package/dist/ui/src/hooks/useDebounceCallback.d.ts +1 -1
  58. package/dist/ui/src/util/debounce.d.ts +1 -1
  59. package/package.json +8 -8
  60. package/src/components/ApiExplorer/ApiExplorer.tsx +2 -2
  61. package/src/components/ApiExplorer/EndpointDetail.tsx +1 -1
  62. package/src/components/ApiExplorer/TryItPanel.tsx +5 -5
  63. package/src/components/ApiExplorer/parseSpec.ts +3 -3
  64. package/src/components/ApiExplorer/types.ts +3 -3
  65. package/src/components/CronJobs/CronJobsView.tsx +27 -2
  66. package/src/components/JSEditor/JSEditor.tsx +21 -18
  67. package/src/components/JSEditor/JSMonacoEditor.tsx +10 -10
  68. package/src/components/LogsExplorer/LogsExplorer.tsx +224 -0
  69. package/src/components/RebaseStudio.tsx +10 -1
  70. package/src/components/SQLEditor/SQLEditor.tsx +28 -7
  71. package/src/components/StudioHomePage.tsx +2 -1
  72. package/src/utils/parseSpec.test.ts +274 -0
  73. package/src/utils/pgColumnToProperty.ts +16 -2
  74. package/dist/ApiExplorer-BmcdhAX0.js.map +0 -1
  75. package/dist/CronJobsView-CNfz0etw.js.map +0 -1
  76. package/dist/JSEditor-Ch8z8lJ4.js.map +0 -1
  77. package/dist/SQLEditor-BELYJQRP.js.map +0 -1
  78. package/dist/core/src/hooks/useValidateAuthenticator.d.ts +0 -21
  79. package/dist/core/src/util/icon_synonyms.d.ts +0 -1
  80. package/dist/core/src/util/useTraceUpdate.d.ts +0 -2
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;
@@ -2769,8 +2787,8 @@ interface RebaseRole {
2769
2787
  id: string;
2770
2788
  name: string;
2771
2789
  isAdmin: boolean;
2772
- defaultPermissions: Record<string, any> | null;
2773
- config: Record<string, any> | null;
2790
+ defaultPermissions: Record<string, unknown> | null;
2791
+ config: Record<string, unknown> | null;
2774
2792
  }
2775
2793
 
2776
2794
  interface RebaseAdmin {
@@ -2781,8 +2799,8 @@ interface RebaseAdmin {
2781
2799
  deleteUser(userId: string): Promise<{ success: boolean }>;
2782
2800
  listRoles(): Promise<{ roles: RebaseRole[] }>;
2783
2801
  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 }>;
2802
+ createRole(data: { id: string; name: string; isAdmin?: boolean; defaultPermissions?: Record<string, unknown>; config?: Record<string, unknown> }): Promise<{ role: RebaseRole }>;
2803
+ updateRole(roleId: string, data: { name?: string; isAdmin?: boolean; defaultPermissions?: Record<string, unknown>; config?: Record<string, unknown> }): Promise<{ role: RebaseRole }>;
2786
2804
  deleteRole(roleId: string): Promise<{ success: boolean }>;
2787
2805
  bootstrap(): Promise<{ success: boolean; message: string; user: { uid: string; roles: string[] } }>;
2788
2806
  }
@@ -2791,7 +2809,7 @@ interface UploadFileProps {
2791
2809
  file: FileIcon;
2792
2810
  fileName?: string;
2793
2811
  path?: string;
2794
- metadata?: Record<string, any>;
2812
+ metadata?: Record<string, unknown>;
2795
2813
  bucket?: string;
2796
2814
  }
2797
2815
 
@@ -2804,7 +2822,7 @@ interface UploadFileResult {
2804
2822
  interface DownloadConfig {
2805
2823
  url: string | null;
2806
2824
  fileNotFound?: boolean;
2807
- metadata?: any;
2825
+ metadata?: Record<string, unknown>;
2808
2826
  }
2809
2827
 
2810
2828
  interface StorageSource {
@@ -2812,7 +2830,7 @@ interface StorageSource {
2812
2830
  getSignedUrl(pathOrUrl: string, bucket?: string): Promise<DownloadConfig>;
2813
2831
  getObject(path: string, bucket?: string): Promise<FileIcon | null>;
2814
2832
  deleteObject(path: string, bucket?: string): Promise<void>;
2815
- listObjects(path: string, options?: { bucket?: string; maxResults?: number; pageToken?: string }): Promise<any>;
2833
+ listObjects(path: string, options?: { bucket?: string; maxResults?: number; pageToken?: string }): Promise<unknown>;
2816
2834
  }
2817
2835
 
2818
2836
  type RebaseData = {
@@ -2856,9 +2874,9 @@ interface RebaseClient {
2856
2874
  /** Storage operations */
2857
2875
  storage?: StorageSource;
2858
2876
  /** Call a custom server-side endpoint */
2859
- call<T = any>(endpoint: string, payload?: any): Promise<T>;
2877
+ call<T = unknown>(endpoint: string, payload?: unknown): Promise<T>;
2860
2878
  /** Direct collection access (shorthand) */
2861
- [collectionSlug: string]: any;
2879
+ [collectionSlug: string]: unknown;
2862
2880
  }
2863
2881
 
2864
2882
  /** The pre-configured client instance. Already authenticated with the current user session. */
@@ -3428,8 +3446,9 @@ return result;
3428
3446
  }
3429
3447
  if (mentionedSlugs.size === 0) return [];
3430
3448
  let rows = [];
3431
- if (resultValue?.data && Array.isArray(resultValue.data)) {
3432
- rows = resultValue.data;
3449
+ const rv = resultValue;
3450
+ if (rv?.data && Array.isArray(rv.data)) {
3451
+ rows = rv.data;
3433
3452
  } else if (Array.isArray(resultValue)) {
3434
3453
  rows = resultValue;
3435
3454
  }
@@ -3691,7 +3710,8 @@ return result;
3691
3710
  duration: duration_0,
3692
3711
  timestamp: Date.now()
3693
3712
  });
3694
- if (value?.data && Array.isArray(value.data)) {
3713
+ const resultObj = value;
3714
+ if (resultObj?.data && Array.isArray(resultObj.data)) {
3695
3715
  setResultView("table");
3696
3716
  } else if (consoleEntries.length > 0 && value === void 0) {
3697
3717
  setResultView("console");
@@ -3756,10 +3776,11 @@ return result;
3756
3776
  data: []
3757
3777
  };
3758
3778
  let rows = [];
3759
- if (result.value?.data && Array.isArray(result.value.data)) {
3760
- rows = result.value.data.map((entity) => ({
3779
+ const val = result.value;
3780
+ if (val?.data && Array.isArray(val.data)) {
3781
+ rows = val.data.map((entity) => ({
3761
3782
  id: entity.id,
3762
- ...entity.values,
3783
+ ...entity.values ?? {},
3763
3784
  ...entity.values ? {} : entity
3764
3785
  }));
3765
3786
  } else if (Array.isArray(result.value)) {
@@ -3800,8 +3821,8 @@ return result;
3800
3821
  if (tableData.data.length === 0) return;
3801
3822
  const headers = tableData.columns.map((c_0) => c_0.key).join(",");
3802
3823
  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);
3824
+ const val_0 = row_0[c_1.key];
3825
+ const str = val_0 === null || val_0 === void 0 ? "" : String(val_0);
3805
3826
  return str.includes(",") ? `"${str}"` : str;
3806
3827
  }).join(","));
3807
3828
  const csv = [headers, ...rows_0].join("\n");
@@ -3821,9 +3842,9 @@ return result;
3821
3842
  const headerRow = `| ${headers_0.join(" | ")} |`;
3822
3843
  const dividerRow = `| ${headers_0.map(() => "---").join(" | ")} |`;
3823
3844
  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, " ");
3845
+ const val_1 = row_1[h_0];
3846
+ if (val_1 === null || val_1 === void 0) return "";
3847
+ return String(val_1).replace(/\|/g, "\\|").replace(/\n/g, " ");
3827
3848
  }).join(" | ")} |`);
3828
3849
  const markdown = [headerRow, dividerRow, ...dataRows].join("\n");
3829
3850
  navigator.clipboard.writeText(markdown).then(() => {
@@ -3857,7 +3878,7 @@ return result;
3857
3878
  setSnippetName("");
3858
3879
  setShowSaveDialog(true);
3859
3880
  }, 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 }) }) }),
3881
+ 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
3882
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", color: "primary", disabled: isRunning || !activeTab?.code.trim(), onClick: () => executeCode(), children: [
3862
3883
  isRunning ? /* @__PURE__ */ jsxRuntime.jsx(ui.CircularProgress, { size: "smallest", className: "mr-2" }) : /* @__PURE__ */ jsxRuntime.jsx(ui.PlayIcon, { size: ui.iconSize.smallest, className: "mr-2" }),
3863
3884
  "Run"
@@ -3872,7 +3893,7 @@ return result;
3872
3893
  /* @__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
3894
  result && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3874
3895
  /* @__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: [
3896
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Tabs, { value: resultView, onValueChange: (val_2) => setResultView(val_2), variant: "pill", className: "w-[unset] mr-2", children: [
3876
3897
  /* @__PURE__ */ jsxRuntime.jsx(ui.Tab, { value: "json", children: "JSON" }),
3877
3898
  tableData.data.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(ui.Tab, { value: "table", children: "Table" }),
3878
3899
  result.console.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(ui.Tab, { value: "console", children: [
@@ -3921,7 +3942,7 @@ return result;
3921
3942
  rowIndex
3922
3943
  }) => {
3923
3944
  if (column.key === "__entity_action__") {
3924
- const rowActions = getRowEntityActions(rowData_0);
3945
+ const rowActions = getRowEntityActions(rowData_0 ?? {});
3925
3946
  if (rowActions.length === 0) return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full w-full" });
3926
3947
  if (rowActions.length === 1) {
3927
3948
  const ra = rowActions[0];
@@ -3951,8 +3972,8 @@ return result;
3951
3972
  }) }, ra_0.collection.collectionSlug)) }) });
3952
3973
  }
3953
3974
  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 ?? "");
3975
+ const val_3 = rowData_0[column.key];
3976
+ const displayValue = typeof val_3 === "object" && val_3 !== null ? JSON.stringify(val_3) : String(val_3 ?? "");
3956
3977
  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
3978
  } }) })
3958
3979
  ] }),
@@ -6842,10 +6863,27 @@ return result;
6842
6863
  }
6843
6864
  }
6844
6865
  load();
6845
- const t = setInterval(load, 15e3);
6866
+ let timeoutId = null;
6867
+ const scheduleNext = () => {
6868
+ if (cancelled) return;
6869
+ timeoutId = setTimeout(async () => {
6870
+ if (document.visibilityState === "visible") {
6871
+ await load();
6872
+ }
6873
+ scheduleNext();
6874
+ }, 15e3);
6875
+ };
6876
+ scheduleNext();
6877
+ const handleVisibility = () => {
6878
+ if (document.visibilityState === "visible") {
6879
+ load();
6880
+ }
6881
+ };
6882
+ document.addEventListener("visibilitychange", handleVisibility);
6846
6883
  return () => {
6847
6884
  cancelled = true;
6848
- clearInterval(t);
6885
+ if (timeoutId) clearTimeout(timeoutId);
6886
+ document.removeEventListener("visibilitychange", handleVisibility);
6849
6887
  };
6850
6888
  }, []);
6851
6889
  React.useEffect(() => {
@@ -9138,7 +9176,7 @@ return result;
9138
9176
  try {
9139
9177
  JSON.parse(body);
9140
9178
  } catch (err) {
9141
- setValidationError(`Invalid JSON: ${err.message}`);
9179
+ setValidationError(`Invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
9142
9180
  return;
9143
9181
  }
9144
9182
  }
@@ -9183,7 +9221,7 @@ return result;
9183
9221
  setResponse({
9184
9222
  status: 0,
9185
9223
  statusText: "Network Error",
9186
- body: err_0.message ?? "Request failed",
9224
+ body: err_0 instanceof Error ? err_0.message : "Request failed",
9187
9225
  time: Math.round(performance.now() - start)
9188
9226
  });
9189
9227
  } finally {
@@ -9511,7 +9549,7 @@ return result;
9511
9549
  }
9512
9550
  } catch (err) {
9513
9551
  if (!cancelled) {
9514
- setError(err.message ?? "Failed to load API spec");
9552
+ setError(err instanceof Error ? err.message : "Failed to load API spec");
9515
9553
  setLoading(false);
9516
9554
  }
9517
9555
  }
@@ -9617,6 +9655,165 @@ return result;
9617
9655
  __proto__: null,
9618
9656
  ApiExplorer
9619
9657
  }, Symbol.toStringTag, { value: "Module" }));
9658
+ const LEVEL_COLORS = {
9659
+ debug: "#6c7086",
9660
+ info: "#89b4fa",
9661
+ warn: "#f9e2af",
9662
+ error: "#f38ba8"
9663
+ };
9664
+ const SOURCE_COLORS = {
9665
+ api: "#74c7ec",
9666
+ auth: "#cba6f7",
9667
+ storage: "#a6e3a1",
9668
+ realtime: "#fab387",
9669
+ system: "#6c7086"
9670
+ };
9671
+ function LogsExplorer() {
9672
+ const [logs, setLogs] = React.useState([]);
9673
+ const [level, setLevel] = React.useState("");
9674
+ const [source, setSource] = React.useState("");
9675
+ const [search, setSearch] = React.useState("");
9676
+ const [autoScroll, setAutoScroll] = React.useState(true);
9677
+ const containerRef = React.useRef(null);
9678
+ const fetchLogs = React.useCallback(async () => {
9679
+ try {
9680
+ const params = new URLSearchParams();
9681
+ if (level) params.set("level", level);
9682
+ if (source) params.set("source", source);
9683
+ if (search) params.set("search", search);
9684
+ params.set("limit", "200");
9685
+ const resp = await fetch(`/api/logs?${params}`);
9686
+ if (resp.ok) {
9687
+ const data = await resp.json();
9688
+ setLogs(data.entries || []);
9689
+ }
9690
+ } catch {
9691
+ }
9692
+ }, [level, source, search]);
9693
+ React.useEffect(() => {
9694
+ let timeoutId = null;
9695
+ let cancelled = false;
9696
+ fetchLogs();
9697
+ const scheduleNext = () => {
9698
+ if (cancelled) return;
9699
+ timeoutId = setTimeout(async () => {
9700
+ if (document.visibilityState === "visible") {
9701
+ await fetchLogs();
9702
+ }
9703
+ scheduleNext();
9704
+ }, 3e3);
9705
+ };
9706
+ scheduleNext();
9707
+ const handleVisibility = () => {
9708
+ if (document.visibilityState === "visible") {
9709
+ fetchLogs();
9710
+ }
9711
+ };
9712
+ document.addEventListener("visibilitychange", handleVisibility);
9713
+ return () => {
9714
+ cancelled = true;
9715
+ if (timeoutId) clearTimeout(timeoutId);
9716
+ document.removeEventListener("visibilitychange", handleVisibility);
9717
+ };
9718
+ }, [fetchLogs]);
9719
+ React.useEffect(() => {
9720
+ if (autoScroll && containerRef.current) {
9721
+ containerRef.current.scrollTop = containerRef.current.scrollHeight;
9722
+ }
9723
+ }, [logs, autoScroll]);
9724
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
9725
+ display: "flex",
9726
+ flexDirection: "column",
9727
+ height: "calc(100vh - 64px)",
9728
+ background: "#1e1e2e",
9729
+ color: "#cdd6f4"
9730
+ }, children: [
9731
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
9732
+ display: "flex",
9733
+ gap: 8,
9734
+ padding: "8px 16px",
9735
+ borderBottom: "1px solid #313244",
9736
+ alignItems: "center",
9737
+ flexWrap: "wrap"
9738
+ }, children: [
9739
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Select, { value: level, onValueChange: setLevel, size: "small", placeholder: "All Levels", children: [
9740
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "", children: "All Levels" }),
9741
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "debug", children: "Debug" }),
9742
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "info", children: "Info" }),
9743
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "warn", children: "Warn" }),
9744
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "error", children: "Error" })
9745
+ ] }),
9746
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Select, { value: source, onValueChange: setSource, size: "small", placeholder: "All Sources", children: [
9747
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "", children: "All Sources" }),
9748
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "api", children: "API" }),
9749
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "auth", children: "Auth" }),
9750
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "storage", children: "Storage" }),
9751
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "realtime", children: "Realtime" }),
9752
+ /* @__PURE__ */ jsxRuntime.jsx(ui.SelectItem, { value: "system", children: "System" })
9753
+ ] }),
9754
+ /* @__PURE__ */ jsxRuntime.jsx(ui.TextField, { size: "small", placeholder: "Search logs...", value: search, onChange: (e) => setSearch(e.target.value), className: "flex-1 min-w-[200px]" }),
9755
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 cursor-pointer", children: [
9756
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Checkbox, { id: "auto-scroll", checked: autoScroll, onCheckedChange: setAutoScroll, size: "small", padding: false }),
9757
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "auto-scroll", className: "text-xs select-none cursor-pointer", children: "Auto-scroll" })
9758
+ ] }),
9759
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: {
9760
+ fontSize: 12,
9761
+ color: "#6c7086"
9762
+ }, children: [
9763
+ logs.length,
9764
+ " entries"
9765
+ ] })
9766
+ ] }),
9767
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, style: {
9768
+ flex: 1,
9769
+ overflow: "auto",
9770
+ fontFamily: "monospace",
9771
+ fontSize: 12,
9772
+ padding: "8px 0"
9773
+ }, children: [
9774
+ logs.map((log) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
9775
+ padding: "2px 16px",
9776
+ display: "flex",
9777
+ gap: 8,
9778
+ borderBottom: "1px solid #181825"
9779
+ }, children: [
9780
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
9781
+ color: "#6c7086",
9782
+ flexShrink: 0
9783
+ }, children: new Date(log.timestamp).toLocaleTimeString() }),
9784
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
9785
+ color: LEVEL_COLORS[log.level] || "#cdd6f4",
9786
+ width: 40,
9787
+ flexShrink: 0,
9788
+ textTransform: "uppercase",
9789
+ fontWeight: 600
9790
+ }, children: log.level }),
9791
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: {
9792
+ color: SOURCE_COLORS[log.source] || "#cdd6f4",
9793
+ width: 64,
9794
+ flexShrink: 0
9795
+ }, children: [
9796
+ "[",
9797
+ log.source,
9798
+ "]"
9799
+ ] }),
9800
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
9801
+ color: "#cdd6f4",
9802
+ flex: 1
9803
+ }, children: log.message })
9804
+ ] }, log.id)),
9805
+ logs.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
9806
+ padding: 32,
9807
+ textAlign: "center",
9808
+ color: "#6c7086"
9809
+ }, children: "No log entries yet. Logs will appear here as requests come in." })
9810
+ ] })
9811
+ ] });
9812
+ }
9813
+ const LogsExplorer$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
9814
+ __proto__: null,
9815
+ LogsExplorer
9816
+ }, Symbol.toStringTag, { value: "Module" }));
9620
9817
  Object.defineProperty(exports2, "StudioBridgeContext", {
9621
9818
  enumerable: true,
9622
9819
  get: () => core.StudioBridgeContext