@lunora/studio 0.0.0 → 1.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/LICENSE.md +105 -0
  2. package/README.md +123 -9
  3. package/__assets__/package-og.svg +14 -0
  4. package/dist/index.d.ts +1402 -0
  5. package/dist/index.js +41 -0
  6. package/dist/mount.d.ts +21 -0
  7. package/dist/mount.js +26 -0
  8. package/dist/packem_shared/ADMIN_FUNCTION_PREFIX-DmBqMZ-z.js +45 -0
  9. package/dist/packem_shared/ApiDocsPanel-DpRjJhG5.js +842 -0
  10. package/dist/packem_shared/ApiReferencePanel-DMIUp-kK.js +229 -0
  11. package/dist/packem_shared/ApiTab-DURGU15e.js +251 -0
  12. package/dist/packem_shared/AuditPanel-BC59Nhst.js +212 -0
  13. package/dist/packem_shared/CommandPalette-Dx_CoB9i.js +373 -0
  14. package/dist/packem_shared/ConfirmButton-WQVUoGFb.js +59 -0
  15. package/dist/packem_shared/ConnectionBadge-Bxagrip8.js +111 -0
  16. package/dist/packem_shared/DEFAULT_AUTO_REFRESH_MS-Vxwaxx51.js +50 -0
  17. package/dist/packem_shared/DEFAULT_INSIGHT_THRESHOLDS-DjF0h-gA.js +89 -0
  18. package/dist/packem_shared/DataBrowser-Coz6jJE6.js +4542 -0
  19. package/dist/packem_shared/DataFilters-FNquMaiu.js +249 -0
  20. package/dist/packem_shared/ErrorBoundary-BzAApI7J.js +66 -0
  21. package/dist/packem_shared/ExportImportPanel-WO34fJxy.js +193 -0
  22. package/dist/packem_shared/FileBrowser-Zcr-Qgxo.js +2932 -0
  23. package/dist/packem_shared/FunctionRunner-j0Rd5m9t.js +343 -0
  24. package/dist/packem_shared/FunctionStatsPanel-DboBl-XL.js +432 -0
  25. package/dist/packem_shared/GlobalDataBrowser-9MhPEfgN.js +318 -0
  26. package/dist/packem_shared/HealthPanel-DOIgbUtx.js +640 -0
  27. package/dist/packem_shared/HomePanel-bdOCNA-p.js +1273 -0
  28. package/dist/packem_shared/InsightsPanel-DaZPnSgt.js +423 -0
  29. package/dist/packem_shared/LogsPanel-CWdqAGpQ.js +839 -0
  30. package/dist/packem_shared/MailPanel-D_EGtDnS.js +447 -0
  31. package/dist/packem_shared/MetricsPanel-E4Gv6wTO.js +1625 -0
  32. package/dist/packem_shared/MigrationsPanel-DQdPY9io.js +246 -0
  33. package/dist/packem_shared/OpenRpcReferencePanel-j2p3HB0s.js +191 -0
  34. package/dist/packem_shared/PitrPanel-BbBkQR6t.js +252 -0
  35. package/dist/packem_shared/STUDIO_ROOT_CLASS-D12gX2dV.js +3 -0
  36. package/dist/packem_shared/ScheduledJobs-Ok1CYYwI.js +159 -0
  37. package/dist/packem_shared/SchemaViewer-D8XGnp-X.js +2512 -0
  38. package/dist/packem_shared/SecurityAdvisorPanel-Cdm2IxLW.js +79 -0
  39. package/dist/packem_shared/SettingsPanel-D3WF2mBU.js +176 -0
  40. package/dist/packem_shared/ShardInput-DNCsT1KW.js +107 -0
  41. package/dist/packem_shared/SqlEditorPanel-BuQ7f2Hs.js +13 -0
  42. package/dist/packem_shared/Studio-D36od9Oz.js +33 -0
  43. package/dist/packem_shared/StudioApp-dvywkJ8I.js +383 -0
  44. package/dist/packem_shared/StudioI18nProvider-Dcajsznk.js +48 -0
  45. package/dist/packem_shared/TableEditor-DIVDk3vT.js +371 -0
  46. package/dist/packem_shared/advisor-view-DBlzJi6C.js +159 -0
  47. package/dist/packem_shared/aggregateMetrics-D4nUHEKU.js +108 -0
  48. package/dist/packem_shared/app.d-CCmwDEVs.d.ts +300 -0
  49. package/dist/packem_shared/badge-B2PKA1-5.js +49 -0
  50. package/dist/packem_shared/bar-chart-CzJAgqkp.js +3245 -0
  51. package/dist/packem_shared/button-BhsN2uZH.js +49 -0
  52. package/dist/packem_shared/card-DURq3ElK.js +175 -0
  53. package/dist/packem_shared/cf-links-BZfRdxSE.js +8 -0
  54. package/dist/packem_shared/checkbox-UNkzAxl-.js +63 -0
  55. package/dist/packem_shared/createStudioI18n-CgvlmDkN.js +27 -0
  56. package/dist/packem_shared/data-grid-CCh2Couo.js +183 -0
  57. package/dist/packem_shared/dropdown-menu-WY4B_eJO.js +280 -0
  58. package/dist/packem_shared/empty-state-DY_oe0k6.js +98 -0
  59. package/dist/packem_shared/grid-features-DTjG6Sex.js +840 -0
  60. package/dist/packem_shared/input-XH4r1Pt1.js +53 -0
  61. package/dist/packem_shared/internal-BBZYexre.js +68 -0
  62. package/dist/packem_shared/label-D8ykjn5J.js +46 -0
  63. package/dist/packem_shared/live-status-bPff1O7Y.js +44 -0
  64. package/dist/packem_shared/reference-view-BCKIoai7.js +2180 -0
  65. package/dist/packem_shared/shard-history-DyebH1R5.js +38 -0
  66. package/dist/packem_shared/sparkline-10dG-_f0.js +93 -0
  67. package/dist/packem_shared/sql-editor-panel-CW2y2x9h.js +2562 -0
  68. package/dist/packem_shared/storage-tier-CL98eOvn.js +85 -0
  69. package/dist/packem_shared/studio-BDVd7rIV.js +10303 -0
  70. package/dist/packem_shared/table-_RzNvy3R.js +246 -0
  71. package/dist/packem_shared/table-list-sidebar-aZHLq70w.js +832 -0
  72. package/dist/packem_shared/textarea-D3gaCU_-.js +46 -0
  73. package/dist/packem_shared/use-live-admin-D1h1Fzsd.js +73 -0
  74. package/dist/packem_shared/use-live-shard-seed-B74RYcOy.js +76 -0
  75. package/dist/packem_shared/useDebounced-Dxncpg6z.js +32 -0
  76. package/dist/packem_shared/utils-B05Dmz_H.js +8 -0
  77. package/dist/packem_shared/virtual-rect-CVMUskSm.js +10 -0
  78. package/dist/standalone/studio.js +356 -0
  79. package/dist/styles.css +2 -0
  80. package/package.json +77 -17
  81. package/src/theme.css +59 -0
@@ -0,0 +1,318 @@
1
+ import { useLunora } from '@lunora/react';
2
+ import { useState, useRef, useCallback, useEffect } from 'react';
3
+ import { E as EmptyState } from './empty-state-DY_oe0k6.js';
4
+ import { T as Table, a as TableHeader, b as TableRow, c as TableHead, d as TableBody, e as TableCell } from './table-_RzNvy3R.js';
5
+ import { useAutoRefresh } from './DEFAULT_AUTO_REFRESH_MS-Vxwaxx51.js';
6
+ import { useT } from './createStudioI18n-CgvlmDkN.js';
7
+ import { C as CLOUDFLARE_D1_URL } from './cf-links-BZfRdxSE.js';
8
+ import { e as errorMessage, f as fireAndForget } from './internal-BBZYexre.js';
9
+ import { u as useFacets, T as TableListSidebar, G as GridPagination, D as DataFacets } from './table-list-sidebar-aZHLq70w.js';
10
+ import { G as GridContainer, C as CellValue } from './data-grid-CCh2Couo.js';
11
+ import { jsxDEV } from 'react/jsx-dev-runtime';
12
+
13
+ const DEFAULT_PAGE_SIZE = 50;
14
+ const NO_TABLES = [];
15
+ const NO_COLUMNS = [];
16
+ const rowKey = (row, index) => {
17
+ const id = row["_id"];
18
+ return typeof id === "string" || typeof id === "number" ? String(id) : `row-${index.toString()}`;
19
+ };
20
+ const chipValue = (value) => {
21
+ if (value === null || value === void 0) {
22
+ return "∅";
23
+ }
24
+ if (value === "") {
25
+ return "(empty)";
26
+ }
27
+ if (typeof value === "object") {
28
+ return JSON.stringify(value);
29
+ }
30
+ return String(value);
31
+ };
32
+ const GlobalDataBrowser = ({
33
+ initialTable,
34
+ onSelectTable,
35
+ pageSize: initialPageSize = DEFAULT_PAGE_SIZE,
36
+ schemaSwitch
37
+ } = {}) => {
38
+ const client = useLunora();
39
+ const t = useT();
40
+ const [tables, setTables] = useState(null);
41
+ const [tablesError, setTablesError] = useState(null);
42
+ const [selectedTable, setSelectedTable] = useState(initialTable ?? null);
43
+ const [offset, setOffset] = useState(0);
44
+ const [pageSize, setPageSize] = useState(initialPageSize);
45
+ const [page, setPage] = useState(null);
46
+ const [pageError, setPageError] = useState(null);
47
+ const [filters, setFilters] = useState([]);
48
+ const filtersRef = useRef(filters);
49
+ filtersRef.current = filters;
50
+ const {
51
+ clearFacets,
52
+ facets,
53
+ refetchFacets: refetchFacetsViaHook,
54
+ toggleFacet
55
+ } = useFacets();
56
+ const fetchTables = useCallback(async () => {
57
+ setTablesError(null);
58
+ try {
59
+ setTables(await client.listGlobalTables());
60
+ } catch (error) {
61
+ setTables(null);
62
+ setTablesError(errorMessage(error));
63
+ }
64
+ }, [client]);
65
+ const fetchSeqRef = useRef(0);
66
+ const fetchPage = useCallback(async (table, nextOffset, limit = pageSize, activeFilters = filtersRef.current) => {
67
+ fetchSeqRef.current += 1;
68
+ const seq = fetchSeqRef.current;
69
+ setPageError(null);
70
+ try {
71
+ const result = await client.readGlobalTablePage({
72
+ filters: activeFilters,
73
+ limit,
74
+ offset: nextOffset,
75
+ table
76
+ });
77
+ if (fetchSeqRef.current !== seq) {
78
+ return;
79
+ }
80
+ setPage(result);
81
+ setOffset(nextOffset);
82
+ } catch (error_0) {
83
+ if (fetchSeqRef.current !== seq) {
84
+ return;
85
+ }
86
+ setPage(null);
87
+ setPageError(errorMessage(error_0));
88
+ }
89
+ }, [client, pageSize]);
90
+ const facetFetcher = (table_0, activeFilters_0) => (column) => client.facetGlobalColumn({
91
+ column,
92
+ filters: activeFilters_0,
93
+ table: table_0
94
+ });
95
+ const refetchFacets = (table_1, activeFilters_1) => {
96
+ refetchFacetsViaHook(facetFetcher(table_1, activeFilters_1));
97
+ };
98
+ useEffect(() => {
99
+ fireAndForget(fetchTables());
100
+ }, [fetchTables]);
101
+ useAutoRefresh(() => {
102
+ fireAndForget(fetchTables());
103
+ if (selectedTable !== null) {
104
+ fireAndForget(fetchPage(selectedTable, offset));
105
+ refetchFacets(selectedTable, filtersRef.current);
106
+ }
107
+ }, true);
108
+ const appliedInitialTable = useRef(void 0);
109
+ const selectTable = useCallback((table_2) => {
110
+ setSelectedTable(table_2);
111
+ appliedInitialTable.current = table_2;
112
+ setFilters([]);
113
+ filtersRef.current = [];
114
+ clearFacets();
115
+ fireAndForget(fetchPage(table_2, 0, pageSize, []));
116
+ onSelectTable?.(table_2);
117
+ }, [clearFacets, fetchPage, onSelectTable, pageSize]);
118
+ const onToggleFacet = (column_0) => {
119
+ toggleFacet(column_0, selectedTable === null ? null : facetFetcher(selectedTable, filtersRef.current));
120
+ };
121
+ const applyFilters = (next) => {
122
+ setFilters(next);
123
+ filtersRef.current = next;
124
+ if (selectedTable !== null) {
125
+ fireAndForget(fetchPage(selectedTable, 0, pageSize, next));
126
+ refetchFacets(selectedTable, next);
127
+ }
128
+ };
129
+ const onFacetFilter = (column_1, value) => {
130
+ applyFilters([...filtersRef.current.filter((clause) => clause.column !== column_1), {
131
+ column: column_1,
132
+ value
133
+ }]);
134
+ };
135
+ const removeFilter = (event) => {
136
+ const index = Number(event.currentTarget.dataset["index"]);
137
+ applyFilters(filtersRef.current.filter((_, position) => position !== index));
138
+ };
139
+ useEffect(() => {
140
+ if (initialTable === void 0 || initialTable === "" || appliedInitialTable.current === initialTable) {
141
+ return;
142
+ }
143
+ appliedInitialTable.current = initialTable;
144
+ const target = initialTable;
145
+ queueMicrotask(() => {
146
+ selectTable(target);
147
+ });
148
+ }, [initialTable, selectTable]);
149
+ const goToPage = (nextOffset_0) => {
150
+ if (selectedTable === null) {
151
+ return;
152
+ }
153
+ fireAndForget(fetchPage(selectedTable, Math.max(0, nextOffset_0)));
154
+ };
155
+ const total = page?.total ?? 0;
156
+ const hasPrevious = offset > 0;
157
+ const hasNext = page !== null && offset + page.rows.length < total;
158
+ const rangeStart = page === null || page.rows.length === 0 ? 0 : offset + 1;
159
+ const rangeEnd = page === null ? 0 : offset + page.rows.length;
160
+ const reloadTables = () => {
161
+ fireAndForget(fetchTables());
162
+ };
163
+ const goPrevious = () => {
164
+ goToPage(offset - pageSize);
165
+ };
166
+ const goNext = () => {
167
+ goToPage(offset + pageSize);
168
+ };
169
+ const jumpToPage = (targetPage) => {
170
+ goToPage(Math.max(0, (targetPage - 1) * pageSize));
171
+ };
172
+ const changePageSize = (size) => {
173
+ setPageSize(size);
174
+ if (selectedTable !== null) {
175
+ fireAndForget(fetchPage(selectedTable, 0, size));
176
+ }
177
+ };
178
+ return /* @__PURE__ */ jsxDEV("div", {
179
+ className: "flex h-full min-w-0",
180
+ "data-testid": "lunora-global-data-browser",
181
+ children: [/* @__PURE__ */ jsxDEV(TableListSidebar, {
182
+ header: /* @__PURE__ */ jsxDEV("div", {
183
+ className: "flex shrink-0 flex-col items-stretch gap-2 border-b border-border p-3",
184
+ children: [schemaSwitch, /* @__PURE__ */ jsxDEV("a", {
185
+ className: "text-sm text-primary underline-offset-4 hover:underline",
186
+ "data-testid": "gdb-cf-link",
187
+ href: CLOUDFLARE_D1_URL,
188
+ rel: "noreferrer",
189
+ target: "_blank",
190
+ children: t("Open in Cloudflare")
191
+ }, void 0, false)]
192
+ }, void 0, true),
193
+ onReload: reloadTables,
194
+ onSelect: selectTable,
195
+ prefix: "gdb",
196
+ selected: selectedTable,
197
+ tables: tables ?? NO_TABLES
198
+ }, void 0, false), /* @__PURE__ */ jsxDEV("div", {
199
+ className: "flex min-w-0 flex-1 flex-col overflow-hidden",
200
+ children: [tablesError !== null && /* @__PURE__ */ jsxDEV("p", {
201
+ className: "shrink-0 border-b border-border px-4 py-2 text-sm text-destructive",
202
+ "data-testid": "gdb-tables-error",
203
+ role: "alert",
204
+ children: tablesError
205
+ }, void 0, false), tables !== null && tables.length === 0 && /* @__PURE__ */ jsxDEV("div", {
206
+ className: "flex flex-1 items-center justify-center p-6",
207
+ children: /* @__PURE__ */ jsxDEV(EmptyState, {
208
+ description: t("Tables marked .global() (D1-backed, region-replicated) will appear here."),
209
+ icon: /* @__PURE__ */ jsxDEV("svg", {
210
+ "aria-hidden": "true",
211
+ fill: "none",
212
+ stroke: "currentColor",
213
+ strokeLinecap: "round",
214
+ strokeLinejoin: "round",
215
+ strokeWidth: 1.6,
216
+ viewBox: "0 0 24 24",
217
+ children: [/* @__PURE__ */ jsxDEV("circle", {
218
+ cx: "12",
219
+ cy: "12",
220
+ r: "9"
221
+ }, void 0, false), /* @__PURE__ */ jsxDEV("path", {
222
+ d: "M3 12h18M12 3a14 14 0 0 1 0 18 14 14 0 0 1 0-18Z"
223
+ }, void 0, false)]
224
+ }, void 0, true),
225
+ testId: "gdb-empty",
226
+ title: t("No global tables.")
227
+ }, void 0, false)
228
+ }, void 0, false), pageError !== null && /* @__PURE__ */ jsxDEV("p", {
229
+ className: "shrink-0 border-b border-border px-4 py-2 text-sm text-destructive",
230
+ "data-testid": "gdb-page-error",
231
+ role: "alert",
232
+ children: pageError
233
+ }, void 0, false), tables !== null && tables.length > 0 && page === null && pageError === null && /* @__PURE__ */ jsxDEV("div", {
234
+ className: "flex flex-1 items-center justify-center p-6",
235
+ children: /* @__PURE__ */ jsxDEV("p", {
236
+ className: "text-sm text-muted-foreground",
237
+ children: t("Select a table to browse its rows.")
238
+ }, void 0, false)
239
+ }, void 0, false), page !== null && /* @__PURE__ */ jsxDEV("div", {
240
+ className: "flex min-h-0 flex-1 flex-col",
241
+ "data-testid": "gdb-page",
242
+ children: [filters.length > 0 && /* @__PURE__ */ jsxDEV("div", {
243
+ className: "flex shrink-0 flex-wrap items-center gap-1.5 border-b border-border px-4 py-2 text-xs",
244
+ "data-testid": "gdb-filters",
245
+ children: filters.map((filter, index_0) => /* @__PURE__ */ jsxDEV("span", {
246
+ className: "inline-flex items-center gap-1 rounded border border-border bg-muted px-1.5 py-0.5",
247
+ "data-testid": "gdb-filter-chip",
248
+ children: [/* @__PURE__ */ jsxDEV("span", {
249
+ className: "font-medium text-foreground",
250
+ children: filter.column
251
+ }, void 0, false), /* @__PURE__ */ jsxDEV("span", {
252
+ className: "text-muted-foreground",
253
+ children: "="
254
+ }, void 0, false), /* @__PURE__ */ jsxDEV("span", {
255
+ className: "font-mono text-foreground",
256
+ children: chipValue(filter.value)
257
+ }, void 0, false), /* @__PURE__ */ jsxDEV("button", {
258
+ "aria-label": t("Remove filter"),
259
+ className: "ml-0.5 text-muted-foreground hover:text-foreground",
260
+ "data-index": index_0,
261
+ "data-testid": "gdb-filter-remove",
262
+ onClick: removeFilter,
263
+ type: "button",
264
+ children: "✕"
265
+ }, void 0, false)]
266
+ }, `${filter.column}:${chipValue(filter.value)}`, true))
267
+ }, void 0, false), /* @__PURE__ */ jsxDEV(GridContainer, {
268
+ layout: "fill",
269
+ children: /* @__PURE__ */ jsxDEV("div", {
270
+ className: "min-h-0 flex-1 overflow-auto",
271
+ children: /* @__PURE__ */ jsxDEV(Table, {
272
+ "data-testid": "gdb-rows",
273
+ children: [/* @__PURE__ */ jsxDEV(TableHeader, {
274
+ children: /* @__PURE__ */ jsxDEV(TableRow, {
275
+ children: page.columns.map((column_2) => /* @__PURE__ */ jsxDEV(TableHead, {
276
+ children: column_2
277
+ }, column_2, false))
278
+ }, void 0, false)
279
+ }, void 0, false), /* @__PURE__ */ jsxDEV(TableBody, {
280
+ children: page.rows.map((row, rowIndex) => /* @__PURE__ */ jsxDEV(TableRow, {
281
+ "data-testid": "gdb-row",
282
+ children: page.columns.map((column_3) => /* @__PURE__ */ jsxDEV(TableCell, {
283
+ className: "max-w-xs truncate font-mono text-xs",
284
+ children: /* @__PURE__ */ jsxDEV(CellValue, {
285
+ value: row[column_3]
286
+ }, void 0, false)
287
+ }, column_3, false))
288
+ }, rowKey(row, rowIndex), false))
289
+ }, void 0, false)]
290
+ }, void 0, true)
291
+ }, void 0, false)
292
+ }, void 0, false), /* @__PURE__ */ jsxDEV("div", {
293
+ className: "flex shrink-0 items-center border-t border-border px-4 py-2",
294
+ children: /* @__PURE__ */ jsxDEV(GridPagination, {
295
+ hasNext,
296
+ hasPrevious,
297
+ onJumpToPage: jumpToPage,
298
+ onNext: goNext,
299
+ onPageSizeChange: changePageSize,
300
+ onPrevious: goPrevious,
301
+ pageSize,
302
+ prefix: "gdb",
303
+ rangeEnd,
304
+ rangeStart,
305
+ total
306
+ }, void 0, false)
307
+ }, void 0, false)]
308
+ }, void 0, true)]
309
+ }, void 0, true), /* @__PURE__ */ jsxDEV(DataFacets, {
310
+ columns: page?.columns ?? NO_COLUMNS,
311
+ facets,
312
+ onFacetFilter,
313
+ onToggleFacet
314
+ }, void 0, false)]
315
+ }, void 0, true);
316
+ };
317
+
318
+ export { GlobalDataBrowser };