@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.
- package/LICENSE +15 -0
- package/README.md +157 -0
- package/bin/wireui.mjs +233 -0
- package/dist/nitro.json +17 -0
- package/dist/public/assets/collections-CLHcfRfi.js +1 -0
- package/dist/public/assets/globals-CZiNFGaK.css +1 -0
- package/dist/public/assets/index-D5VFd_3H.js +14 -0
- package/dist/public/assets/kv-table-oB5gcq0i.js +2 -0
- package/dist/public/assets/query-BKAhHNIi.js +19 -0
- package/dist/public/assets/requests._requestId-Bu7E2eoI.js +1 -0
- package/dist/public/assets/routes-DDY2CfzA.js +1 -0
- package/dist/public/assets/runs._runId-CzwtVjYq.js +1 -0
- package/dist/public/assets/scoped-DB8raIWx.js +1 -0
- package/dist/public/assets/split-Br1RX2I4.js +1 -0
- package/dist/public/favicon.svg +1 -0
- package/dist/server/_chunks/ssr-renderer.mjs +26 -0
- package/dist/server/_libs/@tanstack/react-router+[...].mjs +15246 -0
- package/dist/server/_libs/h3+rou3+srvx.mjs +2086 -0
- package/dist/server/_libs/hookable.mjs +41 -0
- package/dist/server/_libs/tanstack__history.mjs +369 -0
- package/dist/server/_libs/ufo.mjs +64 -0
- package/dist/server/_runtime.mjs +35 -0
- package/dist/server/_ssr/api-Dw1Zb_PK.mjs +931 -0
- package/dist/server/_ssr/collections-CqidTQpw.mjs +495 -0
- package/dist/server/_ssr/empty-plugin-adapters-CCuiUfKt.mjs +5 -0
- package/dist/server/_ssr/kv-table-DQUkoItO.mjs +458 -0
- package/dist/server/_ssr/query-D4so9xiY.mjs +416 -0
- package/dist/server/_ssr/requests._requestId-BFukRwqL.mjs +942 -0
- package/dist/server/_ssr/router-CPcgc_kh.mjs +3176 -0
- package/dist/server/_ssr/routes-DaV9vGHn.mjs +375 -0
- package/dist/server/_ssr/runs._runId-Df_LmPHa.mjs +836 -0
- package/dist/server/_ssr/scoped-CnQ56K8h.mjs +42 -0
- package/dist/server/_ssr/split-DWrMIs7K.mjs +115 -0
- package/dist/server/_ssr/ssr.mjs +6827 -0
- package/dist/server/_ssr/start-zk_ZfrWl.mjs +4 -0
- package/dist/server/_tanstack-start-manifest_v-CARKjHfs.mjs +50 -0
- package/dist/server/index.mjs +368 -0
- package/package.json +71 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Luka Vidakovic
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
11
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
13
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
14
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
15
|
+
PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# wireui
|
|
2
|
+
|
|
3
|
+
A local, read-only browser UI for a database recorded by
|
|
4
|
+
[wire](https://github.com/apisurf/wire), laid out like an API client: collections
|
|
5
|
+
down the left, open tabs across the top, and each request shown the way Postman
|
|
6
|
+
or Insomnia shows one, with the request on one side and the response on the other.
|
|
7
|
+
Nothing can be sent or edited. It is a window onto what your scripts already did.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
wire execute ./scripts/sync.ts # records ./wire.sqlite
|
|
11
|
+
wireui # reads it
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
wireui
|
|
16
|
+
|
|
17
|
+
open http://127.0.0.1:3000
|
|
18
|
+
database /Users/you/work/wire.sqlite
|
|
19
|
+
|
|
20
|
+
Ctrl-C to stop.
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm i -g @apisurf/wireui # the `wireui` command, anywhere
|
|
27
|
+
pnpm add -D @apisurf/wireui # or per project, next to @apisurf/wire
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
It is released on the same version as `@apisurf/wire` and `@apisurf/wire-db`, so
|
|
31
|
+
matching versions always read the same database schema.
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
wireui # ./wire.sqlite on port 3000
|
|
37
|
+
wireui --db ~/work/api.sqlite # another file
|
|
38
|
+
wireui --port 4000 # another port
|
|
39
|
+
wire sql --ui # the same, launched from the CLI
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
| Flag | Meaning |
|
|
43
|
+
| ----------------- | ------------------------------------------------------------------- |
|
|
44
|
+
| `--db <path>` | Database file to read. Relative to the cwd. Default `./wire.sqlite` |
|
|
45
|
+
| `--port <n>` | Port to serve on. Default `3000` |
|
|
46
|
+
| `-h`, `--help` | Show help |
|
|
47
|
+
| `-v`, `--version` | Show the version |
|
|
48
|
+
|
|
49
|
+
Without `--port`, if `3000` is busy it takes the next free port up to `3020`. A
|
|
50
|
+
file that does not exist yet is not an error: the UI starts empty and fills in
|
|
51
|
+
once a run writes to it.
|
|
52
|
+
|
|
53
|
+
## What you get
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
┌ wireui / wire.sqlite [All environments ▾] [● Live] ⟳ ◫ ☾ ┐
|
|
57
|
+
├──────┬──────────────────────┬────────────────────────────────────────┤
|
|
58
|
+
│ ▣ │ Collections │ GET /products × checks.ts #6 × SQL × │
|
|
59
|
+
│ Coll │ scripts/api/ ├────────────────────────────────────────┤
|
|
60
|
+
│ ◷ │ ▾ catalog.ts 2 │ GET https://dummyjson.com/products │
|
|
61
|
+
│ Hist │ ▾ ● 18:09 1.67 s ├───────────────────┬────────────────────┤
|
|
62
|
+
│ ◎ │ GET /products │ Params Headers │ 200 OK 183 ms 1 kB │
|
|
63
|
+
│ Envs │ GET /products/1 │ limit 20 │ Body Headers Time… │
|
|
64
|
+
│ ⌂ ⛁ │ ▸ checks.ts ● 1 │ skip 20 │ { "products": [ … │
|
|
65
|
+
└──────┴──────────────────────┴───────────────────┴────────────────────┘
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**The sidebar** has three panels, the ones an API client has:
|
|
69
|
+
|
|
70
|
+
- **Collections.** Every script is a collection, its runs are folders, and each
|
|
71
|
+
run's requests are the items. Scripts are grouped by the folder they live in,
|
|
72
|
+
relative to the database.
|
|
73
|
+
- **History.** Every request across every run, newest first, under day headings.
|
|
74
|
+
Search by URL, method or status, narrow to HTTP, WebSocket/SSE or failures, and
|
|
75
|
+
turn on **In payloads** to search request and response bodies through the FTS
|
|
76
|
+
index.
|
|
77
|
+
- **Environments.** The `--env` each run was recorded against. Picking one scopes
|
|
78
|
+
the tree, History, the overview and every collection to it; so does the picker in
|
|
79
|
+
the top bar. wire records the environment's name, not its variables, so this
|
|
80
|
+
panel switches scope and does not edit anything.
|
|
81
|
+
|
|
82
|
+
**Tabs** work the way they do in an API client. A single click opens a _preview_
|
|
83
|
+
tab (italic), which the next single click reuses; double-click a tab or a sidebar
|
|
84
|
+
row to keep it open. Middle-click closes a tab. Each tab remembers its sub-tab.
|
|
85
|
+
|
|
86
|
+
**A request** has a URL bar with **cURL** and **URL** copy buttons. The request
|
|
87
|
+
pane has Params, Headers, Body and Cookies. The response pane has:
|
|
88
|
+
|
|
89
|
+
- **Body**, as Pretty (a collapsible JSON tree), Raw, or Preview (images, and
|
|
90
|
+
HTML rendered in a sandbox with scripts disabled)
|
|
91
|
+
- **Headers** and **Cookies**, both filterable
|
|
92
|
+
- **Timeline**, which splits the request into DNS, connect, TLS, waiting and
|
|
93
|
+
download phases that add up to the duration, then shows a `curl -v` style
|
|
94
|
+
transcript of the exchange
|
|
95
|
+
|
|
96
|
+
WebSocket and SSE connections open on **Messages** instead: every frame or event
|
|
97
|
+
in order, filterable by direction, with the selected payload shown below. `[` and
|
|
98
|
+
`]` step to the previous or next request in the run and keep the same pane open.
|
|
99
|
+
|
|
100
|
+
**A run** reads like collection-runner results. The summary shows the verdict,
|
|
101
|
+
wall time, failed requests, checks and bytes. The tabs are:
|
|
102
|
+
|
|
103
|
+
- **Requests**, on one timeline with a waterfall and the run's `check()`/`assert()`
|
|
104
|
+
results interleaved at the moment they were made
|
|
105
|
+
- **Checks**
|
|
106
|
+
- **Insights**: p50/p95/p99, status mix, per-host breakdown, slowest calls
|
|
107
|
+
- **Details**: run metadata, tags, and the snippet for inline runs
|
|
108
|
+
|
|
109
|
+
**A collection** is one script across all its runs:
|
|
110
|
+
|
|
111
|
+
- **Runs**, with a wall-time bar for each run so regressions stand out
|
|
112
|
+
- **Requests**: the endpoints it calls, one row each, with call count, error count
|
|
113
|
+
and last status
|
|
114
|
+
- **Checks**: each assertion's pass rate over time
|
|
115
|
+
|
|
116
|
+
**Overview** gives totals for the file, recent runs, failing checks, failed
|
|
117
|
+
requests and the slowest endpoints. **SQL** is `wire sql` in the browser: a schema
|
|
118
|
+
browser (click a column to insert it), example queries, and results capped at
|
|
119
|
+
1,000 rows. The query is kept in the URL, so you can share it as a link.
|
|
120
|
+
|
|
121
|
+
**Live** re-reads the file every two seconds. The UI also re-reads whenever you
|
|
122
|
+
switch back to its tab. Themes are light, dark or system.
|
|
123
|
+
|
|
124
|
+
## Notes
|
|
125
|
+
|
|
126
|
+
- **It only reads.** The database is opened `readonly` and `query_only`, so neither
|
|
127
|
+
the pages nor the SQL console can change it. SQLite refuses the write, not a check
|
|
128
|
+
in this code. It also means migrations are never applied: a recording older than
|
|
129
|
+
this build shows a message explaining how to upgrade it instead of broken pages.
|
|
130
|
+
- **It is local.** The server binds to `127.0.0.1`. A recording holds real payloads,
|
|
131
|
+
and any headers that were not redacted at capture time.
|
|
132
|
+
- **One file, one process.** No daemon, and it writes no state of its own to disk.
|
|
133
|
+
Layout preferences live in the browser's localStorage.
|
|
134
|
+
|
|
135
|
+
## From a checkout
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
pnpm install
|
|
139
|
+
pnpm --filter @apisurf/wireui build # produces packages/ui/dist
|
|
140
|
+
pnpm wireui --db examples/wire.sqlite
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
For working on the UI itself, run the Vite dev server against a file:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
WIRE_DB=$PWD/examples/wire.sqlite pnpm ui
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
`WIRE_DB` must be an absolute path, because the dev server runs with `packages/ui`
|
|
150
|
+
as its working directory.
|
|
151
|
+
|
|
152
|
+
Stack: TanStack Start (React 19, file routes, server functions) on Vite with a Nitro
|
|
153
|
+
`node-server` build, Panda CSS, TypeScript checked by `tsgo`, linted with `oxlint`
|
|
154
|
+
and formatted with `oxfmt`. Every dependency is pinned to an exact version, and
|
|
155
|
+
`@apisurf/wire-db` is inlined into the server bundle, so the only runtime
|
|
156
|
+
dependency is `better-sqlite3`. Releases go through the repo's changesets flow —
|
|
157
|
+
see [Releasing](../../README.md#releasing).
|
package/bin/wireui.mjs
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* wireui — browse a recorded wire.sqlite in your browser.
|
|
4
|
+
*
|
|
5
|
+
* wireui ./wire.sqlite on http://127.0.0.1:3000
|
|
6
|
+
* wireui --db ~/work/api.sqlite --port 4000
|
|
7
|
+
*
|
|
8
|
+
* The whole command is: start the prebuilt viewer against one file and print
|
|
9
|
+
* the link. It binds to the loopback interface only and opens the database
|
|
10
|
+
* read-only, so it can neither be reached from the network nor modify
|
|
11
|
+
* what it is showing. It stays in the foreground until Ctrl-C.
|
|
12
|
+
*/
|
|
13
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
14
|
+
import { connect, createServer } from "node:net";
|
|
15
|
+
import { isAbsolute, resolve } from "node:path";
|
|
16
|
+
import { parseArgs } from "node:util";
|
|
17
|
+
|
|
18
|
+
/** Loopback only. A recorded database is full of real payloads and real tokens. */
|
|
19
|
+
const HOST = "127.0.0.1";
|
|
20
|
+
const DEFAULT_DB = "wire.sqlite";
|
|
21
|
+
const DEFAULT_PORT = 3000;
|
|
22
|
+
/** How far above the default port to look when it is taken. */
|
|
23
|
+
const PORT_SCAN = 20;
|
|
24
|
+
|
|
25
|
+
const SERVER_ENTRY = new URL("../dist/server/index.mjs", import.meta.url);
|
|
26
|
+
const MANIFEST = new URL("../package.json", import.meta.url);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* One command, so one page — but it leads with the fact that costs the most to
|
|
30
|
+
* learn the hard way: this process does not exit. Anything reading the help to
|
|
31
|
+
* decide whether to run it needs that in the first screenful, along with where
|
|
32
|
+
* to go instead when a browser is not an option.
|
|
33
|
+
*/
|
|
34
|
+
const USAGE = `wireui — browse a recorded wire.sqlite in your browser.
|
|
35
|
+
|
|
36
|
+
Usage
|
|
37
|
+
wireui [options]
|
|
38
|
+
|
|
39
|
+
Serves a prebuilt web UI over one recording: collections of scripts, their runs,
|
|
40
|
+
every request with its headers, payloads and timings, WebSocket frames, SSE
|
|
41
|
+
events and checks, plus a read-only SQL console. Binds to 127.0.0.1 only and
|
|
42
|
+
opens the database read-only, so it is unreachable from the network and cannot
|
|
43
|
+
change what it is showing.
|
|
44
|
+
|
|
45
|
+
Interactive: this command does not exit. It prints a URL and holds the terminal
|
|
46
|
+
until Ctrl-C. To read a recording programmatically, use \`wire sql\` instead —
|
|
47
|
+
same file, and it prints rows and exits.
|
|
48
|
+
|
|
49
|
+
Options
|
|
50
|
+
--db <path> Database file to read. Default ./wire.sqlite
|
|
51
|
+
--port <n> Port to serve on. Default 3000. Without --port, the next free
|
|
52
|
+
port up to ${DEFAULT_PORT + PORT_SCAN} is used instead of failing
|
|
53
|
+
-h, --help Show this help
|
|
54
|
+
-v, --version Show the version
|
|
55
|
+
|
|
56
|
+
Examples
|
|
57
|
+
wireui
|
|
58
|
+
wireui --db ~/work/api.sqlite
|
|
59
|
+
wireui --db ./runs/sync.sqlite --port 4000
|
|
60
|
+
|
|
61
|
+
Notes
|
|
62
|
+
Record a file first: wire execute ./scripts/sync.ts
|
|
63
|
+
A missing database is not an error — the UI starts empty and fills in.
|
|
64
|
+
Read-only, so leaving it open during a run is fine; toggle Live to follow it.
|
|
65
|
+
`;
|
|
66
|
+
|
|
67
|
+
async function main(argv) {
|
|
68
|
+
let parsed;
|
|
69
|
+
try {
|
|
70
|
+
parsed = parseArgs({
|
|
71
|
+
args: argv,
|
|
72
|
+
options: {
|
|
73
|
+
db: { type: "string" },
|
|
74
|
+
port: { type: "string" },
|
|
75
|
+
help: { type: "boolean", short: "h" },
|
|
76
|
+
version: { type: "boolean", short: "v" },
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
} catch (err) {
|
|
80
|
+
// Point at the page rather than reprinting it under an error.
|
|
81
|
+
process.stderr.write(`wireui: ${message(err)}\nRun wireui --help for the options it takes.\n`);
|
|
82
|
+
return 1;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (parsed.values.help) {
|
|
86
|
+
process.stdout.write(USAGE);
|
|
87
|
+
return 0;
|
|
88
|
+
}
|
|
89
|
+
if (parsed.values.version) {
|
|
90
|
+
process.stdout.write(`${version()}\n`);
|
|
91
|
+
return 0;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (!existsSync(SERVER_ENTRY)) {
|
|
95
|
+
process.stderr.write(
|
|
96
|
+
"wireui: this install has no prebuilt UI in dist/. " +
|
|
97
|
+
"From a checkout, run `pnpm --filter @apisurf/wireui build` first.\n",
|
|
98
|
+
);
|
|
99
|
+
return 1;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const raw = parsed.values.db ?? DEFAULT_DB;
|
|
103
|
+
const dbPath = isAbsolute(raw) ? raw : resolve(process.cwd(), raw);
|
|
104
|
+
if (!existsSync(dbPath)) {
|
|
105
|
+
// Not fatal: the UI renders an empty state, and starting it before the
|
|
106
|
+
// first run is a normal thing to do. Say so rather than fail.
|
|
107
|
+
const empty = "the UI will be empty until a run writes to it";
|
|
108
|
+
process.stderr.write(`wireui: no database at ${dbPath} yet — ${empty}.\n`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const wanted = port(parsed.values.port);
|
|
112
|
+
if (wanted === null) return 1;
|
|
113
|
+
|
|
114
|
+
const listening = await freePort(wanted, parsed.values.port === undefined ? PORT_SCAN : 0);
|
|
115
|
+
if (listening === null) {
|
|
116
|
+
process.stderr.write(
|
|
117
|
+
parsed.values.port === undefined
|
|
118
|
+
? `wireui: ports ${wanted}-${wanted + PORT_SCAN} are all in use. ` +
|
|
119
|
+
"Pass --port <n> to pick one.\n"
|
|
120
|
+
: `wireui: port ${wanted} is already in use.\n`,
|
|
121
|
+
);
|
|
122
|
+
return 1;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
process.env.WIRE_DB = dbPath;
|
|
126
|
+
// NITRO_* wins over the plain names inside the server, so set both: an
|
|
127
|
+
// inherited NITRO_PORT from some other project must not redirect this one.
|
|
128
|
+
process.env.PORT = String(listening);
|
|
129
|
+
process.env.NITRO_PORT = String(listening);
|
|
130
|
+
process.env.HOST = HOST;
|
|
131
|
+
process.env.NITRO_HOST = HOST;
|
|
132
|
+
|
|
133
|
+
swallowServerBanner();
|
|
134
|
+
await import(SERVER_ENTRY.href);
|
|
135
|
+
await waitForServer(listening);
|
|
136
|
+
|
|
137
|
+
const url = `http://${HOST}:${listening}`;
|
|
138
|
+
process.stdout.write(
|
|
139
|
+
`\n wireui\n\n` +
|
|
140
|
+
` open ${url}\n` +
|
|
141
|
+
` database ${dbPath}\n\n` +
|
|
142
|
+
` Ctrl-C to stop.\n\n`,
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
// Nothing more to do here: the server holds the process open until Ctrl-C.
|
|
146
|
+
return new Promise(() => {});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Parse --port. Returns null (after reporting) if it is not a usable port. */
|
|
150
|
+
function port(raw) {
|
|
151
|
+
if (raw === undefined) return DEFAULT_PORT;
|
|
152
|
+
const value = Number(raw);
|
|
153
|
+
if (!Number.isInteger(value) || value < 1 || value > 65535) {
|
|
154
|
+
process.stderr.write(`wireui: --port expects a number between 1 and 65535 (got "${raw}")\n`);
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
return value;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* The first free port at or above `from`, or null if `span` more are all taken.
|
|
162
|
+
*
|
|
163
|
+
* Binding here and releasing it a moment before the server binds leaves a race
|
|
164
|
+
* nothing can close, but it turns the common case — 3000 busy because another
|
|
165
|
+
* dev server has it — from a stack trace into the UI simply opening on 3001.
|
|
166
|
+
*/
|
|
167
|
+
async function freePort(from, span) {
|
|
168
|
+
for (let candidate = from; candidate <= from + span; candidate++) {
|
|
169
|
+
if (await available(candidate)) return candidate;
|
|
170
|
+
}
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function available(candidate) {
|
|
175
|
+
return new Promise((done) => {
|
|
176
|
+
const probe = createServer();
|
|
177
|
+
probe.once("error", () => done(false));
|
|
178
|
+
probe.listen(candidate, HOST, () => probe.close(() => done(true)));
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** Resolve once the server accepts connections, or after `timeoutMs` either way. */
|
|
183
|
+
async function waitForServer(listening, timeoutMs = 5000) {
|
|
184
|
+
const deadline = Date.now() + timeoutMs;
|
|
185
|
+
while (Date.now() < deadline) {
|
|
186
|
+
const up = await new Promise((done) => {
|
|
187
|
+
const socket = connect(listening, HOST);
|
|
188
|
+
socket.once("connect", () => socket.end(() => done(true)));
|
|
189
|
+
socket.once("error", () => done(false));
|
|
190
|
+
});
|
|
191
|
+
if (up) return;
|
|
192
|
+
await new Promise((done) => setTimeout(done, 25));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Print one banner, ours.
|
|
198
|
+
*
|
|
199
|
+
* The server bundle logs its own "Listening on" line the moment the socket is
|
|
200
|
+
* up. Ours says the same thing plus which file it is reading, so the first line
|
|
201
|
+
* matching that is swallowed and the patch takes itself back off.
|
|
202
|
+
*/
|
|
203
|
+
function swallowServerBanner() {
|
|
204
|
+
const log = console.log;
|
|
205
|
+
console.log = (...args) => {
|
|
206
|
+
if (typeof args[0] === "string" && args[0].includes("Listening on:")) {
|
|
207
|
+
console.log = log;
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
log(...args);
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function version() {
|
|
215
|
+
try {
|
|
216
|
+
return JSON.parse(readFileSync(MANIFEST, "utf8")).version ?? "unknown";
|
|
217
|
+
} catch {
|
|
218
|
+
return "unknown";
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function message(err) {
|
|
223
|
+
return err instanceof Error ? err.message : String(err);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
main(process.argv.slice(2))
|
|
227
|
+
.then((code) => {
|
|
228
|
+
process.exitCode = code;
|
|
229
|
+
})
|
|
230
|
+
.catch((err) => {
|
|
231
|
+
process.stderr.write(`wireui: ${err instanceof Error ? (err.stack ?? err.message) : err}\n`);
|
|
232
|
+
process.exitCode = 1;
|
|
233
|
+
});
|
package/dist/nitro.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"date": "2026-09-26T22:52:53.907Z",
|
|
3
|
+
"preset": "node-server",
|
|
4
|
+
"framework": {
|
|
5
|
+
"name": "nitro",
|
|
6
|
+
"version": "3.0.260903-beta"
|
|
7
|
+
},
|
|
8
|
+
"versions": {
|
|
9
|
+
"nitro": "3.0.260903-beta"
|
|
10
|
+
},
|
|
11
|
+
"serverEntry": "server/index.mjs",
|
|
12
|
+
"publicDir": "public",
|
|
13
|
+
"commands": {
|
|
14
|
+
"preview": "node ./server/index.mjs"
|
|
15
|
+
},
|
|
16
|
+
"config": {}
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{B as e,C as t,Ct as n,E as r,F as i,G as a,H as o,L as s,N as c,O as l,P as u,R as d,S as f,U as p,W as m,_ as h,b as g,bt as _,dt as v,f as y,h as b,i as x,k as S,l as C,m as w,nt as T,q as E,s as D,st as O,tt as k,u as A,v as j,vt as M,wt as N,yt as P,z as F}from"./index-D5VFd_3H.js";import{t as I}from"./scoped-DB8raIWx.js";var L=N();function R(){let r=x.useLoaderData(),{tab:i=`runs`,entry:a}=x.useSearch(),s=n({from:x.fullPath}),c=t(),l=y(Date.now()),{data:u}=I(r,async e=>await D({data:{entry:a,env:e}})??r),{script:d,runs:f,endpoints:h,checks:g}=u;if(A({key:C.script(d.entry),title:d.file,icon:`collection`}),c)return c;let b=g.filter(e=>e.last_status===`fail`).length;return(0,L.jsxs)(`div`,{className:_({display:`flex`,flexDir:`column`,h:`full`,minH:`0`}),children:[(0,L.jsxs)(`header`,{className:_({px:`5`,pt:`4`,pb:`3`,flexShrink:0}),children:[(0,L.jsxs)(`div`,{className:_({display:`flex`,alignItems:`center`,gap:`2`}),children:[(0,L.jsx)(`span`,{className:_({color:`muted`,display:`inline-flex`}),children:(0,L.jsx)(v,{size:18})}),(0,L.jsx)(`h1`,{className:_({fontSize:`18px`,fontWeight:`600`,m:`0`}),children:d.file})]}),(0,L.jsx)(`p`,{className:P(o,_({color:`muted`,m:`0`,mt:`0.5`})),title:d.entry,children:d.rel})]}),(0,L.jsx)(e,{items:[{id:`runs`,label:`Runs`,count:f.length},{id:`requests`,label:`Requests`,count:h.length},{id:`checks`,label:`Checks`,count:g.length,tone:b?`bad`:void 0,hidden:g.length===0}],value:i,onSelect:e=>void s({search:t=>({...t,tab:e===`runs`?void 0:e})})}),(0,L.jsx)(`div`,{className:m,children:(0,L.jsxs)(`div`,{className:p,children:[i===`runs`?(0,L.jsx)(z,{runs:f,now:l}):null,i===`requests`?(0,L.jsx)(W,{endpoints:h,now:l}):null,i===`checks`?(0,L.jsx)(G,{checks:g}):null]})})]})}function z({runs:e,now:t}){let c=n();if(e.length===0)return(0,L.jsx)(S,{title:`No runs in this environment`});let p=e.filter(e=>e.finished_at!=null),m=p.map(e=>e.finished_at-e.started_at).toSorted((e,t)=>e-t),v=m.length?m[Math.floor((m.length-1)/2)]:null,y=e.filter(e=>k(e)===`bad`).length,x=e.reduce((e,t)=>e+t.request_count,0);return(0,L.jsxs)(L.Fragment,{children:[(0,L.jsxs)(d,{children:[(0,L.jsx)(s,{label:`Runs`,value:h(e.length),sub:`last ${w(t,e[0].started_at)}`}),(0,L.jsx)(s,{label:`Failed runs`,value:h(y),tone:y?`bad`:`ok`,sub:`threw, or a check failed`}),(0,L.jsx)(s,{label:`Median wall time`,value:g(v),sub:`${f(p.length,`finished run`)}`}),(0,L.jsx)(s,{label:`Requests`,value:h(x),sub:`${h(Math.round(x/e.length))} per run`})]}),(0,L.jsxs)(`section`,{children:[(0,L.jsx)(i,{children:`Wall time per run`}),(0,L.jsx)(H,{runs:e})]}),(0,L.jsxs)(`section`,{children:[(0,L.jsx)(i,{children:`History`}),(0,L.jsx)(r,{children:(0,L.jsxs)(`table`,{className:a,children:[(0,L.jsx)(`thead`,{children:(0,L.jsxs)(`tr`,{children:[(0,L.jsx)(`th`,{children:`Run`}),(0,L.jsx)(`th`,{children:`Result`}),(0,L.jsx)(`th`,{children:`Env`}),(0,L.jsx)(`th`,{className:`num`,children:`Requests`}),(0,L.jsx)(`th`,{className:`num`,children:`Checks`}),(0,L.jsx)(`th`,{className:`num`,children:`Data`}),(0,L.jsx)(`th`,{className:`num`,children:`Wall`}),(0,L.jsx)(`th`,{className:`num`,children:`Started`})]})}),(0,L.jsx)(`tbody`,{children:e.map(e=>(0,L.jsxs)(`tr`,{"data-link":!0,onClick:()=>void c({to:`/runs/$runId`,params:{runId:String(e.id)}}),children:[(0,L.jsx)(`td`,{children:(0,L.jsxs)(`div`,{className:_({display:`flex`,alignItems:`center`,gap:`2`}),children:[(0,L.jsx)(l,{tone:k(e)}),(0,L.jsxs)(`span`,{className:o,children:[`#`,e.id]}),e.label&&e.label!==e.entry.split(`/`).pop()?(0,L.jsx)(`span`,{className:P(E,_({color:`muted`})),children:e.label}):null]})}),(0,L.jsx)(`td`,{className:_({color:`muted`,whiteSpace:`nowrap`}),children:T(e)}),(0,L.jsx)(`td`,{children:e.env?(0,L.jsx)(u,{children:e.env}):null}),(0,L.jsxs)(`td`,{className:`num`,children:[h(e.request_count),e.error_count?(0,L.jsxs)(`span`,{className:_({color:`warn`}),children:[` · `,e.error_count,`✕`]}):null]}),(0,L.jsx)(`td`,{className:P(`num`,e.failed_check_count?_({color:`bad`}):void 0),children:e.check_count?`${e.check_count-e.failed_check_count}/${e.check_count}`:`—`}),(0,L.jsx)(`td`,{className:P(`num`,o),children:b(e.total_bytes)}),(0,L.jsx)(`td`,{className:P(`num`,o),children:e.finished_at?g(e.finished_at-e.started_at):`—`}),(0,L.jsx)(`td`,{className:P(`num`,_({color:`muted`})),children:j(t,e.started_at)})]},e.id))})]})})]})]})}var B={ok:_({bg:`ok`}),warn:_({bg:`warn`}),bad:_({bg:`bad`}),info:_({bg:`info`}),neutral:_({bg:`faint`})},V=60;function H({runs:e}){let t=n(),i=e.slice(0,V).toReversed(),a=i.map(e=>e.finished_at?e.finished_at-e.started_at:0),o=Math.max(...a,1);return(0,L.jsxs)(r,{className:_({p:`3`}),children:[(0,L.jsx)(`div`,{className:_({display:`flex`,alignItems:`flex-end`,gap:`2px`,h:`88px`}),children:i.map((e,n)=>(0,L.jsx)(`button`,{type:`button`,title:`#${e.id} · ${g(a[n])} · ${T(e)}`,onClick:()=>void t({to:`/runs/$runId`,params:{runId:String(e.id)}}),className:_({flex:`1`,maxW:`22px`,minW:`4px`,h:`full`,display:`flex`,alignItems:`flex-end`,border:`none`,bg:`transparent`,p:`0`,cursor:`pointer`,rounded:`xs`,_hover:{bg:`hover`}}),children:(0,L.jsx)(`span`,{className:P(_({display:`block`,w:`full`,roundedTop:`sm`}),B[k(e)]),style:{height:`${Math.max(a[n]/o*100,3)}%`}})},e.id))}),(0,L.jsxs)(`div`,{className:_({display:`flex`,gap:`4`,mt:`2`,fontSize:`11px`,color:`muted`,flexWrap:`wrap`}),children:[(0,L.jsxs)(`span`,{children:[`max `,g(o)]}),(0,L.jsx)(U,{tone:`ok`,label:`Passed`}),(0,L.jsx)(U,{tone:`warn`,label:`Failed requests`}),(0,L.jsx)(U,{tone:`bad`,label:`Threw or failed a check`}),(0,L.jsx)(U,{tone:`info`,label:`Unfinished`})]})]})}function U({tone:e,label:t}){return(0,L.jsxs)(`span`,{className:_({display:`inline-flex`,alignItems:`center`,gap:`1`}),children:[(0,L.jsx)(`span`,{className:P(_({w:`8px`,h:`8px`,rounded:`xs`}),B[e])}),t]})}function W({endpoints:e,now:t}){let i=n();return e.length===0?(0,L.jsx)(S,{title:`No requests in this environment`}):(0,L.jsx)(r,{children:(0,L.jsxs)(`table`,{className:a,children:[(0,L.jsx)(`thead`,{children:(0,L.jsxs)(`tr`,{children:[(0,L.jsx)(`th`,{children:`Request`}),(0,L.jsx)(`th`,{children:`Last`}),(0,L.jsx)(`th`,{className:`num`,children:`Calls`}),(0,L.jsx)(`th`,{className:`num`,children:`Errors`}),(0,L.jsx)(`th`,{className:`num`,children:`Avg`}),(0,L.jsx)(`th`,{className:`num`,children:`Last seen`})]})}),(0,L.jsx)(`tbody`,{children:e.map(e=>(0,L.jsxs)(`tr`,{"data-link":!0,onClick:()=>void i({to:`/requests/$requestId`,params:{requestId:String(e.last_request_id)}}),children:[(0,L.jsx)(`td`,{className:_({maxW:`0`,w:`full`}),children:(0,L.jsxs)(`div`,{className:_({display:`flex`,alignItems:`center`,gap:`2`,minW:`0`}),children:[(0,L.jsx)(c,{method:e.method,kind:e.kind,width:`list`}),(0,L.jsxs)(`span`,{className:P(E,o),title:`${e.host}${e.path}`,children:[(0,L.jsx)(`span`,{className:_({color:`faint`}),children:e.host}),e.path]})]})}),(0,L.jsx)(`td`,{children:(0,L.jsx)(F,{status:e.last_status,error:e.last_error_name})}),(0,L.jsx)(`td`,{className:`num`,children:h(e.count)}),(0,L.jsx)(`td`,{className:P(`num`,e.errors?_({color:`warn`}):void 0),children:h(e.errors)}),(0,L.jsx)(`td`,{className:P(`num`,o),children:e.kind===`http`?g(e.avg_ms):`—`}),(0,L.jsx)(`td`,{className:P(`num`,_({color:`muted`})),children:w(t,e.last_ts)})]},`${e.kind} ${e.method} ${e.host}${e.path}`))})]})})}function G({checks:e}){let t=n();return(0,L.jsx)(r,{children:(0,L.jsxs)(`table`,{className:a,children:[(0,L.jsx)(`thead`,{children:(0,L.jsxs)(`tr`,{children:[(0,L.jsx)(`th`,{children:`Check`}),(0,L.jsx)(`th`,{children:`Latest`}),(0,L.jsx)(`th`,{className:`num`,children:`Pass rate`}),(0,L.jsx)(`th`,{className:`num`,children:`Failures`})]})}),(0,L.jsx)(`tbody`,{children:e.map(e=>(0,L.jsxs)(`tr`,{"data-link":!0,onClick:()=>void t({to:`/runs/$runId`,params:{runId:String(e.last_run_id)},search:{tab:`checks`}}),children:[(0,L.jsx)(`td`,{className:_({maxW:`0`,w:`full`}),children:(0,L.jsxs)(`div`,{className:_({display:`flex`,gap:`2`,alignItems:`flex-start`}),children:[(0,L.jsx)(`span`,{className:e.last_status===`pass`?_({color:`ok`}):_({color:`bad`}),children:e.last_status===`pass`?(0,L.jsx)(O,{size:15}):(0,L.jsx)(M,{size:15})}),(0,L.jsxs)(`span`,{className:_({minW:`0`}),children:[(0,L.jsx)(`span`,{className:P(E,_({display:`block`})),children:e.name}),e.last_status===`fail`&&e.last_message?(0,L.jsx)(`span`,{className:P(E,_({display:`block`,color:`bad`,fontSize:`12px`})),children:e.last_message}):null]})]})}),(0,L.jsx)(`td`,{children:e.last_status===`pass`?(0,L.jsx)(u,{tone:`ok`,children:`pass`}):(0,L.jsx)(u,{tone:`bad`,children:`fail`})}),(0,L.jsxs)(`td`,{className:`num`,children:[Math.round((e.total-e.failures)/e.total*100),`%`]}),(0,L.jsxs)(`td`,{className:P(`num`,e.failures?_({color:`bad`}):void 0),children:[e.failures,`/`,e.total]})]},e.name))})]})})}export{R as component};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@layer reset{html,:host{--font-fallback:ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";-webkit-text-size-adjust:100%;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;tab-size:4;line-height:1.5;font-family:var(--global-font-body,var(--font-fallback));-webkit-tap-highlight-color:transparent}*,:before,:after,::backdrop{border-style:solid;border-width:0;border-color:var(--global-color-border,currentcolor);box-sizing:border-box;margin:0;padding:0}::file-selector-button{border-style:solid;border-width:0;border-color:var(--global-color-border,currentcolor);box-sizing:border-box;margin:0;padding:0}hr{color:inherit;border-top-width:1px;height:0}body{line-height:inherit;height:100%}img{border-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}h1,h2,h3,h4,h5,h6{text-wrap:balance;font-size:inherit;font-weight:inherit}p,h1,h2,h3,h4,h5,h6{overflow-wrap:break-word}ol,ul,menu{list-style:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}button,input,optgroup,select,textarea{font:inherit;background:var(--colors-transparent);font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit}::file-selector-button{font:inherit;background:var(--colors-transparent);font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit}::placeholder{--placeholder-fallback:#00000080;opacity:1;color:var(--global-color-placeholder,var(--placeholder-fallback))}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{--placeholder-fallback:color-mix(in oklab, currentcolor 50%, transparent)}}::selection{background-color:var(--global-color-selection,#0073ff4d)}textarea{resize:vertical}table{border-color:inherit;text-indent:0;border-collapse:collapse}summary{display:list-item}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}dialog{padding:0}a{-webkit-text-decoration:inherit;text-decoration:inherit;color:inherit}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp,pre{--font-mono-fallback:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New";font-family:var(--global-font-mono,var(--font-mono-fallback));font-feature-settings:normal;font-variation-settings:normal;font-size:1em}progress{vertical-align:baseline}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-search-cancel-button{-webkit-appearance:none}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}:-moz-ui-invalid{box-shadow:none}:-moz-focusring{outline:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer base{:root{--made-with-panda:"🐼"}html,body{height:100%;overflow:hidden}body{background:var(--colors-canvas);margin:var(--spacing-0);font-family:var(--fonts-body);color:var(--colors-fg);-webkit-font-smoothing:antialiased;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light;font-size:13px;line-height:1.45}[data-theme=dark] body{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}input,button,select,textarea{font-family:inherit;font-size:inherit;color:inherit}::selection{background:var(--colors-accent-soft)}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-thumb{background:var(--colors-line-strong);-webkit-background-clip:content-box;background-clip:content-box;border:3px solid #0000;border-radius:999px}::-webkit-scrollbar-corner{background:var(--colors-transparent)}*,:before,:after,::backdrop{--blur: ;--brightness: ;--contrast: ;--grayscale: ;--hue-rotate: ;--invert: ;--saturate: ;--sepia: ;--drop-shadow: ;--backdrop-blur: ;--backdrop-brightness: ;--backdrop-contrast: ;--backdrop-grayscale: ;--backdrop-hue-rotate: ;--backdrop-invert: ;--backdrop-opacity: ;--backdrop-saturate: ;--backdrop-sepia: ;--gradient-from-position: ;--gradient-to-position: ;--gradient-via-position: ;--scroll-snap-strictness:proximity;--border-spacing-x:0;--border-spacing-y:0;--translate-x:0;--translate-y:0;--rotate:0;--rotate-x:0;--rotate-y:0;--skew-x:0;--skew-y:0;--scale-x:1;--scale-y:1}}@layer tokens{:where(:root,:host){--aspect-ratios-square:1 / 1;--aspect-ratios-landscape:4 / 3;--aspect-ratios-portrait:3 / 4;--aspect-ratios-wide:16 / 9;--aspect-ratios-ultrawide:18 / 5;--aspect-ratios-golden:1.618 / 1;--borders-none:none;--easings-default:cubic-bezier(.4, 0, .2, 1);--easings-linear:linear;--easings-in:cubic-bezier(.4, 0, 1, 1);--easings-out:cubic-bezier(0, 0, .2, 1);--easings-in-out:cubic-bezier(.4, 0, .2, 1);--durations-fastest:50ms;--durations-faster:.1s;--durations-fast:.15s;--durations-normal:.2s;--durations-slow:.3s;--durations-slower:.4s;--durations-slowest:.5s;--font-weights-thin:100;--font-weights-extralight:200;--font-weights-light:300;--font-weights-normal:400;--font-weights-medium:500;--font-weights-semibold:600;--font-weights-bold:700;--font-weights-extrabold:800;--font-weights-black:900;--line-heights-none:1;--line-heights-tight:1.25;--line-heights-snug:1.375;--line-heights-normal:1.5;--line-heights-relaxed:1.625;--line-heights-loose:2;--letter-spacings-tighter:-.05em;--letter-spacings-tight:-.025em;--letter-spacings-normal:0em;--letter-spacings-wide:.025em;--letter-spacings-wider:.05em;--letter-spacings-widest:.1em;--font-sizes-2xs:.5rem;--font-sizes-xs:.75rem;--font-sizes-sm:.875rem;--font-sizes-md:1rem;--font-sizes-lg:1.125rem;--font-sizes-xl:1.25rem;--font-sizes-2xl:1.5rem;--font-sizes-3xl:1.875rem;--font-sizes-4xl:2.25rem;--font-sizes-5xl:3rem;--font-sizes-6xl:3.75rem;--font-sizes-7xl:4.5rem;--font-sizes-8xl:6rem;--font-sizes-9xl:8rem;--shadows-2xs:0 1px #0000000d;--shadows-xs:0 1px 2px 0 #0000000d;--shadows-sm:0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a;--shadows-md:0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a;--shadows-lg:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--shadows-xl:0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a;--shadows-2xl:0 25px 50px -12px #00000040;--shadows-inset-2xs:inset 0 1px #0000000d;--shadows-inset-xs:inset 0 1px 1px #0000000d;--shadows-inset-sm:inset 0 2px 4px #0000000d;--colors-current:currentColor;--colors-black:#000;--colors-white:#fff;--colors-transparent:#0000;--colors-rose-50:#fff1f2;--colors-rose-100:#ffe4e6;--colors-rose-200:#fecdd3;--colors-rose-300:#fda4af;--colors-rose-400:#fb7185;--colors-rose-500:#f43f5e;--colors-rose-600:#e11d48;--colors-rose-700:#be123c;--colors-rose-800:#9f1239;--colors-rose-900:#881337;--colors-rose-950:#4c0519;--colors-pink-50:#fdf2f8;--colors-pink-100:#fce7f3;--colors-pink-200:#fbcfe8;--colors-pink-300:#f9a8d4;--colors-pink-400:#f472b6;--colors-pink-500:#ec4899;--colors-pink-600:#db2777;--colors-pink-700:#be185d;--colors-pink-800:#9d174d;--colors-pink-900:#831843;--colors-pink-950:#500724;--colors-fuchsia-50:#fdf4ff;--colors-fuchsia-100:#fae8ff;--colors-fuchsia-200:#f5d0fe;--colors-fuchsia-300:#f0abfc;--colors-fuchsia-400:#e879f9;--colors-fuchsia-500:#d946ef;--colors-fuchsia-600:#c026d3;--colors-fuchsia-700:#a21caf;--colors-fuchsia-800:#86198f;--colors-fuchsia-900:#701a75;--colors-fuchsia-950:#4a044e;--colors-purple-50:#faf5ff;--colors-purple-100:#f3e8ff;--colors-purple-200:#e9d5ff;--colors-purple-300:#d8b4fe;--colors-purple-400:#c084fc;--colors-purple-500:#a855f7;--colors-purple-600:#9333ea;--colors-purple-700:#7e22ce;--colors-purple-800:#6b21a8;--colors-purple-900:#581c87;--colors-purple-950:#3b0764;--colors-violet-50:#f5f3ff;--colors-violet-100:#ede9fe;--colors-violet-200:#ddd6fe;--colors-violet-300:#c4b5fd;--colors-violet-400:#a78bfa;--colors-violet-500:#8b5cf6;--colors-violet-600:#7c3aed;--colors-violet-700:#6d28d9;--colors-violet-800:#5b21b6;--colors-violet-900:#4c1d95;--colors-violet-950:#2e1065;--colors-indigo-50:#eef2ff;--colors-indigo-100:#e0e7ff;--colors-indigo-200:#c7d2fe;--colors-indigo-300:#a5b4fc;--colors-indigo-400:#818cf8;--colors-indigo-500:#6366f1;--colors-indigo-600:#4f46e5;--colors-indigo-700:#4338ca;--colors-indigo-800:#3730a3;--colors-indigo-900:#312e81;--colors-indigo-950:#1e1b4b;--colors-blue-50:#eff6ff;--colors-blue-100:#dbeafe;--colors-blue-200:#bfdbfe;--colors-blue-300:#93c5fd;--colors-blue-400:#60a5fa;--colors-blue-500:#3b82f6;--colors-blue-600:#2563eb;--colors-blue-700:#1d4ed8;--colors-blue-800:#1e40af;--colors-blue-900:#1e3a8a;--colors-blue-950:#172554;--colors-sky-50:#f0f9ff;--colors-sky-100:#e0f2fe;--colors-sky-200:#bae6fd;--colors-sky-300:#7dd3fc;--colors-sky-400:#38bdf8;--colors-sky-500:#0ea5e9;--colors-sky-600:#0284c7;--colors-sky-700:#0369a1;--colors-sky-800:#075985;--colors-sky-900:#0c4a6e;--colors-sky-950:#082f49;--colors-cyan-50:#ecfeff;--colors-cyan-100:#cffafe;--colors-cyan-200:#a5f3fc;--colors-cyan-300:#67e8f9;--colors-cyan-400:#22d3ee;--colors-cyan-500:#06b6d4;--colors-cyan-600:#0891b2;--colors-cyan-700:#0e7490;--colors-cyan-800:#155e75;--colors-cyan-900:#164e63;--colors-cyan-950:#083344;--colors-teal-50:#f0fdfa;--colors-teal-100:#ccfbf1;--colors-teal-200:#99f6e4;--colors-teal-300:#5eead4;--colors-teal-400:#2dd4bf;--colors-teal-500:#14b8a6;--colors-teal-600:#0d9488;--colors-teal-700:#0f766e;--colors-teal-800:#115e59;--colors-teal-900:#134e4a;--colors-teal-950:#042f2e;--colors-emerald-50:#ecfdf5;--colors-emerald-100:#d1fae5;--colors-emerald-200:#a7f3d0;--colors-emerald-300:#6ee7b7;--colors-emerald-400:#34d399;--colors-emerald-500:#10b981;--colors-emerald-600:#059669;--colors-emerald-700:#047857;--colors-emerald-800:#065f46;--colors-emerald-900:#064e3b;--colors-emerald-950:#022c22;--colors-green-50:#f0fdf4;--colors-green-100:#dcfce7;--colors-green-200:#bbf7d0;--colors-green-300:#86efac;--colors-green-400:#4ade80;--colors-green-500:#22c55e;--colors-green-600:#16a34a;--colors-green-700:#15803d;--colors-green-800:#166534;--colors-green-900:#14532d;--colors-green-950:#052e16;--colors-lime-50:#f7fee7;--colors-lime-100:#ecfccb;--colors-lime-200:#d9f99d;--colors-lime-300:#bef264;--colors-lime-400:#a3e635;--colors-lime-500:#84cc16;--colors-lime-600:#65a30d;--colors-lime-700:#4d7c0f;--colors-lime-800:#3f6212;--colors-lime-900:#365314;--colors-lime-950:#1a2e05;--colors-yellow-50:#fefce8;--colors-yellow-100:#fef9c3;--colors-yellow-200:#fef08a;--colors-yellow-300:#fde047;--colors-yellow-400:#facc15;--colors-yellow-500:#eab308;--colors-yellow-600:#ca8a04;--colors-yellow-700:#a16207;--colors-yellow-800:#854d0e;--colors-yellow-900:#713f12;--colors-yellow-950:#422006;--colors-amber-50:#fffbeb;--colors-amber-100:#fef3c7;--colors-amber-200:#fde68a;--colors-amber-300:#fcd34d;--colors-amber-400:#fbbf24;--colors-amber-500:#f59e0b;--colors-amber-600:#d97706;--colors-amber-700:#b45309;--colors-amber-800:#92400e;--colors-amber-900:#78350f;--colors-amber-950:#451a03;--colors-orange-50:#fff7ed;--colors-orange-100:#ffedd5;--colors-orange-200:#fed7aa;--colors-orange-300:#fdba74;--colors-orange-400:#fb923c;--colors-orange-500:#f97316;--colors-orange-600:#ea580c;--colors-orange-700:#c2410c;--colors-orange-800:#9a3412;--colors-orange-900:#7c2d12;--colors-orange-950:#431407;--colors-red-50:#fef2f2;--colors-red-100:#fee2e2;--colors-red-200:#fecaca;--colors-red-300:#fca5a5;--colors-red-400:#f87171;--colors-red-500:#ef4444;--colors-red-600:#dc2626;--colors-red-700:#b91c1c;--colors-red-800:#991b1b;--colors-red-900:#7f1d1d;--colors-red-950:#450a0a;--colors-neutral-50:#fafafa;--colors-neutral-100:#f5f5f5;--colors-neutral-200:#e5e5e5;--colors-neutral-300:#d4d4d4;--colors-neutral-400:#a3a3a3;--colors-neutral-500:#737373;--colors-neutral-600:#525252;--colors-neutral-700:#404040;--colors-neutral-800:#262626;--colors-neutral-900:#171717;--colors-neutral-950:#0a0a0a;--colors-stone-50:#fafaf9;--colors-stone-100:#f5f5f4;--colors-stone-200:#e7e5e4;--colors-stone-300:#d6d3d1;--colors-stone-400:#a8a29e;--colors-stone-500:#78716c;--colors-stone-600:#57534e;--colors-stone-700:#44403c;--colors-stone-800:#292524;--colors-stone-900:#1c1917;--colors-stone-950:#0c0a09;--colors-zinc-50:#fafafa;--colors-zinc-100:#f4f4f5;--colors-zinc-200:#e4e4e7;--colors-zinc-300:#d4d4d8;--colors-zinc-400:#a1a1aa;--colors-zinc-500:#71717a;--colors-zinc-600:#52525b;--colors-zinc-700:#3f3f46;--colors-zinc-800:#27272a;--colors-zinc-900:#18181b;--colors-zinc-950:#09090b;--colors-gray-50:#f9fafb;--colors-gray-100:#f3f4f6;--colors-gray-200:#e5e7eb;--colors-gray-300:#d1d5db;--colors-gray-400:#9ca3af;--colors-gray-500:#6b7280;--colors-gray-600:#4b5563;--colors-gray-700:#374151;--colors-gray-800:#1f2937;--colors-gray-900:#111827;--colors-gray-950:#030712;--colors-slate-50:#f8fafc;--colors-slate-100:#f1f5f9;--colors-slate-200:#e2e8f0;--colors-slate-300:#cbd5e1;--colors-slate-400:#94a3b8;--colors-slate-500:#64748b;--colors-slate-600:#475569;--colors-slate-700:#334155;--colors-slate-800:#1e293b;--colors-slate-900:#0f172a;--colors-slate-950:#020617;--blurs-xs:4px;--blurs-sm:8px;--blurs-md:12px;--blurs-lg:16px;--blurs-xl:24px;--blurs-2xl:40px;--blurs-3xl:64px;--spacing-0:0rem;--spacing-1:.25rem;--spacing-2:.5rem;--spacing-3:.75rem;--spacing-4:1rem;--spacing-5:1.25rem;--spacing-6:1.5rem;--spacing-7:1.75rem;--spacing-8:2rem;--spacing-9:2.25rem;--spacing-10:2.5rem;--spacing-11:2.75rem;--spacing-12:3rem;--spacing-14:3.5rem;--spacing-16:4rem;--spacing-20:5rem;--spacing-24:6rem;--spacing-28:7rem;--spacing-32:8rem;--spacing-36:9rem;--spacing-40:10rem;--spacing-44:11rem;--spacing-48:12rem;--spacing-52:13rem;--spacing-56:14rem;--spacing-60:15rem;--spacing-64:16rem;--spacing-72:18rem;--spacing-80:20rem;--spacing-96:24rem;--spacing-0\.5:.125rem;--spacing-1\.5:.375rem;--spacing-2\.5:.625rem;--spacing-3\.5:.875rem;--spacing-4\.5:1.125rem;--spacing-5\.5:1.375rem;--sizes-0:0rem;--sizes-1:.25rem;--sizes-2:.5rem;--sizes-3:.75rem;--sizes-4:1rem;--sizes-5:1.25rem;--sizes-6:1.5rem;--sizes-7:1.75rem;--sizes-8:2rem;--sizes-9:2.25rem;--sizes-10:2.5rem;--sizes-11:2.75rem;--sizes-12:3rem;--sizes-14:3.5rem;--sizes-16:4rem;--sizes-20:5rem;--sizes-24:6rem;--sizes-28:7rem;--sizes-32:8rem;--sizes-36:9rem;--sizes-40:10rem;--sizes-44:11rem;--sizes-48:12rem;--sizes-52:13rem;--sizes-56:14rem;--sizes-60:15rem;--sizes-64:16rem;--sizes-72:18rem;--sizes-80:20rem;--sizes-96:24rem;--sizes-0\.5:.125rem;--sizes-1\.5:.375rem;--sizes-2\.5:.625rem;--sizes-3\.5:.875rem;--sizes-4\.5:1.125rem;--sizes-5\.5:1.375rem;--sizes-xs:20rem;--sizes-sm:24rem;--sizes-md:28rem;--sizes-lg:32rem;--sizes-xl:36rem;--sizes-2xl:42rem;--sizes-3xl:48rem;--sizes-4xl:56rem;--sizes-5xl:64rem;--sizes-6xl:72rem;--sizes-7xl:80rem;--sizes-8xl:90rem;--sizes-prose:65ch;--sizes-full:100%;--sizes-min:min-content;--sizes-max:max-content;--sizes-fit:fit-content;--sizes-breakpoint-sm:640px;--sizes-breakpoint-md:768px;--sizes-breakpoint-lg:1024px;--sizes-breakpoint-xl:1280px;--sizes-breakpoint-2xl:1536px;--animations-spin:spin 1s linear infinite;--animations-ping:ping 1s cubic-bezier(0, 0, .2, 1) infinite;--animations-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--animations-bounce:bounce 1s infinite;--fonts-sans:ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--fonts-serif:ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;--fonts-body:Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;--fonts-mono:"JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;--radii-xl:.75rem;--radii-2xl:1rem;--radii-3xl:1.5rem;--radii-4xl:2rem;--radii-full:9999px;--radii-xs:3px;--radii-sm:4px;--radii-md:6px;--radii-lg:8px;--breakpoints-sm:640px;--breakpoints-md:768px;--breakpoints-lg:1024px;--breakpoints-xl:1280px;--breakpoints-2xl:1536px;--colors-chrome:#f3f4f6;--colors-canvas:#fff;--colors-raised:#fff;--colors-well:#f8f9fb;--colors-hover:#eceef2;--colors-selected:#e5edff;--colors-fg:#18181b;--colors-muted:#5f6572;--colors-faint:#9097a3;--colors-line:#e3e5ea;--colors-line-strong:#cfd3da;--colors-accent:#1f6feb;--colors-accent-fg:#fff;--colors-accent-soft:#e8f0fe;--colors-ok:#15803d;--colors-ok-soft:#e7f6ec;--colors-warn:#b45309;--colors-warn-soft:#fdf3e3;--colors-bad:#c62828;--colors-bad-soft:#fdecec;--colors-info:#1d4ed8;--colors-get:#15803d;--colors-post:#b45309;--colors-put:#1d4ed8;--colors-patch:#7e22ce;--colors-delete:#c62828;--colors-other:#64748b;--colors-ws:#7c3aed;--colors-sse:#0f766e;--colors-syn-key:#9a3412;--colors-syn-string:#15803d;--colors-syn-number:#1d4ed8;--colors-syn-bool:#7e22ce;--colors-syn-null:#6b7280;--colors-syn-punct:#6b7280}[data-theme=dark]{--colors-chrome:#18181b;--colors-canvas:#1f1f23;--colors-raised:#26262b;--colors-well:#19191c;--colors-hover:#2c2c32;--colors-selected:#2b3350;--colors-fg:#e7e7ea;--colors-muted:#a1a1aa;--colors-faint:#6c6c75;--colors-line:#303036;--colors-line-strong:#43434b;--colors-accent:#6ea8fe;--colors-accent-fg:#0b1220;--colors-accent-soft:#1e2a44;--colors-ok:#4ade80;--colors-ok-soft:#16301f;--colors-warn:#fbbf24;--colors-warn-soft:#352a12;--colors-bad:#f87171;--colors-bad-soft:#3a1d1f;--colors-info:#60a5fa;--colors-get:#4ade80;--colors-post:#fbbf24;--colors-put:#60a5fa;--colors-patch:#c084fc;--colors-delete:#f87171;--colors-other:#94a3b8;--colors-ws:#a78bfa;--colors-sse:#2dd4bf;--colors-syn-key:#f0abfc;--colors-syn-string:#86efac;--colors-syn-number:#93c5fd;--colors-syn-bool:#c4b5fd;--colors-syn-null:#9ca3af;--colors-syn-punct:#71717a}@keyframes spin{to{transform:rotate(360deg)}}@keyframes ping{75%,to{opacity:0;transform:scale(2)}}@keyframes pulse{50%{opacity:.5}}@keyframes bounce{0%,to{animation-timing-function:cubic-bezier(.8,0,1,1);transform:translateY(-25%)}50%{animation-timing-function:cubic-bezier(0,0,.2,1);transform:none}}}@layer recipes;@layer utilities{.bg_well{background:var(--colors-well)}.p_4{padding:var(--spacing-4)}.bd_none{border:var(--borders-none)}.bg_white{background:var(--colors-white)}.bg_transparent{background:var(--colors-transparent)}.bg_okSoft{background:var(--colors-ok-soft)}.bg_accentSoft{background:var(--colors-accent-soft)}.bg_warnSoft{background:var(--colors-warn-soft)}.bg_badSoft{background:var(--colors-bad-soft)}.bg_hover{background:var(--colors-hover)}.bg_ok{background:var(--colors-ok)}.bg_info{background:var(--colors-info)}.bg_warn{background:var(--colors-warn)}.bg_bad{background:var(--colors-bad)}.bg_faint{background:var(--colors-faint)}.bd_1px_solid{border:1px solid}.bg_raised{background:var(--colors-raised)}.p_2px{padding:2px}.bg_canvas{background:var(--colors-canvas)}.m_0{margin:var(--spacing-0)}.bg_chrome{background:var(--colors-chrome)}.anim_pulse_1\.6s_ease-in-out_infinite{animation:1.6s ease-in-out infinite pulse}.bg_line{background:var(--colors-line)}.bg_accent{background:var(--colors-accent)}.p_0{padding:var(--spacing-0)}.bg_sse{background:var(--colors-sse)}.bg_patch{background:var(--colors-patch)}.bg_post{background:var(--colors-post)}.bg_get{background:var(--colors-get)}.p_3{padding:var(--spacing-3)}.p_2\.5{padding:var(--spacing-2\.5)}.gap_2{gap:var(--spacing-2)}.px_3{padding-inline:var(--spacing-3)}.py_1\.5{padding-block:var(--spacing-1\.5)}.bd-b_1px_solid{border-bottom:1px solid}.bd-c_line{border-color:var(--colors-line)}.flex_1{flex:1}.gap_1\.5{gap:var(--spacing-1\.5)}.ov_auto{overflow:auto}.bg-p_0_0\,_0_8px\,_8px_-8px\,_-8px_0{background-position:0 0,0 8px,8px -8px,-8px 0}.py_2{padding-block:var(--spacing-2)}.bdr_xs{border-radius:var(--radii-xs)}.px_1{padding-inline:var(--spacing-1)}.py_1{padding-block:var(--spacing-1)}.ov_hidden{overflow:hidden}.gap_1{gap:var(--spacing-1)}.px_2{padding-inline:var(--spacing-2)}.py_0\.5{padding-block:var(--spacing-0\.5)}.bdr_sm{border-radius:var(--radii-sm)}.bdr_full{border-radius:var(--radii-full)}.px_1\.5{padding-inline:var(--spacing-1\.5)}.py_0{padding-block:var(--spacing-0)}.px_2\.5{padding-inline:var(--spacing-2\.5)}.bdr_md{border-radius:var(--radii-md)}.trs_background_80ms{transition:background 80ms}.gap_0\.5{gap:var(--spacing-0\.5)}.gap_2px{gap:2px}.ring_none{outline:var(--borders-none)}.px_3\.5{padding-inline:var(--spacing-3\.5)}.py_2\.5{padding-block:var(--spacing-2\.5)}.bdr_lg{border-radius:var(--radii-lg)}.gap_2\.5{gap:var(--spacing-2\.5)}.px_6{padding-inline:var(--spacing-6)}.py_10{padding-block:var(--spacing-10)}.px_5{padding-inline:var(--spacing-5)}.py_4{padding-block:var(--spacing-4)}.gap_5{gap:var(--spacing-5)}.bd-l_1px_solid{border-left:1px solid}.bd-t_1px_solid{border-top:1px solid}.gap_3{gap:var(--spacing-3)}.td_none{text-decoration:none}.bd-c_accent{border-color:var(--colors-accent)}.my_1\.5{margin-block:var(--spacing-1\.5)}.bd-r_1px_solid{border-right:1px solid}.gap_4{gap:var(--spacing-4)}.px_4{padding-inline:var(--spacing-4)}.bd-c_lineStrong{border-color:var(--colors-line-strong)}.py_6{padding-block:var(--spacing-6)}.d_flex{display:flex}.flex-d_column{flex-direction:column}.ai_center{align-items:center}.flex-sh_0{flex-shrink:0}.fs_11px{font-size:11px}.jc_center{justify-content:center}.bg-i_linear-gradient\(45deg\,_token\(colors\.hover\)_25\%\,_transparent_25\%\)\,_linear-gradient\(-45deg\,_token\(colors\.hover\)_25\%\,_transparent_25\%\)\,_linear-gradient\(45deg\,_transparent_75\%\,_token\(colors\.hover\)_75\%\)\,_linear-gradient\(-45deg\,_transparent_75\%\,_token\(colors\.hover\)_75\%\){background-image:linear-gradient(45deg, var(--colors-hover) 25%, transparent 25%), linear-gradient(-45deg, var(--colors-hover) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, var(--colors-hover) 75%), linear-gradient(-45deg, transparent 75%, var(--colors-hover) 75%)}.bg-s_16px_16px{background-size:16px 16px}.obj-f_contain{object-fit:contain}.lh_1\.6{line-height:1.6}.c_faint{color:var(--colors-faint)}.ta_right{text-align:right}.us_none{-webkit-user-select:none;user-select:none}.white-space_pre-wrap{white-space:pre-wrap}.wb_break-all{word-break:break-all}.white-space_pre{white-space:pre}.c_synKey{color:var(--colors-syn-key)}.c_synString{color:var(--colors-syn-string)}.c_synNumber{color:var(--colors-syn-number)}.c_synBool{color:var(--colors-syn-bool)}.c_synNull{color:var(--colors-syn-null)}.c_synPunct{color:var(--colors-syn-punct)}.ff_mono{font-family:var(--fonts-mono)}.fs_12px{font-size:12px}.lh_1\.65{line-height:1.65}.wb_break-word{word-break:break-word}.cursor_pointer{cursor:pointer}.pos_relative{position:relative}.pos_absolute{position:absolute}.d_inline-flex{display:inline-flex}.font-style_italic{font-style:italic}.c_muted{color:var(--colors-muted)}.va_top{vertical-align:top}.ta_center{text-align:center}.d_grid{display:grid}.grid-tc_18px_76px_70px_1fr_64px{grid-template-columns:18px 76px 70px 1fr 64px}.ta_left{text-align:left}.c_post{color:var(--colors-post)}.c_get{color:var(--colors-get)}.flex-wrap_wrap{flex-wrap:wrap}.tov_ellipsis{text-overflow:ellipsis}.white-space_nowrap{white-space:nowrap}.c_put{color:var(--colors-put)}.c_patch{color:var(--colors-patch)}.c_delete{color:var(--colors-delete)}.c_other{color:var(--colors-other)}.c_ws{color:var(--colors-ws)}.c_sse{color:var(--colors-sse)}.fs_10\.5px{font-size:10.5px}.fw_700{font-weight:700}.ls_0\.02em{letter-spacing:.02em}.d_inline-block{display:inline-block}.c_ok{color:var(--colors-ok)}.c_info{color:var(--colors-info)}.c_warn{color:var(--colors-warn)}.c_bad{color:var(--colors-bad)}.fw_600{font-weight:600}.fw_500{font-weight:500}.lh_18px{line-height:18px}.c_fg{color:var(--colors-fg)}.ai_stretch{align-items:stretch}.scr-bar-w_none{scrollbar-width:none}.fv-num_tabular-nums{font-variant-numeric:tabular-nums}.fs_10px{font-size:10px}.lh_16px{line-height:16px}.fs_20px{font-size:20px}.lh_1\.2{line-height:1.2}.grid-tc_repeat\(auto-fill\,_minmax\(150px\,_1fr\)\){grid-template-columns:repeat(auto-fill,minmax(150px,1fr))}.tt_uppercase{text-transform:uppercase}.ls_0\.06em{letter-spacing:.06em}.ai_flex-start{align-items:flex-start}.fs_14px{font-size:14px}.bd-cl_separate{border-collapse:separate}.bd-sp_0{border-spacing:var(--spacing-0)}.fs_12\.5px{font-size:12.5px}.ls_-0\.01em{letter-spacing:-.01em}.c_lineStrong{color:var(--colors-line-strong)}.c_accent{color:var(--colors-accent)}.cursor_col-resize{cursor:col-resize}.z_2{z-index:2}.op_0\.4{opacity:.4}.flex-sh_1{flex-shrink:1}.pos_sticky{position:sticky}.z_1{z-index:1}.ai_flex-end{align-items:flex-end}.flex-d_row{flex-direction:row}.cursor_row-resize{cursor:row-resize}.d_block{display:block}.grid-tc_150px_1fr_80px{grid-template-columns:150px 1fr 80px}.fs_18px{font-size:18px}.bdr-t_sm{border-top-left-radius:var(--radii-sm);border-top-right-radius:var(--radii-sm)}.grid-tc_1fr{grid-template-columns:1fr}.c_accentFg{color:var(--colors-accent-fg)}.resize_none{resize:none}.fs_13px{font-size:13px}.tab-size_2{tab-size:2}.op_0\.6{opacity:.6}.op_1{opacity:1}.us_all{-webkit-user-select:all;user-select:all}.h_full{height:var(--sizes-full)}.min-h_0{min-height:var(--sizes-0)}.min-w_0{min-width:var(--sizes-0)}.ml_auto{margin-left:auto}.pt_2{padding-top:var(--spacing-2)}.min-h_full{min-height:var(--sizes-full)}.max-w_full{max-width:var(--sizes-full)}.w_full{width:var(--sizes-full)}.w_max-content{width:max-content}.min-w_full{min-width:var(--sizes-full)}.pr_3{padding-right:var(--spacing-3)}.pl_6{padding-left:var(--spacing-6)}.ml_-14px{margin-left:-14px}.pl_14px{padding-left:14px}.left_0{left:var(--spacing-0)}.top_2px{top:2px}.w_32\%{width:32%}.max-w_240px{max-width:240px}.w_46px{width:46px}.w_7px{width:7px}.h_7px{height:7px}.h_28px{height:28px}.w_28px{width:28px}.min-h_34px{min-height:34px}.min-h_38px{min-height:38px}.ov-x_auto{overflow-x:auto}.pl_2{padding-left:var(--spacing-2)}.h_22px{height:22px}.mb_2{margin-bottom:var(--spacing-2)}.mt_1{margin-top:var(--spacing-1)}.mt_1px{margin-top:1px}.mt_0\.5{margin-top:var(--spacing-0\.5)}.mb_1{margin-bottom:var(--spacing-1)}.max-w_440px{max-width:440px}.h_100vh{height:100vh}.bdr-tl_lg{border-top-left-radius:var(--radii-lg)}.h_44px{height:44px}.pr_1{padding-right:var(--spacing-1)}.max-w_180px{max-width:180px}.w_56px{width:56px}.w_64px{width:64px}.pt_1{padding-top:var(--spacing-1)}.pb_2{padding-bottom:var(--spacing-2)}.h_1px{height:1px}.mt_auto{margin-top:auto}.h_30px{height:30px}.top_0{top:var(--spacing-0)}.bottom_0{bottom:var(--spacing-0)}.right_-3px{right:-3px}.w_6px{width:6px}.h_36px{height:36px}.pl_3{padding-left:var(--spacing-3)}.max-w_220px{max-width:220px}.w_20px{width:20px}.h_20px{height:20px}.h_24px{height:24px}.h_26px{height:26px}.pr_2{padding-right:var(--spacing-2)}.w_16px{width:16px}.h_16px{height:16px}.pb_3{padding-bottom:var(--spacing-3)}.pt_1\.5{padding-top:var(--spacing-1\.5)}.pb_0\.5{padding-bottom:var(--spacing-0\.5)}.pl_1{padding-left:var(--spacing-1)}.pl_9{padding-left:var(--spacing-9)}.pl_5{padding-left:var(--spacing-5)}.pl_12{padding-left:var(--spacing-12)}.pl_10{padding-left:var(--spacing-10)}.h_auto{height:auto}.pb_1{padding-bottom:var(--spacing-1)}.pt_1px{padding-top:1px}.w_1px{width:1px}.mt_3{margin-top:var(--spacing-3)}.h_10px{height:10px}.mt_2{margin-top:var(--spacing-2)}.pt_4{padding-top:var(--spacing-4)}.h_88px{height:88px}.max-w_22px{max-width:22px}.min-w_4px{min-width:4px}.w_8px{width:8px}.h_8px{height:8px}.max-w_0{max-width:var(--sizes-0)}.mt_-2{margin-top:calc(var(--spacing-2) * -1)}.max-w_260px{max-width:260px}.h_40px{height:40px}.w_260px{width:260px}.h_32px{height:32px}.w_auto{width:auto}.pt_3{padding-top:var(--spacing-3)}.pb_2\.5{padding-bottom:var(--spacing-2\.5)}.pt_2\.5{padding-top:var(--spacing-2\.5)}.w_280px{width:280px}.min-w_2px{min-width:2px}.top_-1px{top:-1px}.w_2px{width:2px}.h_14px{height:14px}.mt_2\.5{margin-top:var(--spacing-2\.5)}.h_3px{height:3px}.\[\&\[aria-selected\=true\]\]\:bg_selected[aria-selected=true]{background:var(--colors-selected)}.\[\&\[aria-pressed\=true\]\]\:bg_accentSoft[aria-pressed=true]{background:var(--colors-accent-soft)}.\[\&\[aria-pressed\=true\]\]\:bg_raised[aria-pressed=true]{background:var(--colors-raised)}.\[\&_th\]\:bg_chrome th{background:var(--colors-chrome)}.\[\&\[aria-pressed\=true\]\]\:bg_okSoft[aria-pressed=true]{background:var(--colors-ok-soft)}.\[\&\[data-active\=true\]\]\:bg_hover[data-active=true]{background:var(--colors-hover)}.\[\&\[aria-selected\=true\]\]\:bg_canvas[aria-selected=true]{background:var(--colors-canvas)}.\[\&\[data-active\=true\]\]\:bg_selected[data-active=true]{background:var(--colors-selected)}.\[\&_th\]\:px_3 th{padding-inline:var(--spacing-3)}.\[\&_th\]\:py_1\.5 th{padding-block:var(--spacing-1\.5)}.\[\&_th\]\:bd-b_1px_solid th{border-bottom:1px solid}.\[\&_th\]\:bd-c_line th{border-color:var(--colors-line)}.\[\&_td\]\:px_3 td{padding-inline:var(--spacing-3)}.\[\&_td\]\:py_1\.5 td{padding-block:var(--spacing-1\.5)}.\[\&_td\]\:bd-b_1px_solid td{border-bottom:1px solid}.\[\&_td\]\:bd-c_line td{border-color:var(--colors-line)}.\[\&\[aria-pressed\=true\]\]\:bd-c_ok[aria-pressed=true]{border-color:var(--colors-ok)}.\[\&\[aria-pressed\=true\]\]\:bd-c_accent[aria-pressed=true]{border-color:var(--colors-accent)}.last\:bd-b_none:last-child{border-bottom:var(--borders-none)}.disabled\:op_0\.45:is(:disabled,[disabled],[data-disabled],[aria-disabled=true]){opacity:.45}.disabled\:cursor_default:is(:disabled,[disabled],[data-disabled],[aria-disabled=true]){cursor:default}.disabled\:op_0\.35:is(:disabled,[disabled],[data-disabled],[aria-disabled=true]){opacity:.35}.\[\&\[aria-pressed\=true\]\]\:c_accent[aria-pressed=true]{color:var(--colors-accent)}.\[\&\[aria-selected\=true\]\]\:c_fg[aria-selected=true],.\[\&\[aria-pressed\=true\]\]\:c_fg[aria-pressed=true]{color:var(--colors-fg)}.\[\&\[aria-pressed\=true\]\]\:bx-sh_0_1px_2px_rgba\(0\,0\,0\,0\.08\)[aria-pressed=true]{box-shadow:0 1px 2px #00000014}.\[\&\:\:placeholder\]\:c_faint::placeholder{color:var(--colors-faint)}.\[\&\:\:-webkit-search-cancel-button\]\:d_none::-webkit-search-cancel-button{display:none}.\[\&_th\]\:pos_sticky th{position:sticky}.\[\&_th\]\:z_1 th{z-index:1}.\[\&_th\]\:ta_left th{text-align:left}.\[\&_th\]\:fw_500 th{font-weight:500}.\[\&_th\]\:fs_11px th{font-size:11px}.\[\&_th\]\:c_muted th{color:var(--colors-muted)}.\[\&_th\]\:white-space_nowrap th{white-space:nowrap}.\[\&_td\]\:va_middle td{vertical-align:middle}.\[\&_tbody_tr\]\:cursor_default tbody tr{cursor:default}.\[\&_tbody_tr\[data-link\]\]\:cursor_pointer tbody tr[data-link]{cursor:pointer}.\[\&_td\.num\,_\&_th\.num\]\:ta_right td.num,.\[\&_td\.num\,_\&_th\.num\]\:ta_right th.num{text-align:right}.\[\&_td\.num\,_\&_th\.num\]\:fv-num_tabular-nums td.num,.\[\&_td\.num\,_\&_th\.num\]\:fv-num_tabular-nums th.num{font-variant-numeric:tabular-nums}.\[\&_td\.num\,_\&_th\.num\]\:white-space_nowrap td.num,.\[\&_td\.num\,_\&_th\.num\]\:white-space_nowrap th.num{white-space:nowrap}.\[\&\[aria-pressed\=true\]\]\:c_ok[aria-pressed=true]{color:var(--colors-ok)}.\[\&\[data-active\=true\]\]\:c_fg[data-active=true]{color:var(--colors-fg)}.\[\&\[data-active\=true\]_svg\]\:c_accent[data-active=true] svg{color:var(--colors-accent)}.\[\&\[data-preview\=true\]_\.tab-title\]\:font-style_italic[data-preview=true] .tab-title{font-style:italic}.\[\&_\.tab-close\]\:op_0 .tab-close{opacity:0}.after\:content_\"\":after{content:""}.after\:pos_absolute:after{position:absolute}.\[\&_td\]\:ff_mono td{font-family:var(--fonts-mono)}.\[\&_td\]\:fs_12px td,.\[\&_\>_span\]\:fs_12px>span{font-size:12px}.\[\&_th\]\:top_0 th,.after\:top_0:after{top:var(--spacing-0)}.after\:bottom_0:after{bottom:var(--spacing-0)}.after\:left_-3px:after{left:-3px}.after\:right_-3px:after{right:-3px}.after\:left_0:after{left:var(--spacing-0)}.after\:right_0:after{right:var(--spacing-0)}.after\:top_-3px:after{top:-3px}.after\:bottom_-3px:after{bottom:-3px}.\[\&_td\]\:max-w_420px td{max-width:420px}.focusWithin\:bd-c_accent:focus-within{border-color:var(--colors-accent)}.focusWithin\:c_muted:focus-within{color:var(--colors-muted)}.focusVisible\:ring_2px_solid:is(:focus-visible,[data-focus-visible]){outline:2px solid}.focusVisible\:ring-c_accent:is(:focus-visible,[data-focus-visible]){outline-color:var(--colors-accent)}.focusVisible\:ring-o_1px:is(:focus-visible,[data-focus-visible]){outline-offset:1px}.hover\:bg_hover:is(:hover,[data-hover]),.\[\&_tbody_tr\:hover_td\]\:bg_hover tbody tr:hover td{background:var(--colors-hover)}.hover\:bg_accent:is(:hover,[data-hover]){background:var(--colors-accent)}.hover\:c_fg:is(:hover,[data-hover]){color:var(--colors-fg)}.hover\:op_0\.4:is(:hover,[data-hover]){opacity:.4}.\[\&\:hover_\.tab-close\,_\&\[aria-selected\=true\]_\.tab-close\]\:op_1:hover .tab-close,.\[\&\:hover_\.tab-close\,_\&\[aria-selected\=true\]_\.tab-close\]\:op_1[aria-selected=true] .tab-close{opacity:1}.hover\:op_0\.9:is(:hover,[data-hover]){opacity:.9}.hover\:c_accent:is(:hover,[data-hover]){color:var(--colors-accent)}.disabled\:hover\:bg_raised:is(:disabled,[disabled],[data-disabled],[aria-disabled=true]):is(:hover,[data-hover]){background:var(--colors-raised)}.disabled\:hover\:bg_transparent:is(:disabled,[disabled],[data-disabled],[aria-disabled=true]):is(:hover,[data-hover]){background:var(--colors-transparent)}.\[\&\[aria-selected\=true\]\]\:after\:bg_accent[aria-selected=true]:after,.\[\&\[aria-selected\=true\]\]\:before\:bg_accent[aria-selected=true]:before{background:var(--colors-accent)}.\[\&\[aria-selected\=true\]\]\:after\:bdr_full[aria-selected=true]:after{border-radius:var(--radii-full)}.\[\&\[aria-selected\=true\]\]\:after\:content_\"\"[aria-selected=true]:after{content:""}.\[\&\[aria-selected\=true\]\]\:after\:pos_absolute[aria-selected=true]:after{position:absolute}.\[\&\[aria-selected\=true\]\]\:before\:content_\"\"[aria-selected=true]:before{content:""}.\[\&\[aria-selected\=true\]\]\:before\:pos_absolute[aria-selected=true]:before{position:absolute}.\[\&\[aria-selected\=true\]\]\:after\:left_2[aria-selected=true]:after{left:var(--spacing-2)}.\[\&\[aria-selected\=true\]\]\:after\:right_2[aria-selected=true]:after{right:var(--spacing-2)}.\[\&\[aria-selected\=true\]\]\:after\:bottom_-1px[aria-selected=true]:after{bottom:-1px}.\[\&\[aria-selected\=true\]\]\:after\:h_2px[aria-selected=true]:after{height:2px}.\[\&\[aria-selected\=true\]\]\:before\:left_0[aria-selected=true]:before{left:var(--spacing-0)}.\[\&\[aria-selected\=true\]\]\:before\:right_0[aria-selected=true]:before{right:var(--spacing-0)}.\[\&\[aria-selected\=true\]\]\:before\:top_0[aria-selected=true]:before{top:var(--spacing-0)}.\[\&\[aria-selected\=true\]\]\:before\:h_2px[aria-selected=true]:before{height:2px}@media screen and (width>=64rem){.lg\:grid-tc_1fr_1fr{grid-template-columns:1fr 1fr}}@media screen and (width>=80rem){.xl\:grid-tc_3fr_2fr{grid-template-columns:3fr 2fr}}}
|