@lunora/studio 1.0.0-alpha.3 → 1.0.0-alpha.30

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 (174) hide show
  1. package/__assets__/package-og.svg +1 -1
  2. package/dist/index.d.ts +29 -18
  3. package/dist/index.js +29 -29
  4. package/dist/mount.d.ts +1 -1
  5. package/dist/mount.js +1 -1
  6. package/dist/{packem_shared/ApiTab-W3no0KOj.js → packem_chunks/ApiTab.js} +5 -5
  7. package/dist/{packem_shared/AuditPanel-Bq4o_IqT.js → packem_chunks/AuditPanel.js} +24 -36
  8. package/dist/{packem_shared/ExportImportPanel-dxY56TDF.js → packem_chunks/ExportImportPanel.js} +13 -9
  9. package/dist/{packem_shared/FileBrowser-Dhy4zES8.js → packem_chunks/FileBrowser.js} +15 -15
  10. package/dist/{packem_shared/FunctionRunner--fQJRPAD.js → packem_chunks/FunctionRunner.js} +10 -10
  11. package/dist/{packem_shared/FunctionStatsPanel-BjRUA_G3.js → packem_chunks/FunctionStatsPanel.js} +147 -204
  12. package/dist/{packem_shared/HealthPanel-PxclMWmA.js → packem_chunks/HealthPanel.js} +37 -29
  13. package/dist/{packem_shared/InsightsPanel-CWS_C-xW.js → packem_chunks/InsightsPanel.js} +107 -69
  14. package/dist/{packem_shared/LogsPanel-CTW8CFcM.js → packem_chunks/LogsPanel.js} +41 -53
  15. package/dist/{packem_shared/MailPanel-BwkvfIHF.js → packem_chunks/MailPanel.js} +37 -44
  16. package/dist/{packem_shared/MetricsPanel-BLuOhZQ4.js → packem_chunks/MetricsPanel.js} +41 -322
  17. package/dist/{packem_shared/MigrationsPanel-DT3lnwHF.js → packem_chunks/MigrationsPanel.js} +39 -46
  18. package/dist/{packem_shared/PitrPanel-CdErL7EJ.js → packem_chunks/PitrPanel.js} +9 -9
  19. package/dist/{packem_shared/SchemaViewer-LJDcmNIO.js → packem_chunks/SchemaViewer.js} +15 -15
  20. package/dist/{packem_shared/SecurityAdvisorPanel-C_ETsPih.js → packem_chunks/SecurityAdvisorPanel.js} +44 -31
  21. package/dist/packem_chunks/SettingsPanel.js +390 -0
  22. package/dist/{packem_shared/sql-editor-panel-BFRpzj6r.js → packem_chunks/SqlEditorPanel.js} +12 -252
  23. package/dist/{packem_shared/TableEditor-ChfUOZec.js → packem_chunks/TableEditor.js} +10 -68
  24. package/dist/packem_chunks/analytics-panel.js +261 -0
  25. package/dist/packem_chunks/auth-config-panel.js +179 -0
  26. package/dist/packem_chunks/auth-sessions-panel.js +175 -0
  27. package/dist/packem_chunks/dashboards-panel.js +779 -0
  28. package/dist/packem_chunks/fanout-panel.js +481 -0
  29. package/dist/packem_chunks/flags-panel.js +176 -0
  30. package/dist/packem_chunks/kv-browser.js +1896 -0
  31. package/dist/packem_chunks/log-drains-panel.js +273 -0
  32. package/dist/packem_chunks/organizations-panel.js +670 -0
  33. package/dist/packem_chunks/payments-panel.js +185 -0
  34. package/dist/packem_chunks/permissions-panel.js +804 -0
  35. package/dist/packem_chunks/queues-panel.js +147 -0
  36. package/dist/packem_chunks/rls-panel.js +313 -0
  37. package/dist/packem_chunks/schedule-panel.js +831 -0
  38. package/dist/packem_chunks/sparkline.js +79 -0
  39. package/dist/packem_chunks/storage-rules-panel.js +138 -0
  40. package/dist/packem_chunks/subscriptions-panel.js +236 -0
  41. package/dist/packem_chunks/users-panel.js +1265 -0
  42. package/dist/packem_chunks/vector-browser.js +281 -0
  43. package/dist/packem_chunks/workflows-panel.js +562 -0
  44. package/dist/packem_shared/{ADMIN_FUNCTIONS-DmBqMZ-z.js → ADMIN_FUNCTIONS-CdaxLGkE.js} +3 -0
  45. package/dist/packem_shared/{ApiDocsPanel-C5-yJ1p7.js → ApiDocsPanel-B6u_wnz-.js} +2 -2
  46. package/dist/packem_shared/{ApiReferencePanel-1vubqG5s.js → ApiReferencePanel-Drz4UO0a.js} +2 -1
  47. package/dist/packem_shared/{CommandPalette-BtgkBzZI.js → CommandPalette-B5BertvU.js} +1 -1
  48. package/dist/packem_shared/{DataBrowser-CtBe1So9.js → DataBrowser-ANTHLWWh.js} +198 -247
  49. package/dist/packem_shared/{GlobalDataBrowser-BTEmGrph.js → GlobalDataBrowser-CjgTG_wa.js} +37 -66
  50. package/dist/packem_shared/HomePanel-c2FodE9t.js +14 -0
  51. package/dist/packem_shared/{OpenRpcReferencePanel-vbcYbv3V.js → OpenRpcReferencePanel-CspFdbUT.js} +2 -1
  52. package/dist/packem_shared/{ScheduledJobs-CabfKbyM.js → ScheduledJobs-BEJXtsBn.js} +163 -60
  53. package/dist/packem_shared/Studio-CVTtA_sB.js +16 -0
  54. package/dist/packem_shared/{StudioApp-CHOZA-z-.js → StudioApp-BSYV2fz6.js} +277 -3
  55. package/dist/packem_shared/{advisor-view-CGcfMiPq.js → advisor-view-DzqyvUU3.js} +1 -1
  56. package/dist/packem_shared/{app.d-CCmwDEVs.d.ts → app.d-B6MyY_al.d.ts} +1 -1
  57. package/dist/packem_shared/{bar-chart-CzJAgqkp.js → bar-chart-Bb__F5-u.js} +1 -1
  58. package/dist/packem_shared/browser-storage-d03UsV7v.js +249 -0
  59. package/dist/packem_shared/{cf-links-2cktDedA.js → cf-links-BZfRdxSE.js} +1 -1
  60. package/dist/packem_shared/{data-grid-B5CaV3wS.js → data-grid-Dsg6nRjo.js} +1 -1
  61. package/dist/packem_shared/data-view-params-Cd6yRVbv.js +96 -0
  62. package/dist/packem_shared/{grid-features-CzUfqgsM.js → grid-features-D7nNzBYm.js} +4 -99
  63. package/dist/packem_shared/{HomePanel-Cw16stjq.js → home-panel-aOR_drVv.js} +833 -469
  64. package/dist/packem_shared/{internal-rXJEAhXS.js → internal-FcNZ3beb.js} +1 -1
  65. package/dist/packem_shared/modal-shell-hyaJvIJ6.js +100 -0
  66. package/dist/packem_shared/{reference-view-B4E49Lip.js → reference-view-Doy1XlQq.js} +4 -44
  67. package/dist/packem_shared/select-UkNYCT3s.js +273 -0
  68. package/dist/packem_shared/skeleton-CGhL0p20.js +45 -0
  69. package/dist/packem_shared/{sparkline-10dG-_f0.js → sparkline-KgMPHS4u.js} +1 -1
  70. package/dist/packem_shared/studio-dMTJ-kRR.js +3987 -0
  71. package/dist/packem_shared/{table-_RzNvy3R.js → table-DsCa9Qp9.js} +1 -1
  72. package/dist/packem_shared/{table-list-sidebar-Bg7uzbvC.js → table-list-sidebar-VMo0ftxD.js} +1 -1
  73. package/dist/packem_shared/use-admin-query-BViPA3US.js +105 -0
  74. package/dist/packem_shared/use-auth-capabilities-BHkoBnbZ.js +32 -0
  75. package/dist/standalone/chunk-2DS7JLWL.js +13 -0
  76. package/dist/standalone/chunk-2K47A3P6.js +1 -0
  77. package/dist/standalone/chunk-2NGUNNGW.js +1 -0
  78. package/dist/standalone/chunk-2PDQ4KZ6.js +1 -0
  79. package/dist/standalone/chunk-3BP4BTLR.js +4 -0
  80. package/dist/standalone/chunk-3OA7PECS.js +6 -0
  81. package/dist/standalone/chunk-4QHKBC77.js +1 -0
  82. package/dist/standalone/chunk-57LYXHXH.js +1 -0
  83. package/dist/standalone/chunk-5NSZVXCS.js +1 -0
  84. package/dist/standalone/chunk-5OIBXYZM.js +1 -0
  85. package/dist/standalone/chunk-63XKJQTQ.js +1 -0
  86. package/dist/standalone/chunk-6RC6L33K.js +4 -0
  87. package/dist/standalone/chunk-6VTGE3WJ.js +1 -0
  88. package/dist/standalone/chunk-7PBZKXYA.js +1 -0
  89. package/dist/standalone/chunk-7POIIWC5.js +3 -0
  90. package/dist/standalone/chunk-7RYIQKZA.js +1 -0
  91. package/dist/standalone/chunk-7TJJXVSE.js +1 -0
  92. package/dist/standalone/chunk-AB6QGMBF.js +1 -0
  93. package/dist/standalone/chunk-AHILM3ZP.js +1 -0
  94. package/dist/standalone/chunk-AQGOX5DK.js +1 -0
  95. package/dist/standalone/chunk-ASLGNHAX.js +1 -0
  96. package/dist/standalone/chunk-BHTPZS7L.js +4 -0
  97. package/dist/standalone/chunk-BJGBHGK3.js +1 -0
  98. package/dist/standalone/chunk-D7HKX4DI.js +1 -0
  99. package/dist/standalone/chunk-DGWTR4G7.js +1 -0
  100. package/dist/standalone/chunk-DSX53PBM.js +1 -0
  101. package/dist/standalone/chunk-DV2MNASX.js +1 -0
  102. package/dist/standalone/chunk-DWDILV2E.js +1 -0
  103. package/dist/standalone/chunk-E7AVZZKO.js +1 -0
  104. package/dist/standalone/chunk-EGJX34WM.js +1 -0
  105. package/dist/standalone/chunk-FCR3HKFV.js +1 -0
  106. package/dist/standalone/chunk-FKO3HO6I.js +4 -0
  107. package/dist/standalone/chunk-FQKNJSRA.js +76 -0
  108. package/dist/standalone/chunk-G2TFEWEQ.js +4 -0
  109. package/dist/standalone/chunk-GABMIICA.js +1 -0
  110. package/dist/standalone/chunk-GTM65MVX.js +1 -0
  111. package/dist/standalone/chunk-GZXPPJVK.js +1 -0
  112. package/dist/standalone/chunk-HFBRE65A.js +1 -0
  113. package/dist/standalone/chunk-HFMQNUBC.js +1 -0
  114. package/dist/standalone/chunk-HG7Q5B3H.js +1 -0
  115. package/dist/standalone/chunk-HTQL7AXU.js +1 -0
  116. package/dist/standalone/chunk-HV7G6DFP.js +5 -0
  117. package/dist/standalone/chunk-ITLLHEVG.js +1 -0
  118. package/dist/standalone/chunk-J6J54MBP.js +1 -0
  119. package/dist/standalone/chunk-JSEXCW5Q.js +1 -0
  120. package/dist/standalone/chunk-KEGAWN6Y.js +1 -0
  121. package/dist/standalone/chunk-KG3QTFWE.js +1 -0
  122. package/dist/standalone/chunk-KGS7KM4A.js +2 -0
  123. package/dist/standalone/chunk-KODWGUAB.js +1 -0
  124. package/dist/standalone/chunk-KZ6INM5M.js +1 -0
  125. package/dist/standalone/chunk-MGFEVTRI.js +1 -0
  126. package/dist/standalone/chunk-N2QDG3MW.js +1 -0
  127. package/dist/standalone/chunk-N4JI6VQD.js +1 -0
  128. package/dist/standalone/chunk-NNISYDNI.js +1 -0
  129. package/dist/standalone/chunk-O4PXDNR3.js +1 -0
  130. package/dist/standalone/chunk-O77VNUFD.js +1 -0
  131. package/dist/standalone/chunk-OD2POGPJ.js +1 -0
  132. package/dist/standalone/chunk-OXCK3ZUG.js +1 -0
  133. package/dist/standalone/chunk-P7DSVO4U.js +1 -0
  134. package/dist/standalone/chunk-PKAM3N5C.js +1 -0
  135. package/dist/standalone/chunk-QGXGBHQO.js +1 -0
  136. package/dist/standalone/chunk-QHA3TAEJ.js +1 -0
  137. package/dist/standalone/chunk-QQWC62X7.js +1 -0
  138. package/dist/standalone/chunk-RMYA7NAH.js +1 -0
  139. package/dist/standalone/chunk-RRCPZMC2.js +22 -0
  140. package/dist/standalone/chunk-S53RUBW5.js +1 -0
  141. package/dist/standalone/chunk-SB4GT6PK.js +1 -0
  142. package/dist/standalone/chunk-SEU5V7I6.js +1 -0
  143. package/dist/standalone/chunk-SHIOUDOT.js +1 -0
  144. package/dist/standalone/chunk-SIDRSX7Y.js +1 -0
  145. package/dist/standalone/chunk-SVR644RF.js +1 -0
  146. package/dist/standalone/chunk-TAD43CG5.js +1 -0
  147. package/dist/standalone/chunk-TBMYIZIO.js +1 -0
  148. package/dist/standalone/chunk-TICVNLPM.js +1 -0
  149. package/dist/standalone/chunk-TQ36RWOP.js +1 -0
  150. package/dist/standalone/chunk-UGMRUEBU.js +1 -0
  151. package/dist/standalone/chunk-UII66UVF.js +1 -0
  152. package/dist/standalone/chunk-VJPQUBN6.js +8 -0
  153. package/dist/standalone/chunk-VLXV72QE.js +1 -0
  154. package/dist/standalone/chunk-VMJKJWG6.js +1 -0
  155. package/dist/standalone/chunk-VPDPN5RR.js +2 -0
  156. package/dist/standalone/chunk-VSEGZA3J.js +1 -0
  157. package/dist/standalone/chunk-VXBZQIGY.js +4 -0
  158. package/dist/standalone/chunk-W7PCVQTE.js +1 -0
  159. package/dist/standalone/chunk-XLILSHPE.js +1 -0
  160. package/dist/standalone/chunk-XURNGQSS.js +1 -0
  161. package/dist/standalone/chunk-YJGANMU7.js +18 -0
  162. package/dist/standalone/chunk-YQQJ4N6U.js +1 -0
  163. package/dist/standalone/chunk-ZH7UES4T.js +2 -0
  164. package/dist/standalone/chunk-ZPUO7FNI.js +1 -0
  165. package/dist/standalone/chunk-ZQCVDXDL.js +1 -0
  166. package/dist/standalone/studio.js +104 -246
  167. package/dist/styles.css +1 -1
  168. package/package.json +13 -12
  169. package/dist/packem_shared/SettingsPanel-C0uLRf5P.js +0 -176
  170. package/dist/packem_shared/SqlEditorPanel-CguV7otm.js +0 -13
  171. package/dist/packem_shared/Studio-DFWAlcuf.js +0 -33
  172. package/dist/packem_shared/studio-Bj8psK1c.js +0 -10303
  173. package/dist/packem_shared/use-live-admin-Dq6g3daN.js +0 -73
  174. package/dist/packem_shared/use-live-shard-seed-Cuk3dnH0.js +0 -76
@@ -1,18 +1,19 @@
1
1
  import { c } from 'react/compiler-runtime';
2
2
  import { useLunora } from '@lunora/react';
3
3
  import { useNavigate } from '@tanstack/react-router';
4
- import { useState, useEffect, useMemo } from 'react';
5
- import { ShardInput } from './ShardInput-gx_DZXXn.js';
6
- import { B as Button } from './button-BhsN2uZH.js';
7
- import { useT } from './DEFAULT_LOCALE-CiX4W7Kr.js';
8
- import { ADMIN_FUNCTIONS } from './ADMIN_FUNCTIONS-DmBqMZ-z.js';
9
- import { f as fireAndForget, c as callOptions, e as errorMessage, a as adminRef } from './internal-rXJEAhXS.js';
10
- import { r as recordShard } from './shard-history-DyebH1R5.js';
11
- import { u as useLiveShardSeed } from './use-live-shard-seed-Cuk3dnH0.js';
12
- import { a as advisoryRow, A as AdvisorView } from './advisor-view-CGcfMiPq.js';
13
- import { ConfirmButton } from './ConfirmButton-C2eVi2Qv.js';
4
+ import { useState, useRef, useCallback, useEffect, useMemo } from 'react';
5
+ import { ShardInput } from '../packem_shared/ShardInput-gx_DZXXn.js';
6
+ import { B as Button } from '../packem_shared/button-BhsN2uZH.js';
7
+ import { u as useAdminQuery } from '../packem_shared/use-admin-query-BViPA3US.js';
8
+ import useDebounced from '../packem_shared/useDebounced-Dxncpg6z.js';
9
+ import { useT } from '../packem_shared/DEFAULT_LOCALE-CiX4W7Kr.js';
10
+ import { ADMIN_FUNCTIONS } from '../packem_shared/ADMIN_FUNCTIONS-CdaxLGkE.js';
11
+ import { f as fireAndForget, c as callOptions, a as adminRef } from '../packem_shared/internal-FcNZ3beb.js';
12
+ import { r as recordShard } from '../packem_shared/shard-history-DyebH1R5.js';
13
+ import { a as advisoryRow, A as AdvisorView } from '../packem_shared/advisor-view-DzqyvUU3.js';
14
+ import { ConfirmButton } from '../packem_shared/ConfirmButton-C2eVi2Qv.js';
14
15
  import { jsxDEV } from 'react/jsx-dev-runtime';
15
- import { deriveInsights } from './DEFAULT_INSIGHT_THRESHOLDS-DjF0h-gA.js';
16
+ import { deriveInsights } from '../packem_shared/DEFAULT_INSIGHT_THRESHOLDS-DjF0h-gA.js';
16
17
  import { runAdvisor, RUNTIME_LINTS } from '@lunora/advisor';
17
18
 
18
19
  const hasIndexMetadata = (metadata) => {
@@ -185,9 +186,6 @@ const deriveRuntimeAdvisories = (inputs) => {
185
186
  return visible.map((finding) => advisoryRow(finding));
186
187
  };
187
188
 
188
- const GET_ADVISORIES = adminRef(ADMIN_FUNCTIONS.getAdvisories);
189
- const GET_FUNCTION_STATS = adminRef(ADMIN_FUNCTIONS.getFunctionStats);
190
- const GET_METRICS = adminRef(ADMIN_FUNCTIONS.getMetrics);
191
189
  const LIST_TABLES = adminRef(ADMIN_FUNCTIONS.listTables);
192
190
  const LIST_TABLE_INDEXES = adminRef(ADMIN_FUNCTIONS.listTableIndexes);
193
191
  const percent = (rate) => `${(rate * 100).toFixed(1)}%`;
@@ -286,46 +284,41 @@ const InsightsPanel = ({
286
284
  const navigate = useNavigate();
287
285
  const t = useT();
288
286
  const [shardKey, setShardKey] = useState(initialShardKey ?? "");
289
- const [metrics, setMetrics] = useState(null);
290
- const [functions, setFunctions] = useState(null);
291
- const [advisories, setAdvisories] = useState(null);
292
- const [indexHits, setIndexHits] = useState(null);
293
287
  const [declaredIndexes, setDeclaredIndexes] = useState(null);
294
288
  const [shardTraffic, setShardTraffic] = useState(null);
295
- const [error, setError] = useState(null);
289
+ const debouncedShard = useDebounced(shardKey.trim(), 400);
290
+ const latestEnumeratedShard = useRef("");
291
+ const metricsQuery = useAdminQuery(ADMIN_FUNCTIONS.getMetrics, {}, {
292
+ live: true,
293
+ shardKey: debouncedShard
294
+ });
295
+ const functionsQuery = useAdminQuery(ADMIN_FUNCTIONS.getFunctionStats, {}, {
296
+ live: true,
297
+ shardKey: debouncedShard
298
+ });
299
+ const advisoriesQuery = useAdminQuery(ADMIN_FUNCTIONS.getAdvisories, {}, {
300
+ live: true,
301
+ shardKey: debouncedShard
302
+ });
303
+ const metrics = metricsQuery.data ?? null;
304
+ const functions = functionsQuery.data?.functions ?? null;
305
+ const advisories = advisoriesQuery.data?.advisories ?? null;
306
+ const indexHits = metricsQuery.data?.indexHits ?? null;
307
+ const error = metricsQuery.error !== null && functionsQuery.error !== null ? metricsQuery.error : null;
296
308
  const fanShardTraffic = loadShardTraffic ?? ((table) => client.shardTraffic(table));
297
- const refresh = async (shard) => {
298
- const [snapshot, stats, advisorySnapshot] = await Promise.allSettled([client.query(GET_METRICS, {}, callOptions(shard)), client.query(GET_FUNCTION_STATS, {}, callOptions(shard)), client.query(GET_ADVISORIES, {}, callOptions(shard))]);
299
- if (snapshot.status === "rejected" && stats.status === "rejected") {
300
- setError(errorMessage(snapshot.reason));
301
- } else {
302
- setError(null);
303
- recordShard(shard);
304
- }
305
- setMetrics(snapshot.status === "fulfilled" ? snapshot.value : null);
306
- setFunctions(stats.status === "fulfilled" ? stats.value.functions : null);
307
- setAdvisories(advisorySnapshot.status === "fulfilled" ? advisorySnapshot.value.advisories : null);
308
- setIndexHits(snapshot.status === "fulfilled" ? snapshot.value.indexHits ?? null : null);
309
- let tableNames = [];
310
- try {
311
- const tables = await client.query(LIST_TABLES, {}, callOptions(shard));
312
- tableNames = tables.map((table_0) => table_0.name);
313
- const indexResults = await Promise.allSettled(tables.map(async (table_1) => [table_1.name, await client.query(LIST_TABLE_INDEXES, {
314
- table: table_1.name
315
- }, callOptions(shard))]));
316
- const declared = [];
317
- for (const result of indexResults) {
318
- if (result.status === "fulfilled") {
319
- const [name, payload] = result.value;
320
- declared.push(...declaredIndexesFor(name, payload.indexes));
321
- }
309
+ const loadShardTrafficFeed = async (tableNames, shard) => {
310
+ const seedTable = tableNames[0];
311
+ if (seedTable === void 0 || seedTable === "") {
312
+ if (latestEnumeratedShard.current === shard) {
313
+ setShardTraffic(null);
322
314
  }
323
- setDeclaredIndexes(declared);
324
- } catch {
325
- setDeclaredIndexes(null);
315
+ return;
326
316
  }
327
317
  try {
328
- const traffic = await fanShardTraffic(tableNames[0] ?? "");
318
+ const traffic = await fanShardTraffic(seedTable);
319
+ if (latestEnumeratedShard.current !== shard) {
320
+ return;
321
+ }
329
322
  const byShard = /* @__PURE__ */ new Map();
330
323
  for (const entry of traffic.shards) {
331
324
  if (!byShard.has(entry.shardKey)) {
@@ -337,31 +330,76 @@ const InsightsPanel = ({
337
330
  }
338
331
  setShardTraffic([...byShard.values()]);
339
332
  } catch {
340
- setShardTraffic(null);
333
+ if (latestEnumeratedShard.current === shard) {
334
+ setShardTraffic(null);
335
+ }
341
336
  }
342
337
  };
343
- useLiveShardSeed(shardKey, refresh);
338
+ const enumerateShard = useCallback(
339
+ async (shard) => {
340
+ latestEnumeratedShard.current = shard;
341
+ let tableNames = [];
342
+ try {
343
+ const tables = await client.query(LIST_TABLES, {}, callOptions(shard));
344
+ if (latestEnumeratedShard.current !== shard) {
345
+ return;
346
+ }
347
+ recordShard(shard);
348
+ tableNames = tables.map((table) => table.name);
349
+ const indexResults = await Promise.allSettled(tables.map(async (table) => [table.name, await client.query(LIST_TABLE_INDEXES, {
350
+ table: table.name
351
+ }, callOptions(shard))]));
352
+ if (latestEnumeratedShard.current !== shard) {
353
+ return;
354
+ }
355
+ const declared = [];
356
+ for (const result of indexResults) {
357
+ if (result.status === "fulfilled") {
358
+ const [name, payload] = result.value;
359
+ declared.push(...declaredIndexesFor(name, payload.indexes));
360
+ }
361
+ }
362
+ setDeclaredIndexes(declared);
363
+ } catch {
364
+ if (latestEnumeratedShard.current === shard) {
365
+ setDeclaredIndexes(null);
366
+ }
367
+ }
368
+ await loadShardTrafficFeed(tableNames, shard);
369
+ },
370
+ // `fanShardTraffic`/`loadShardTrafficFeed` are render-fresh closures; the
371
+ // enumeration only needs to re-run on a shard change (or a manual visibility
372
+ // refresh), so they're intentionally excluded from the cache key.
373
+ // eslint-disable-next-line react-hooks/exhaustive-deps
374
+ [client]
375
+ );
376
+ useEffect(() => {
377
+ fireAndForget(enumerateShard(debouncedShard));
378
+ }, [debouncedShard, enumerateShard]);
344
379
  useEffect(() => {
345
380
  const onVisible = () => {
346
381
  if (document.visibilityState === "visible") {
347
- fireAndForget(refresh(shardKey));
382
+ metricsQuery.refetch();
383
+ functionsQuery.refetch();
384
+ advisoriesQuery.refetch();
385
+ fireAndForget(enumerateShard(debouncedShard));
348
386
  }
349
387
  };
350
388
  document.addEventListener("visibilitychange", onVisible);
351
389
  return () => {
352
390
  document.removeEventListener("visibilitychange", onVisible);
353
391
  };
354
- }, [refresh, shardKey]);
355
- const jumpToSchemaIndex = (table_2) => {
392
+ }, [advisoriesQuery, debouncedShard, enumerateShard, functionsQuery, metricsQuery]);
393
+ const jumpToSchemaIndex = useCallback((table) => {
356
394
  fireAndForget(navigate({
357
395
  search: {
358
- table: table_2
396
+ table
359
397
  },
360
398
  to: "/schema"
361
399
  }));
362
- };
400
+ }, [navigate]);
363
401
  const insights = deriveInsights(metrics, functions);
364
- const missingIndexTables = new Set(insights.filter((insight) => insight.kind === "missing-index").flatMap((insight_0) => insight_0.tables ?? []));
402
+ const missingIndexTables = new Set(insights.filter((insight) => insight.kind === "missing-index").flatMap((insight) => insight.tables ?? []));
365
403
  const runtimeRows = deriveRuntimeAdvisories({
366
404
  declaredIndexes: declaredIndexes ?? [],
367
405
  functions,
@@ -370,18 +408,18 @@ const InsightsPanel = ({
370
408
  suppressHotScanTables: missingIndexTables
371
409
  });
372
410
  const rows = useMemo(() => {
373
- const insightRows = insights.map((insight_1) => {
374
- const tables_0 = insight_1.kind === "missing-index" ? insight_1.tables ?? [] : [];
411
+ const insightRows = insights.map((insight) => {
412
+ const tables = insight.kind === "missing-index" ? insight.tables ?? [] : [];
375
413
  return {
376
- action: tables_0.length > 0 ? tables_0.map((table_3) => /* @__PURE__ */ jsxDEV(AddIndexButton, {
414
+ action: tables.length > 0 ? tables.map((table) => /* @__PURE__ */ jsxDEV(AddIndexButton, {
377
415
  onJump: jumpToSchemaIndex,
378
- table: table_3
379
- }, table_3, false)) : void 0,
380
- description: insight_1.message === void 0 ? insightDetail(t, insight_1) : `${insightDetail(t, insight_1)} — ${insight_1.message}`,
381
- entity: insight_1.fn,
382
- issueType: insightTitle(t, insight_1),
383
- key: `${insight_1.kind}:${insight_1.fn ?? ""}`,
384
- level: insight_1.severity
416
+ table
417
+ }, table, false)) : void 0,
418
+ description: insight.message === void 0 ? insightDetail(t, insight) : `${insightDetail(t, insight)} — ${insight.message}`,
419
+ entity: insight.fn,
420
+ issueType: insightTitle(t, insight),
421
+ key: `${insight.kind}:${insight.fn ?? ""}`,
422
+ level: insight.severity
385
423
  };
386
424
  });
387
425
  const indexAdvisoryLints = /* @__PURE__ */ new Set(["unindexed_foreign_key", "unindexed_relation_target"]);
@@ -389,16 +427,16 @@ const InsightsPanel = ({
389
427
  const base = advisoryRow(finding);
390
428
  if (indexAdvisoryLints.has(finding.name) && hasIndexMetadata(finding.metadata)) {
391
429
  const {
392
- table: table_4,
430
+ table,
393
431
  suggestedIndex
394
432
  } = finding.metadata;
395
- const testId = `in-apply-index-${table_4}-${suggestedIndex.name}`;
433
+ const testId = `in-apply-index-${table}-${suggestedIndex.name}`;
396
434
  return {
397
435
  ...base,
398
436
  action: /* @__PURE__ */ jsxDEV(ApplyIndexButton, {
399
437
  fields: suggestedIndex.fields,
400
438
  indexName: suggestedIndex.name,
401
- table: table_4,
439
+ table,
402
440
  testId
403
441
  }, void 0, false)
404
442
  };
@@ -1,21 +1,19 @@
1
1
  import { c } from 'react/compiler-runtime';
2
- import { useLunora } from '@lunora/react';
3
2
  import { useVirtualizer } from '@tanstack/react-virtual';
4
- import { useState, useMemo, useRef } from 'react';
5
- import { L as LiveError } from './live-status-FZ0psC1z.js';
6
- import { ShardInput } from './ShardInput-gx_DZXXn.js';
7
- import { B as Badge } from './badge-B2PKA1-5.js';
8
- import { E as EmptyState } from './empty-state-DY_oe0k6.js';
9
- import { I as Input } from './input-XH4r1Pt1.js';
10
- import { u as useLiveAdmin } from './use-live-admin-Dq6g3daN.js';
11
- import { useT } from './DEFAULT_LOCALE-CiX4W7Kr.js';
12
- import { ADMIN_FUNCTIONS } from './ADMIN_FUNCTIONS-DmBqMZ-z.js';
13
- import { C as CLOUDFLARE_OBSERVABILITY_URL } from './cf-links-2cktDedA.js';
14
- import { c as callOptions, e as errorMessage, a as adminRef } from './internal-rXJEAhXS.js';
15
- import { r as recordShard } from './shard-history-DyebH1R5.js';
16
- import { c as cn } from './utils-B05Dmz_H.js';
17
- import { f as flooredRectObserver } from './virtual-rect-CVMUskSm.js';
18
- import { u as useLiveShardSeed } from './use-live-shard-seed-Cuk3dnH0.js';
3
+ import { useState, useEffect, useMemo, useRef } from 'react';
4
+ import { L as LiveError } from '../packem_shared/live-status-FZ0psC1z.js';
5
+ import { ShardInput } from '../packem_shared/ShardInput-gx_DZXXn.js';
6
+ import { B as Badge } from '../packem_shared/badge-B2PKA1-5.js';
7
+ import { E as EmptyState } from '../packem_shared/empty-state-DY_oe0k6.js';
8
+ import { I as Input } from '../packem_shared/input-XH4r1Pt1.js';
9
+ import { u as useAdminQuery } from '../packem_shared/use-admin-query-BViPA3US.js';
10
+ import useDebounced from '../packem_shared/useDebounced-Dxncpg6z.js';
11
+ import { useT } from '../packem_shared/DEFAULT_LOCALE-CiX4W7Kr.js';
12
+ import { ADMIN_FUNCTIONS } from '../packem_shared/ADMIN_FUNCTIONS-CdaxLGkE.js';
13
+ import { a as CLOUDFLARE_OBSERVABILITY_URL } from '../packem_shared/cf-links-BZfRdxSE.js';
14
+ import { r as recordShard } from '../packem_shared/shard-history-DyebH1R5.js';
15
+ import { c as cn } from '../packem_shared/utils-B05Dmz_H.js';
16
+ import { f as flooredRectObserver } from '../packem_shared/virtual-rect-CVMUskSm.js';
19
17
  import { jsxDEV } from 'react/jsx-dev-runtime';
20
18
 
21
19
  const SCROLL_HEIGHT = 400;
@@ -316,8 +314,6 @@ const RequestRow = (t0) => {
316
314
  }
317
315
  return t17;
318
316
  };
319
- const GET_LOGS = adminRef(ADMIN_FUNCTIONS.getLogs);
320
- const GET_REQUEST_LOG = adminRef(ADMIN_FUNCTIONS.getRequestLog);
321
317
  const entriesOf = (result) => {
322
318
  const {
323
319
  entries
@@ -488,13 +484,9 @@ const SummaryBucketRow = (t0) => {
488
484
  const LogsPanel = ({
489
485
  initialShardKey
490
486
  }) => {
491
- const client = useLunora();
492
487
  const t = useT();
493
488
  const [view, setView] = useState("requests");
494
489
  const [shardKey, setShardKey] = useState(initialShardKey ?? "");
495
- const [entries, setEntries] = useState([]);
496
- const [requests, setRequests] = useState([]);
497
- const [error, setError] = useState(null);
498
490
  const [search, setSearch] = useState("");
499
491
  const [levelFilter, setLevelFilter] = useState(() => /* @__PURE__ */ new Set());
500
492
  const [pathFilter, setPathFilter] = useState("");
@@ -504,43 +496,36 @@ const LogsPanel = ({
504
496
  const [userIdFilter, setUserIdFilter] = useState("");
505
497
  const [tableFilter, setTableFilter] = useState("");
506
498
  const [outcomeFilter, setOutcomeFilter] = useState("all");
507
- const [liveError, setLiveError] = useState(void 0);
499
+ const debouncedShard = useDebounced(shardKey.trim(), 400);
508
500
  const requestQuery = buildRequestQuery({
509
501
  functionPathPrefix: pathPrefix,
510
502
  outcome: outcomeFilter,
511
503
  tableTouched: tableFilter,
512
504
  userId: userIdFilter
513
505
  });
514
- const refresh = async (shard) => {
515
- setError(null);
516
- try {
517
- if (view === "requests") {
518
- const result = await client.query(GET_REQUEST_LOG, requestQuery, callOptions(shard));
519
- recordShard(shard);
520
- setRequests(entriesOf(result));
521
- } else {
522
- const result_0 = await client.query(GET_LOGS, {}, callOptions(shard));
523
- recordShard(shard);
524
- setEntries(entriesOf(result_0));
525
- }
526
- } catch (error_) {
527
- setEntries([]);
528
- setRequests([]);
529
- setError(errorMessage(error_));
530
- throw error_;
506
+ const requestsQuery = useAdminQuery(ADMIN_FUNCTIONS.getRequestLog, requestQuery, {
507
+ enabled: view === "requests",
508
+ live: true,
509
+ shardKey: debouncedShard
510
+ });
511
+ const errorsQuery = useAdminQuery(ADMIN_FUNCTIONS.getLogs, {}, {
512
+ enabled: view === "errors",
513
+ live: true,
514
+ shardKey: debouncedShard
515
+ });
516
+ const activeQuery = view === "requests" ? requestsQuery : errorsQuery;
517
+ const {
518
+ error,
519
+ isLoading: activeLoading,
520
+ liveError
521
+ } = activeQuery;
522
+ const entries = entriesOf(errorsQuery.data);
523
+ const requests = entriesOf(requestsQuery.data);
524
+ useEffect(() => {
525
+ if (activeQuery.data !== void 0) {
526
+ recordShard(debouncedShard);
531
527
  }
532
- };
533
- const committedShard = useLiveShardSeed(shardKey, refresh, [view, requestQuery]);
534
- useLiveAdmin(ADMIN_FUNCTIONS.getRequestLog, requestQuery, committedShard ?? "", (result_1) => {
535
- setError(null);
536
- setLiveError(void 0);
537
- setRequests(entriesOf(result_1));
538
- }, view === "requests" && committedShard !== void 0, setLiveError);
539
- useLiveAdmin(ADMIN_FUNCTIONS.getLogs, {}, committedShard ?? "", (result_2) => {
540
- setError(null);
541
- setLiveError(void 0);
542
- setEntries(entriesOf(result_2));
543
- }, view === "errors" && committedShard !== void 0, setLiveError);
528
+ }, [activeQuery.data, debouncedShard]);
544
529
  const filtered = filterLogs(entries, {
545
530
  levels: levelFilter,
546
531
  now: Date.now(),
@@ -556,10 +541,13 @@ const LogsPanel = ({
556
541
  return "error";
557
542
  }
558
543
  if (activeCount === 0) {
544
+ if (activeLoading) {
545
+ return summaryVisible ? "summary" : "list";
546
+ }
559
547
  return "empty";
560
548
  }
561
549
  return summaryVisible ? "summary" : "list";
562
- }, [activeCount, error, summaryVisible]);
550
+ }, [activeCount, activeLoading, error, summaryVisible]);
563
551
  const scrollRef = useRef(null);
564
552
  const virtualizer = useVirtualizer({
565
553
  count: activeCount,
@@ -1,19 +1,20 @@
1
1
  'use client';
2
2
  import { useLunora } from '@lunora/react';
3
- import { useState, useEffect, useMemo } from 'react';
4
- import { B as Badge } from './badge-B2PKA1-5.js';
5
- import { B as Button } from './button-BhsN2uZH.js';
6
- import { E as EmptyState } from './empty-state-DY_oe0k6.js';
7
- import { I as Input } from './input-XH4r1Pt1.js';
3
+ import { useState, useMemo } from 'react';
4
+ import { B as Badge } from '../packem_shared/badge-B2PKA1-5.js';
5
+ import { B as Button } from '../packem_shared/button-BhsN2uZH.js';
6
+ import { E as EmptyState } from '../packem_shared/empty-state-DY_oe0k6.js';
7
+ import { I as Input } from '../packem_shared/input-XH4r1Pt1.js';
8
8
  import { c } from 'react/compiler-runtime';
9
9
  import { ScrollArea as ScrollArea$1 } from '@base-ui/react/scroll-area';
10
- import { c as cn } from './utils-B05Dmz_H.js';
10
+ import { c as cn } from '../packem_shared/utils-B05Dmz_H.js';
11
11
  import { jsxDEV, Fragment } from 'react/jsx-dev-runtime';
12
12
  import { Separator as Separator$1 } from '@base-ui/react/separator';
13
- import { useAutoRefresh } from './DEFAULT_AUTO_REFRESH_MS-Vxwaxx51.js';
14
- import { useT } from './DEFAULT_LOCALE-CiX4W7Kr.js';
15
- import { ADMIN_FUNCTIONS } from './ADMIN_FUNCTIONS-DmBqMZ-z.js';
16
- import { f as fireAndForget, b as formatTimestamp, c as callOptions, e as errorMessage, g as copyToClipboard, a as adminRef } from './internal-rXJEAhXS.js';
13
+ import { u as useAdminQuery } from '../packem_shared/use-admin-query-BViPA3US.js';
14
+ import { useAutoRefresh } from '../packem_shared/DEFAULT_AUTO_REFRESH_MS-Vxwaxx51.js';
15
+ import { useT } from '../packem_shared/DEFAULT_LOCALE-CiX4W7Kr.js';
16
+ import { ADMIN_FUNCTIONS } from '../packem_shared/ADMIN_FUNCTIONS-CdaxLGkE.js';
17
+ import { g as formatTimestamp, f as fireAndForget, b as copyToClipboard, c as callOptions, e as errorMessage, a as adminRef } from '../packem_shared/internal-FcNZ3beb.js';
17
18
 
18
19
  function Separator({
19
20
  className,
@@ -114,7 +115,6 @@ function ScrollBar({
114
115
  }, void 0, false);
115
116
  }
116
117
 
117
- const GET_CAPTURED_MAIL = adminRef(ADMIN_FUNCTIONS.getCapturedMail);
118
118
  const CLEAR_CAPTURED_MAIL = adminRef(ADMIN_FUNCTIONS.clearCapturedMail);
119
119
  const SEND_TEST_MAIL = adminRef(ADMIN_FUNCTIONS.sendTestMail);
120
120
  const LINK_PATTERN = /https?:\/\/[^\s"'<>)]+/i;
@@ -144,49 +144,42 @@ const MailPanel = ({
144
144
  }) => {
145
145
  const client = useLunora();
146
146
  const t = useT();
147
- const [entries, setEntries] = useState([]);
148
- const [error, setError] = useState(null);
147
+ const {
148
+ data,
149
+ error: readError,
150
+ isLoading,
151
+ refetch
152
+ } = useAdminQuery(ADMIN_FUNCTIONS.getCapturedMail, {
153
+ limit
154
+ });
155
+ const [actionError, setActionError] = useState(null);
149
156
  const [selectedId, setSelectedId] = useState(null);
150
157
  const [tab, setTab] = useState("html");
151
158
  const [filter, setFilter] = useState("");
152
- const refresh = async () => {
153
- setError(null);
154
- try {
155
- const next = await client.query(GET_CAPTURED_MAIL, {
156
- limit
157
- }, callOptions(""));
158
- setEntries(next.entries);
159
- } catch (error_) {
160
- setEntries([]);
161
- setError(errorMessage(error_));
162
- }
163
- };
159
+ const entries = useMemo(() => data?.entries ?? [], [data]);
160
+ const error = readError ?? actionError;
164
161
  const clearInbox = async () => {
165
- setError(null);
162
+ setActionError(null);
166
163
  try {
167
164
  await client.query(CLEAR_CAPTURED_MAIL, {}, callOptions(""));
168
165
  setSelectedId(null);
169
- await refresh();
170
- } catch (error__0) {
171
- setError(errorMessage(error__0));
166
+ refetch();
167
+ } catch (error_) {
168
+ setActionError(errorMessage(error_));
172
169
  }
173
170
  };
174
171
  const sendTest = async () => {
175
- setError(null);
172
+ setActionError(null);
176
173
  try {
177
174
  await client.query(SEND_TEST_MAIL, {}, callOptions(""));
178
- await refresh();
179
- } catch (error__1) {
180
- setError(errorMessage(error__1));
175
+ refetch();
176
+ } catch (error__0) {
177
+ setActionError(errorMessage(error__0));
181
178
  }
182
179
  };
183
- useEffect(() => {
184
- fireAndForget(refresh());
185
- }, [refresh]);
186
- const reload = () => {
187
- fireAndForget(refresh());
188
- };
189
- useAutoRefresh(reload, true);
180
+ useAutoRefresh(() => {
181
+ refetch();
182
+ }, true);
190
183
  const onClear = () => {
191
184
  fireAndForget(clearInbox());
192
185
  };
@@ -205,9 +198,9 @@ const MailPanel = ({
205
198
  }
206
199
  };
207
200
  const onSelectTab = (event_1) => {
208
- const next_0 = event_1.currentTarget.dataset["tab"];
209
- if (next_0 === "headers" || next_0 === "html" || next_0 === "text") {
210
- setTab(next_0);
201
+ const next = event_1.currentTarget.dataset["tab"];
202
+ if (next === "headers" || next === "html" || next === "text") {
203
+ setTab(next);
211
204
  }
212
205
  };
213
206
  const tabTitle = (value) => {
@@ -276,7 +269,7 @@ const MailPanel = ({
276
269
  "data-testid": "mail-error",
277
270
  role: "alert",
278
271
  children: error
279
- }, void 0, false), error === null && entries.length === 0 && /* @__PURE__ */ jsxDEV(EmptyState, {
272
+ }, void 0, false), error === null && !isLoading && entries.length === 0 && /* @__PURE__ */ jsxDEV(EmptyState, {
280
273
  description: t("Email your app sends in dev is captured here — nothing is delivered."),
281
274
  icon: /* @__PURE__ */ jsxDEV("svg", {
282
275
  "aria-hidden": "true",