@apisurf/wireui 0.1.2

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 (38) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +157 -0
  3. package/bin/wireui.mjs +233 -0
  4. package/dist/nitro.json +17 -0
  5. package/dist/public/assets/collections-CLHcfRfi.js +1 -0
  6. package/dist/public/assets/globals-CZiNFGaK.css +1 -0
  7. package/dist/public/assets/index-D5VFd_3H.js +14 -0
  8. package/dist/public/assets/kv-table-oB5gcq0i.js +2 -0
  9. package/dist/public/assets/query-BKAhHNIi.js +19 -0
  10. package/dist/public/assets/requests._requestId-Bu7E2eoI.js +1 -0
  11. package/dist/public/assets/routes-DDY2CfzA.js +1 -0
  12. package/dist/public/assets/runs._runId-CzwtVjYq.js +1 -0
  13. package/dist/public/assets/scoped-DB8raIWx.js +1 -0
  14. package/dist/public/assets/split-Br1RX2I4.js +1 -0
  15. package/dist/public/favicon.svg +1 -0
  16. package/dist/server/_chunks/ssr-renderer.mjs +26 -0
  17. package/dist/server/_libs/@tanstack/react-router+[...].mjs +15246 -0
  18. package/dist/server/_libs/h3+rou3+srvx.mjs +2086 -0
  19. package/dist/server/_libs/hookable.mjs +41 -0
  20. package/dist/server/_libs/tanstack__history.mjs +369 -0
  21. package/dist/server/_libs/ufo.mjs +64 -0
  22. package/dist/server/_runtime.mjs +35 -0
  23. package/dist/server/_ssr/api-Dw1Zb_PK.mjs +931 -0
  24. package/dist/server/_ssr/collections-CqidTQpw.mjs +495 -0
  25. package/dist/server/_ssr/empty-plugin-adapters-CCuiUfKt.mjs +5 -0
  26. package/dist/server/_ssr/kv-table-DQUkoItO.mjs +458 -0
  27. package/dist/server/_ssr/query-D4so9xiY.mjs +416 -0
  28. package/dist/server/_ssr/requests._requestId-BFukRwqL.mjs +942 -0
  29. package/dist/server/_ssr/router-CPcgc_kh.mjs +3176 -0
  30. package/dist/server/_ssr/routes-DaV9vGHn.mjs +375 -0
  31. package/dist/server/_ssr/runs._runId-Df_LmPHa.mjs +836 -0
  32. package/dist/server/_ssr/scoped-CnQ56K8h.mjs +42 -0
  33. package/dist/server/_ssr/split-DWrMIs7K.mjs +115 -0
  34. package/dist/server/_ssr/ssr.mjs +6827 -0
  35. package/dist/server/_ssr/start-zk_ZfrWl.mjs +4 -0
  36. package/dist/server/_tanstack-start-manifest_v-CARKjHfs.mjs +50 -0
  37. package/dist/server/index.mjs +368 -0
  38. package/package.json +71 -0
@@ -0,0 +1,416 @@
1
+ import { __toESM } from "../_runtime.mjs";
2
+ import { require_jsx_runtime, require_react, useNavigate } from "../_libs/@tanstack/react-router+[...].mjs";
3
+ import { Button, Callout, Empty, FilterInput, IconDatabase, IconPlay, Kbd, Pill, Route$2, css, cx, formatMs, mono, runSql, tabKey, table, truncate, useTab } from "./router-CPcgc_kh.mjs";
4
+ import { Split } from "./split-DWrMIs7K.mjs";
5
+ //#region node_modules/.nitro/vite/services/ssr/assets/query-D4so9xiY.js
6
+ var import_react = /* @__PURE__ */ __toESM(require_react());
7
+ var import_jsx_runtime = require_jsx_runtime();
8
+ var EXAMPLES = [
9
+ {
10
+ label: "Slowest requests",
11
+ sql: "SELECT id, method, host, path, status, duration_ms\nFROM v_requests\nORDER BY duration_ms DESC\nLIMIT 20"
12
+ },
13
+ {
14
+ label: "Errors by host",
15
+ sql: "SELECT host, status, COUNT(*) AS n\nFROM v_requests\nWHERE status >= 400 OR error_name IS NOT NULL\nGROUP BY host, status\nORDER BY n DESC"
16
+ },
17
+ {
18
+ label: "Failed checks",
19
+ sql: "SELECT c.run_id, r.label, c.name, c.message\nFROM v_checks c JOIN v_runs r ON r.id = c.run_id\nWHERE c.status = 'fail'\nORDER BY c.ts DESC"
20
+ },
21
+ {
22
+ label: "Search payloads",
23
+ sql: "SELECT q.id, q.method, q.path, q.status\nFROM body_fts f\nJOIN v_requests q ON q.response_body_id = f.body_id\nWHERE body_fts MATCH 'error'\nLIMIT 50"
24
+ },
25
+ {
26
+ label: "Header usage",
27
+ sql: "SELECT name, COUNT(DISTINCT value) AS distinct_values, COUNT(*) AS n\nFROM v_headers\nWHERE kind = 'response'\nGROUP BY name\nORDER BY n DESC"
28
+ }
29
+ ];
30
+ function QueryPage() {
31
+ useTab({
32
+ key: tabKey.query(),
33
+ title: "SQL",
34
+ icon: "query"
35
+ });
36
+ const schema = Route$2.useLoaderData();
37
+ const search = Route$2.useSearch();
38
+ const navigate = useNavigate({ from: Route$2.fullPath });
39
+ const [sql, setSql] = import_react.useState(search.sql ?? EXAMPLES[0].sql);
40
+ const [result, setResult] = import_react.useState(null);
41
+ const [running, setRunning] = import_react.useState(false);
42
+ const editor = import_react.useRef(null);
43
+ const run = import_react.useCallback(async (statement) => {
44
+ if (!statement.trim()) return;
45
+ setRunning(true);
46
+ try {
47
+ setResult(await runSql({ data: { sql: statement } }));
48
+ } catch (err) {
49
+ setResult({
50
+ ok: false,
51
+ error: err instanceof Error ? err.message : String(err)
52
+ });
53
+ } finally {
54
+ setRunning(false);
55
+ }
56
+ navigate({
57
+ search: { sql: statement },
58
+ replace: true
59
+ });
60
+ }, [navigate]);
61
+ const ranInitial = import_react.useRef(false);
62
+ import_react.useEffect(() => {
63
+ if (ranInitial.current || !search.sql) return;
64
+ ranInitial.current = true;
65
+ run(search.sql);
66
+ }, [search.sql, run]);
67
+ const insert = (text) => {
68
+ const el = editor.current;
69
+ if (!el) return setSql((s) => s + text);
70
+ const { selectionStart, selectionEnd } = el;
71
+ const next = sql.slice(0, selectionStart) + text + sql.slice(selectionEnd);
72
+ setSql(next);
73
+ window.requestAnimationFrame(() => {
74
+ el.focus();
75
+ el.setSelectionRange(selectionStart + text.length, selectionStart + text.length);
76
+ });
77
+ };
78
+ const editorPane = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
79
+ className: css({
80
+ display: "flex",
81
+ flexDir: "column",
82
+ h: "full",
83
+ minH: "0"
84
+ }),
85
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
86
+ className: css({
87
+ display: "flex",
88
+ alignItems: "center",
89
+ gap: "2",
90
+ px: "3",
91
+ h: "40px",
92
+ flexShrink: 0,
93
+ borderBottom: "1px solid",
94
+ borderColor: "line"
95
+ }),
96
+ children: [
97
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
98
+ onClick: () => void run(sql),
99
+ disabled: running,
100
+ className: css({
101
+ bg: "accent",
102
+ color: "accentFg",
103
+ borderColor: "accent",
104
+ _hover: {
105
+ bg: "accent",
106
+ opacity: .9
107
+ }
108
+ }),
109
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconPlay, { size: 12 }), "Run"]
110
+ }),
111
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Kbd, { children: "⌘ ↵" }),
112
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", {
113
+ "aria-label": "Example queries",
114
+ value: "",
115
+ onChange: (e) => {
116
+ const example = EXAMPLES.find((x) => x.label === e.target.value);
117
+ if (example) setSql(example.sql);
118
+ },
119
+ className: css({
120
+ h: "28px",
121
+ rounded: "md",
122
+ border: "1px solid",
123
+ borderColor: "line",
124
+ bg: "raised",
125
+ px: "1.5",
126
+ fontSize: "12px"
127
+ }),
128
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
129
+ value: "",
130
+ children: "Examples…"
131
+ }), EXAMPLES.map((x) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
132
+ value: x.label,
133
+ children: x.label
134
+ }, x.label))]
135
+ }),
136
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
137
+ className: css({
138
+ ml: "auto",
139
+ color: "faint",
140
+ fontSize: "12px"
141
+ }),
142
+ children: "Read-only connection"
143
+ })
144
+ ]
145
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("textarea", {
146
+ ref: editor,
147
+ value: sql,
148
+ spellCheck: false,
149
+ onChange: (e) => setSql(e.target.value),
150
+ onKeyDown: (e) => {
151
+ if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
152
+ e.preventDefault();
153
+ run(sql);
154
+ }
155
+ },
156
+ className: cx(mono, css({
157
+ flex: "1",
158
+ minH: "0",
159
+ resize: "none",
160
+ border: "none",
161
+ outline: "none",
162
+ p: "3",
163
+ bg: "well",
164
+ fontSize: "13px",
165
+ lineHeight: "1.6",
166
+ tabSize: 2
167
+ }))
168
+ })]
169
+ });
170
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
171
+ className: css({
172
+ display: "flex",
173
+ h: "full",
174
+ minH: "0"
175
+ }),
176
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SchemaBrowser, {
177
+ schema,
178
+ onInsert: insert
179
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
180
+ className: css({
181
+ flex: "1",
182
+ minW: "0",
183
+ display: "flex",
184
+ borderLeft: "1px solid",
185
+ borderColor: "line"
186
+ }),
187
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Split, {
188
+ direction: "stacked",
189
+ storageKey: "query",
190
+ initial: .38,
191
+ first: editorPane,
192
+ second: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Results, {
193
+ result,
194
+ running
195
+ })
196
+ })
197
+ })]
198
+ });
199
+ }
200
+ function SchemaBrowser({ schema, onInsert }) {
201
+ const [filter, setFilter] = import_react.useState("");
202
+ const [open, setOpen] = import_react.useState("v_requests");
203
+ const needle = filter.trim().toLowerCase();
204
+ const visible = schema.filter((r) => !needle || r.name.includes(needle) || r.columns.some((c) => c.name.includes(needle)));
205
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
206
+ className: css({
207
+ w: "260px",
208
+ flexShrink: 0,
209
+ display: "flex",
210
+ flexDir: "column",
211
+ minH: "0",
212
+ bg: "canvas"
213
+ }),
214
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
215
+ className: css({
216
+ p: "2.5",
217
+ flexShrink: 0
218
+ }),
219
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FilterInput, {
220
+ placeholder: "Filter tables and columns",
221
+ value: filter,
222
+ onChange: (e) => setFilter(e.target.value)
223
+ })
224
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
225
+ className: css({
226
+ flex: "1",
227
+ minH: "0",
228
+ overflow: "auto",
229
+ px: "1.5",
230
+ pb: "3"
231
+ }),
232
+ children: visible.map((relation) => {
233
+ const expanded = open === relation.name || needle.length > 0;
234
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
235
+ type: "button",
236
+ onClick: () => setOpen(expanded && !needle ? null : relation.name),
237
+ onDoubleClick: () => onInsert(relation.name),
238
+ title: relation.description ?? relation.name,
239
+ className: css({
240
+ display: "flex",
241
+ alignItems: "center",
242
+ gap: "1.5",
243
+ w: "full",
244
+ h: "26px",
245
+ px: "1.5",
246
+ rounded: "sm",
247
+ border: "none",
248
+ bg: "transparent",
249
+ cursor: "pointer",
250
+ textAlign: "left",
251
+ _hover: { bg: "hover" }
252
+ }),
253
+ children: [
254
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
255
+ className: css({
256
+ color: relation.type === "view" ? "accent" : "faint",
257
+ display: "inline-flex"
258
+ }),
259
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconDatabase, { size: 13 })
260
+ }),
261
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
262
+ className: cx(mono, truncate, css({ flex: "1" })),
263
+ children: relation.name
264
+ }),
265
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pill, { children: relation.type })
266
+ ]
267
+ }), expanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
268
+ className: css({
269
+ pl: "6",
270
+ pb: "1"
271
+ }),
272
+ children: [relation.description ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
273
+ className: css({
274
+ color: "faint",
275
+ fontSize: "11px",
276
+ pr: "2",
277
+ pb: "1"
278
+ }),
279
+ children: relation.description
280
+ }) : null, relation.columns.filter((c) => !needle || relation.name.includes(needle) || c.name.includes(needle)).map((column) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
281
+ type: "button",
282
+ onClick: () => onInsert(column.name),
283
+ title: `Insert ${column.name}`,
284
+ className: css({
285
+ display: "flex",
286
+ w: "full",
287
+ gap: "2",
288
+ h: "22px",
289
+ alignItems: "center",
290
+ px: "1.5",
291
+ border: "none",
292
+ bg: "transparent",
293
+ rounded: "sm",
294
+ cursor: "pointer",
295
+ textAlign: "left",
296
+ _hover: { bg: "hover" }
297
+ }),
298
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
299
+ className: cx(mono, truncate, css({ flex: "1" })),
300
+ children: column.name
301
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
302
+ className: cx(mono, css({
303
+ color: "faint",
304
+ fontSize: "10.5px"
305
+ })),
306
+ children: column.type || "?"
307
+ })]
308
+ }, column.name))]
309
+ }) : null] }, relation.name);
310
+ })
311
+ })]
312
+ });
313
+ }
314
+ function Results({ result, running }) {
315
+ if (!result) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Empty, {
316
+ title: "Run a query",
317
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconDatabase, { size: 22 }),
318
+ children: [
319
+ "Views (",
320
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
321
+ className: mono,
322
+ children: "v_runs"
323
+ }),
324
+ ", ",
325
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
326
+ className: mono,
327
+ children: "v_requests"
328
+ }),
329
+ ",",
330
+ " ",
331
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
332
+ className: mono,
333
+ children: "v_headers"
334
+ }),
335
+ "…) join the interned ids back to strings. Click a column on the left to insert it."
336
+ ]
337
+ });
338
+ if (!result.ok) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
339
+ className: css({ p: "3" }),
340
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Callout, {
341
+ tone: "bad",
342
+ title: "Query failed",
343
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
344
+ className: mono,
345
+ children: result.error
346
+ })
347
+ })
348
+ });
349
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
350
+ className: css({
351
+ display: "flex",
352
+ flexDir: "column",
353
+ h: "full",
354
+ minH: "0",
355
+ opacity: running ? .6 : 1
356
+ }),
357
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
358
+ className: css({
359
+ display: "flex",
360
+ gap: "3",
361
+ px: "3",
362
+ h: "32px",
363
+ alignItems: "center",
364
+ flexShrink: 0,
365
+ fontSize: "12px",
366
+ color: "muted",
367
+ borderBottom: "1px solid",
368
+ borderColor: "line"
369
+ }),
370
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
371
+ result.rows.length.toLocaleString("en-US"),
372
+ " row",
373
+ result.rows.length === 1 ? "" : "s",
374
+ result.truncated ? " (first 1,000)" : ""
375
+ ] }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: formatMs(result.ms) })]
376
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
377
+ className: css({
378
+ flex: "1",
379
+ minH: "0",
380
+ overflow: "auto"
381
+ }),
382
+ children: result.columns.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Empty, { title: "No columns" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", {
383
+ className: cx(table, css({
384
+ w: "auto",
385
+ minW: "full",
386
+ "& td": {
387
+ fontFamily: "mono",
388
+ fontSize: "12px",
389
+ maxW: "420px"
390
+ }
391
+ })),
392
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tr", { children: result.columns.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: c }, `${c}:${i}`)) }) }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: result.rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tr", { children: row.map((cell, j) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
393
+ className: truncate,
394
+ title: cell == null ? "NULL" : String(cell),
395
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CellValue, { value: cell })
396
+ }, j)) }, i)) })]
397
+ })
398
+ })]
399
+ });
400
+ }
401
+ function CellValue({ value }) {
402
+ if (value === null) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
403
+ className: css({
404
+ color: "faint",
405
+ fontStyle: "italic"
406
+ }),
407
+ children: "NULL"
408
+ });
409
+ if (typeof value === "number") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
410
+ className: css({ color: "synNumber" }),
411
+ children: value
412
+ });
413
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: value });
414
+ }
415
+ //#endregion
416
+ export { QueryPage as component };