@c9up/ream 0.2.29 → 0.2.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 (220) hide show
  1. package/README.md +5 -6
  2. package/dist/Codemods.d.ts +8 -0
  3. package/dist/Codemods.d.ts.map +1 -1
  4. package/dist/Codemods.js +29 -1
  5. package/dist/Codemods.js.map +1 -1
  6. package/dist/HttpKernel.d.ts.map +1 -1
  7. package/dist/HttpKernel.js +17 -5
  8. package/dist/HttpKernel.js.map +1 -1
  9. package/dist/Ignitor.d.ts +5 -0
  10. package/dist/Ignitor.d.ts.map +1 -1
  11. package/dist/Ignitor.js +12 -1
  12. package/dist/Ignitor.js.map +1 -1
  13. package/dist/bodyparser/BodyParserMiddleware.d.ts +4 -4
  14. package/dist/bodyparser/BodyParserMiddleware.d.ts.map +1 -1
  15. package/dist/bodyparser/BodyParserMiddleware.js +38 -11
  16. package/dist/bodyparser/BodyParserMiddleware.js.map +1 -1
  17. package/dist/bodyparser/MultipartFile.d.ts +21 -15
  18. package/dist/bodyparser/MultipartFile.d.ts.map +1 -1
  19. package/dist/bodyparser/MultipartFile.js +40 -58
  20. package/dist/bodyparser/MultipartFile.js.map +1 -1
  21. package/dist/bodyparser/parseSize.d.ts +7 -4
  22. package/dist/bodyparser/parseSize.d.ts.map +1 -1
  23. package/dist/bodyparser/parseSize.js +12 -17
  24. package/dist/bodyparser/parseSize.js.map +1 -1
  25. package/dist/bodyparser/qsParse.d.ts +10 -0
  26. package/dist/bodyparser/qsParse.d.ts.map +1 -1
  27. package/dist/bodyparser/qsParse.js +27 -12
  28. package/dist/bodyparser/qsParse.js.map +1 -1
  29. package/dist/console/prompts.d.ts.map +1 -1
  30. package/dist/console/prompts.js +3 -1
  31. package/dist/console/prompts.js.map +1 -1
  32. package/dist/container/Container.d.ts.map +1 -1
  33. package/dist/container/Container.js +61 -71
  34. package/dist/container/Container.js.map +1 -1
  35. package/dist/events/Emitter.d.ts +12 -0
  36. package/dist/events/Emitter.d.ts.map +1 -1
  37. package/dist/events/Emitter.js +36 -9
  38. package/dist/events/Emitter.js.map +1 -1
  39. package/dist/events/helix/helpers.d.ts.map +1 -1
  40. package/dist/events/helix/helpers.js +19 -9
  41. package/dist/events/helix/helpers.js.map +1 -1
  42. package/dist/graphql/GraphQLEngine.d.ts +8 -0
  43. package/dist/graphql/GraphQLEngine.d.ts.map +1 -1
  44. package/dist/graphql/GraphQLEngine.js +77 -11
  45. package/dist/graphql/GraphQLEngine.js.map +1 -1
  46. package/dist/helpers/MessageBuilder.d.ts +4 -2
  47. package/dist/helpers/MessageBuilder.d.ts.map +1 -1
  48. package/dist/helpers/MessageBuilder.js +4 -2
  49. package/dist/helpers/MessageBuilder.js.map +1 -1
  50. package/dist/helpers/errors.d.ts +11 -0
  51. package/dist/helpers/errors.d.ts.map +1 -0
  52. package/dist/helpers/errors.js +17 -0
  53. package/dist/helpers/errors.js.map +1 -0
  54. package/dist/helpers/napi-loader.d.ts.map +1 -1
  55. package/dist/helpers/napi-loader.js +3 -2
  56. package/dist/helpers/napi-loader.js.map +1 -1
  57. package/dist/http/HttpContext.d.ts +20 -2
  58. package/dist/http/HttpContext.d.ts.map +1 -1
  59. package/dist/http/HttpContext.js +10 -4
  60. package/dist/http/HttpContext.js.map +1 -1
  61. package/dist/http/RedirectBuilder.d.ts.map +1 -1
  62. package/dist/http/RedirectBuilder.js +4 -0
  63. package/dist/http/RedirectBuilder.js.map +1 -1
  64. package/dist/http/Request.d.ts.map +1 -1
  65. package/dist/http/Request.js +15 -29
  66. package/dist/http/Request.js.map +1 -1
  67. package/dist/http/Response.d.ts +7 -4
  68. package/dist/http/Response.d.ts.map +1 -1
  69. package/dist/http/Response.js +14 -6
  70. package/dist/http/Response.js.map +1 -1
  71. package/dist/http/permissions.d.ts +14 -8
  72. package/dist/http/permissions.d.ts.map +1 -1
  73. package/dist/http/permissions.js +26 -16
  74. package/dist/http/permissions.js.map +1 -1
  75. package/dist/index.d.ts +2 -2
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.js +1 -1
  78. package/dist/index.js.map +1 -1
  79. package/dist/middleware/Pipeline.js +1 -1
  80. package/dist/middleware/Pipeline.js.map +1 -1
  81. package/dist/native/generated.d.ts +16 -30
  82. package/dist/native/generated.d.ts.map +1 -1
  83. package/dist/profiler/Profiler.d.ts.map +1 -1
  84. package/dist/profiler/Profiler.js +4 -1
  85. package/dist/profiler/Profiler.js.map +1 -1
  86. package/dist/profiler/client.generated.d.ts +5 -0
  87. package/dist/profiler/client.generated.d.ts.map +1 -0
  88. package/dist/profiler/client.generated.js +6 -0
  89. package/dist/profiler/client.generated.js.map +1 -0
  90. package/dist/profiler/collectors.d.ts +92 -13
  91. package/dist/profiler/collectors.d.ts.map +1 -1
  92. package/dist/profiler/collectors.js +106 -19
  93. package/dist/profiler/collectors.js.map +1 -1
  94. package/dist/profiler/endpoint.d.ts +2 -1
  95. package/dist/profiler/endpoint.d.ts.map +1 -1
  96. package/dist/profiler/endpoint.js +25 -1
  97. package/dist/profiler/endpoint.js.map +1 -1
  98. package/dist/profiler/index.d.ts +8 -4
  99. package/dist/profiler/index.d.ts.map +1 -1
  100. package/dist/profiler/index.js +11 -4
  101. package/dist/profiler/index.js.map +1 -1
  102. package/dist/profiler/middleware.d.ts.map +1 -1
  103. package/dist/profiler/middleware.js +76 -10
  104. package/dist/profiler/middleware.js.map +1 -1
  105. package/dist/profiler/preview.d.ts +17 -0
  106. package/dist/profiler/preview.d.ts.map +1 -0
  107. package/dist/profiler/preview.js +100 -0
  108. package/dist/profiler/preview.js.map +1 -0
  109. package/dist/profiler/toolbar.d.ts +15 -23
  110. package/dist/profiler/toolbar.d.ts.map +1 -1
  111. package/dist/profiler/toolbar.js +25 -91
  112. package/dist/profiler/toolbar.js.map +1 -1
  113. package/dist/profiler/types.d.ts +6 -1
  114. package/dist/profiler/types.d.ts.map +1 -1
  115. package/dist/router/Router.d.ts +6 -0
  116. package/dist/router/Router.d.ts.map +1 -1
  117. package/dist/router/Router.js +115 -12
  118. package/dist/router/Router.js.map +1 -1
  119. package/dist/rpc/RpcRouter.js +3 -3
  120. package/dist/rpc/RpcRouter.js.map +1 -1
  121. package/dist/scheduler/Scheduler.js +1 -1
  122. package/dist/scheduler/Scheduler.js.map +1 -1
  123. package/dist/security/CookieSigner.d.ts.map +1 -1
  124. package/dist/security/CookieSigner.js +15 -5
  125. package/dist/security/CookieSigner.js.map +1 -1
  126. package/dist/security/SignedUrl.d.ts.map +1 -1
  127. package/dist/security/SignedUrl.js +10 -18
  128. package/dist/security/SignedUrl.js.map +1 -1
  129. package/dist/server/Server.d.ts +4 -1
  130. package/dist/server/Server.d.ts.map +1 -1
  131. package/dist/server/Server.js.map +1 -1
  132. package/dist/server/nativeLimits.d.ts +9 -1
  133. package/dist/server/nativeLimits.d.ts.map +1 -1
  134. package/dist/server/nativeLimits.js +8 -0
  135. package/dist/server/nativeLimits.js.map +1 -1
  136. package/dist/session/Session.d.ts.map +1 -1
  137. package/dist/session/Session.js +13 -4
  138. package/dist/session/Session.js.map +1 -1
  139. package/dist/session/drivers/MemoryDriver.d.ts.map +1 -1
  140. package/dist/session/drivers/MemoryDriver.js +14 -2
  141. package/dist/session/drivers/MemoryDriver.js.map +1 -1
  142. package/dist/storage/StaticMiddleware.d.ts.map +1 -1
  143. package/dist/storage/StaticMiddleware.js +20 -9
  144. package/dist/storage/StaticMiddleware.js.map +1 -1
  145. package/dist/testing/ApiResponse.d.ts.map +1 -1
  146. package/dist/testing/ApiResponse.js +7 -1
  147. package/dist/testing/ApiResponse.js.map +1 -1
  148. package/dist/testing/TestClient.d.ts.map +1 -1
  149. package/dist/testing/TestClient.js +16 -4
  150. package/dist/testing/TestClient.js.map +1 -1
  151. package/dist/utils/Macroable.d.ts +1 -1
  152. package/dist/utils/Macroable.js +2 -2
  153. package/dist/utils/Macroable.js.map +1 -1
  154. package/events.darwin-arm64.node +0 -0
  155. package/events.darwin-x64.node +0 -0
  156. package/events.linux-arm64-gnu.node +0 -0
  157. package/events.linux-x64-gnu.node +0 -0
  158. package/events.win32-x64-msvc.node +0 -0
  159. package/index.darwin-arm64.node +0 -0
  160. package/index.darwin-x64.node +0 -0
  161. package/index.linux-arm64-gnu.node +0 -0
  162. package/index.linux-x64-gnu.node +0 -0
  163. package/index.win32-x64-msvc.node +0 -0
  164. package/package.json +1 -2
  165. package/scheduler.darwin-arm64.node +0 -0
  166. package/scheduler.darwin-x64.node +0 -0
  167. package/scheduler.linux-arm64-gnu.node +0 -0
  168. package/scheduler.linux-x64-gnu.node +0 -0
  169. package/scheduler.win32-x64-msvc.node +0 -0
  170. package/src/Codemods.ts +49 -3
  171. package/src/HttpKernel.ts +18 -7
  172. package/src/Ignitor.ts +21 -4
  173. package/src/bodyparser/BodyParserMiddleware.ts +42 -16
  174. package/src/bodyparser/MultipartFile.ts +46 -67
  175. package/src/bodyparser/parseSize.ts +17 -17
  176. package/src/bodyparser/qsParse.ts +28 -13
  177. package/src/console/prompts.ts +3 -1
  178. package/src/container/Container.ts +97 -81
  179. package/src/events/Emitter.ts +37 -10
  180. package/src/events/helix/helpers.ts +24 -19
  181. package/src/graphql/GraphQLEngine.ts +89 -13
  182. package/src/helpers/MessageBuilder.ts +4 -2
  183. package/src/helpers/errors.ts +16 -0
  184. package/src/helpers/napi-loader.ts +3 -2
  185. package/src/http/HttpContext.ts +20 -4
  186. package/src/http/RedirectBuilder.ts +3 -0
  187. package/src/http/Request.ts +15 -29
  188. package/src/http/Response.ts +15 -7
  189. package/src/http/permissions.ts +31 -15
  190. package/src/index.ts +2 -1
  191. package/src/middleware/Pipeline.ts +1 -1
  192. package/src/native/generated.ts +18 -42
  193. package/src/profiler/Profiler.ts +4 -1
  194. package/src/profiler/client/toolbar.css +595 -0
  195. package/src/profiler/client/toolbar.js +1299 -0
  196. package/src/profiler/client.generated.ts +7 -0
  197. package/src/profiler/collectors.ts +156 -19
  198. package/src/profiler/endpoint.ts +27 -1
  199. package/src/profiler/index.ts +17 -3
  200. package/src/profiler/middleware.ts +74 -9
  201. package/src/profiler/preview.ts +104 -0
  202. package/src/profiler/toolbar.ts +28 -91
  203. package/src/profiler/types.ts +6 -1
  204. package/src/router/Router.ts +136 -13
  205. package/src/rpc/RpcRouter.ts +4 -4
  206. package/src/scheduler/Scheduler.ts +1 -1
  207. package/src/security/CookieSigner.ts +13 -5
  208. package/src/security/SignedUrl.ts +12 -16
  209. package/src/server/Server.ts +4 -1
  210. package/src/server/nativeLimits.ts +18 -1
  211. package/src/session/Session.ts +13 -4
  212. package/src/session/drivers/MemoryDriver.ts +15 -2
  213. package/src/storage/StaticMiddleware.ts +18 -9
  214. package/src/testing/ApiResponse.ts +7 -1
  215. package/src/testing/TestClient.ts +14 -5
  216. package/src/utils/Macroable.ts +2 -2
  217. package/scripts/build-napi-types.mjs +0 -69
  218. package/scripts/copy-napi.mjs +0 -121
  219. package/scripts/generate-mime.mjs +0 -119
  220. package/scripts/generate-napi-types.mjs +0 -187
package/src/index.ts CHANGED
@@ -289,6 +289,7 @@ export {
289
289
  createCodemods,
290
290
  type EnvValidationNode,
291
291
  type GeneratedStub,
292
+ type MiddlewarePosition,
292
293
  type PreloadEnvironment,
293
294
  type StubState,
294
295
  } from './Codemods.js'
@@ -413,4 +414,4 @@ export {
413
414
  StatsTracker,
414
415
  } from './scheduler/index.js'
415
416
 
416
- export const VERSION = '0.2.29'
417
+ export const VERSION = '0.2.30'
@@ -245,7 +245,7 @@ function createGuardMiddleware(
245
245
 
246
246
  // A token-authenticated request also needs the token to allow each one.
247
247
  if (permissions && permissions.length > 0) {
248
- if (!holdsPermissions(ctx.auth, permissions)) {
248
+ if (!(await holdsPermissions(ctx.auth, permissions))) {
249
249
  throw new E_FORBIDDEN('Insufficient permissions', permissions)
250
250
  }
251
251
  }
@@ -113,7 +113,20 @@ export interface NapiBodyLimits {
113
113
  json?: NapiBodyLimit
114
114
  form?: NapiBodyLimit
115
115
  raw?: NapiBodyLimit
116
- multipart?: NapiBodyLimit
116
+ multipart?: NapiMultipartLimit
117
+ }
118
+
119
+ /**
120
+ * The multipart section: its size limit and types, and how many fields
121
+ * and files a body may carry (default 1000 each), enforced while the body
122
+ * is parsed.
123
+ */
124
+
125
+ export interface NapiMultipartLimit {
126
+ limit?: number
127
+ types?: Array<string>
128
+ maxFields?: number
129
+ maxFiles?: number
117
130
  }
118
131
 
119
132
  /**
@@ -168,9 +181,10 @@ export declare class EventBus {
168
181
 
169
182
  export declare class HyperServer {
170
183
  /**
171
- * `host` is the bind address: an IPv4 literal (`0.0.0.0` to accept from
172
- * every interface) or the `localhost` alias. Omitted → loopback only,
173
- * the safe default for a dev machine.
184
+ * `host` is the bind address: an IPv4 or IPv6 literal (`0.0.0.0` or `::`
185
+ * to accept from every interface, a bracketed `[::1]` too) or the
186
+ * `localhost` alias. Omitted → loopback only, the safe default for a dev
187
+ * machine.
174
188
  */
175
189
  constructor(port?: number | undefined | null, host?: string | undefined | null)
176
190
  /**
@@ -336,44 +350,6 @@ export declare class RustScheduler {
336
350
  nextRun(name: string): number | null
337
351
  }
338
352
 
339
- /**
340
- * Sign a JWT payload with HMAC-SHA256 (Rust-native).
341
- * Returns the complete JWT token string.
342
- */
343
-
344
- export declare function jwtSign(payload: string, secret: string): string
345
-
346
- /**
347
- * Verify a JWT token and return the decoded payload JSON string.
348
- * Validates signature (constant-time), exp, and nbf claims.
349
- */
350
-
351
- export declare function jwtVerify(token: string, secret: string): string
352
-
353
- /**
354
- * Hash a password with Argon2id (Rust-native).
355
- * Returns the PHC-formatted hash string.
356
- */
357
-
358
- export declare function argon2Hash(password: string): string
359
-
360
- /** Verify a password against an Argon2id hash. */
361
-
362
- export declare function argon2Verify(password: string, hash: string): boolean
363
-
364
- /**
365
- * Hash a password with bcrypt (Rust-native).
366
- * `rounds` defaults to 12 when not supplied — matches the previous
367
- * warden-engine default and the OWASP-recommended cost floor enforced
368
- * by `sigil-engine`.
369
- */
370
-
371
- export declare function bcryptHash(password: string, rounds?: number | undefined | null): string
372
-
373
- /** Verify a password against a bcrypt hash. */
374
-
375
- export declare function bcryptVerify(password: string, hash: string): boolean
376
-
377
353
  /** Constant-time string comparison. */
378
354
 
379
355
  export declare function constantTimeEq(a: string, b: string): boolean
@@ -68,7 +68,10 @@ export class Profiler {
68
68
  const token = newToken()
69
69
  const startedAt = Date.now()
70
70
  const started = performance.now()
71
- const active: ActiveProfile = { scope: { token, startedAt }, bags: new Map() }
71
+ const active: ActiveProfile = {
72
+ scope: { token, startedAt, elapsed: () => performance.now() - started },
73
+ bags: new Map(),
74
+ }
72
75
 
73
76
  for (const collector of this.#collectors) {
74
77
  // A collector that throws while starting must not fail the request it was
@@ -0,0 +1,595 @@
1
+ /*
2
+ * The debug toolbar's stylesheet. Loaded into the bar's shadow root from
3
+ * /__ream/profiler/_assets/toolbar.css: a same-origin stylesheet passes a
4
+ * `style-src 'self'` policy, where an inline one would be dropped.
5
+ */
6
+
7
+ :host {
8
+ all: initial;
9
+ }
10
+
11
+ * {
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ .rp {
16
+ --bg: #17191d;
17
+ --bg-2: #1f2228;
18
+ --bg-3: #272b33;
19
+ --line: #2f343d;
20
+ --text: #e6e8eb;
21
+ --muted: #8b939e;
22
+ --accent: #6cb6ff;
23
+ --ok: #3fb950;
24
+ --warn: #d29922;
25
+ --bad: #f85149;
26
+ --bar: 34px;
27
+ position: fixed;
28
+ left: 0;
29
+ right: 0;
30
+ bottom: 0;
31
+ z-index: 2147483000;
32
+ display: flex;
33
+ flex-direction: column;
34
+ color: var(--text);
35
+ font:
36
+ 12px / 1.45 ui-sans-serif,
37
+ system-ui,
38
+ -apple-system,
39
+ "Segoe UI",
40
+ sans-serif;
41
+ text-align: left;
42
+ }
43
+
44
+ .rp[data-closed] {
45
+ left: auto;
46
+ right: 8px;
47
+ bottom: 8px;
48
+ }
49
+
50
+ .mono,
51
+ .sql,
52
+ pre,
53
+ code {
54
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
55
+ font-size: 12px;
56
+ }
57
+
58
+ button {
59
+ font: inherit;
60
+ color: inherit;
61
+ background: none;
62
+ border: 0;
63
+ cursor: pointer;
64
+ padding: 0;
65
+ }
66
+
67
+ /* The closed state: one small button in the corner. */
68
+ .restore {
69
+ display: none;
70
+ width: 34px;
71
+ height: 34px;
72
+ border-radius: 8px;
73
+ background: var(--bg);
74
+ border: 1px solid var(--line);
75
+ color: var(--accent);
76
+ font-weight: 700;
77
+ box-shadow: 0 2px 10px rgb(0 0 0 / 0.4);
78
+ }
79
+
80
+ .rp[data-closed] .restore {
81
+ display: block;
82
+ }
83
+
84
+ /* ── The bar ─────────────────────────────────────────────── */
85
+
86
+ .bar {
87
+ display: flex;
88
+ align-items: stretch;
89
+ height: var(--bar);
90
+ background: var(--bg);
91
+ border-top: 1px solid var(--line);
92
+ box-shadow: 0 -2px 10px rgb(0 0 0 / 0.35);
93
+ }
94
+
95
+ .item {
96
+ position: relative;
97
+ display: flex;
98
+ align-items: center;
99
+ gap: 6px;
100
+ padding: 0 11px;
101
+ border-right: 1px solid var(--line);
102
+ white-space: nowrap;
103
+ cursor: pointer;
104
+ }
105
+
106
+ .item:hover,
107
+ .item:focus-visible,
108
+ .item[data-active] {
109
+ background: var(--bg-2);
110
+ outline: none;
111
+ }
112
+
113
+ .item .label {
114
+ color: var(--muted);
115
+ }
116
+
117
+ .item .value {
118
+ font-weight: 600;
119
+ }
120
+
121
+ .item[data-tone="ok"] .value {
122
+ color: var(--ok);
123
+ }
124
+
125
+ .item[data-tone="warn"] {
126
+ box-shadow: inset 0 -3px 0 var(--warn);
127
+ }
128
+
129
+ .item[data-tone="warn"] .value {
130
+ color: var(--warn);
131
+ }
132
+
133
+ .item[data-tone="bad"] {
134
+ box-shadow: inset 0 -3px 0 var(--bad);
135
+ }
136
+
137
+ .item[data-tone="bad"] .value {
138
+ color: var(--bad);
139
+ }
140
+
141
+ .status {
142
+ display: inline-block;
143
+ min-width: 34px;
144
+ padding: 2px 6px;
145
+ border-radius: 4px;
146
+ text-align: center;
147
+ font-weight: 700;
148
+ color: #fff;
149
+ background: #238636;
150
+ }
151
+
152
+ .status[data-tone="warn"] {
153
+ background: #9e6a03;
154
+ }
155
+
156
+ .status[data-tone="bad"] {
157
+ background: #b62324;
158
+ }
159
+
160
+ .spacer {
161
+ flex: 1;
162
+ min-width: 0;
163
+ display: flex;
164
+ align-items: center;
165
+ padding: 0 10px;
166
+ color: var(--muted);
167
+ overflow: hidden;
168
+ text-overflow: ellipsis;
169
+ white-space: nowrap;
170
+ }
171
+
172
+ .viewing {
173
+ margin-left: 8px;
174
+ padding: 1px 8px;
175
+ border-radius: 999px;
176
+ background: #1f3a5f;
177
+ color: var(--accent);
178
+ }
179
+
180
+ .tool {
181
+ display: flex;
182
+ align-items: center;
183
+ justify-content: center;
184
+ width: 34px;
185
+ border-left: 1px solid var(--line);
186
+ color: var(--muted);
187
+ }
188
+
189
+ .tool:hover {
190
+ color: var(--text);
191
+ background: var(--bg-2);
192
+ }
193
+
194
+ a {
195
+ color: var(--accent);
196
+ text-decoration: none;
197
+ }
198
+
199
+ a:hover {
200
+ text-decoration: underline;
201
+ }
202
+
203
+ /* ── Hover summaries ─────────────────────────────────────── */
204
+
205
+ .info {
206
+ display: none;
207
+ position: absolute;
208
+ bottom: calc(100% + 1px);
209
+ left: 0;
210
+ min-width: 240px;
211
+ max-width: 520px;
212
+ max-height: 420px;
213
+ overflow: auto;
214
+ padding: 8px 10px;
215
+ background: var(--bg-2);
216
+ border: 1px solid var(--line);
217
+ border-radius: 6px 6px 0 0;
218
+ box-shadow: 0 -4px 14px rgb(0 0 0 / 0.4);
219
+ cursor: default;
220
+ white-space: normal;
221
+ }
222
+
223
+ .item:hover .info,
224
+ .item:focus-within .info {
225
+ display: block;
226
+ }
227
+
228
+ .rp[data-open] .item .info {
229
+ display: none;
230
+ }
231
+
232
+ .row {
233
+ display: flex;
234
+ gap: 12px;
235
+ padding: 3px 0;
236
+ }
237
+
238
+ .row b {
239
+ flex: 0 0 130px;
240
+ color: var(--muted);
241
+ font-weight: 500;
242
+ }
243
+
244
+ .row span {
245
+ overflow-wrap: anywhere;
246
+ }
247
+
248
+ /* ── The panel ───────────────────────────────────────────── */
249
+
250
+ .panel {
251
+ display: none;
252
+ flex-direction: column;
253
+ background: var(--bg);
254
+ border-top: 1px solid var(--line);
255
+ box-shadow: 0 -4px 16px rgb(0 0 0 / 0.4);
256
+ }
257
+
258
+ .rp[data-open] .panel {
259
+ display: flex;
260
+ }
261
+
262
+ .rp[data-closed] .bar,
263
+ .rp[data-closed] .panel {
264
+ display: none;
265
+ }
266
+
267
+ .grip {
268
+ height: 5px;
269
+ cursor: row-resize;
270
+ background: var(--bg-3);
271
+ }
272
+
273
+ .grip:hover {
274
+ background: var(--accent);
275
+ }
276
+
277
+ .tabs {
278
+ display: flex;
279
+ gap: 2px;
280
+ padding: 0 6px;
281
+ border-bottom: 1px solid var(--line);
282
+ background: var(--bg-2);
283
+ overflow-x: auto;
284
+ }
285
+
286
+ .tab {
287
+ padding: 7px 12px;
288
+ color: var(--muted);
289
+ border-bottom: 2px solid transparent;
290
+ white-space: nowrap;
291
+ }
292
+
293
+ .tab:hover {
294
+ color: var(--text);
295
+ }
296
+
297
+ .tab[data-active] {
298
+ color: var(--text);
299
+ border-bottom-color: var(--accent);
300
+ }
301
+
302
+ .tab .count {
303
+ margin-left: 6px;
304
+ padding: 0 6px;
305
+ border-radius: 999px;
306
+ background: var(--bg-3);
307
+ color: var(--text);
308
+ font-size: 11px;
309
+ }
310
+
311
+ .tab .count[data-tone="warn"] {
312
+ background: #5c4106;
313
+ }
314
+
315
+ .tab .count[data-tone="bad"] {
316
+ background: #6e1a1b;
317
+ }
318
+
319
+ .body {
320
+ flex: 1;
321
+ overflow: auto;
322
+ padding: 10px 12px 14px;
323
+ }
324
+
325
+ .toolbar {
326
+ display: flex;
327
+ flex-wrap: wrap;
328
+ align-items: center;
329
+ gap: 8px;
330
+ margin-bottom: 10px;
331
+ color: var(--muted);
332
+ }
333
+
334
+ .toolbar input[type="search"] {
335
+ min-width: 220px;
336
+ padding: 4px 8px;
337
+ border: 1px solid var(--line);
338
+ border-radius: 4px;
339
+ background: var(--bg-2);
340
+ color: var(--text);
341
+ font: inherit;
342
+ }
343
+
344
+ .chip {
345
+ display: inline-block;
346
+ padding: 1px 7px;
347
+ border-radius: 999px;
348
+ background: var(--bg-3);
349
+ color: var(--muted);
350
+ font-size: 11px;
351
+ }
352
+
353
+ button.chip[data-off] {
354
+ text-decoration: line-through;
355
+ opacity: 0.55;
356
+ }
357
+
358
+ .chip[data-tone="warn"] {
359
+ background: #5c4106;
360
+ color: #f2cc60;
361
+ }
362
+
363
+ .chip[data-tone="bad"] {
364
+ background: #6e1a1b;
365
+ color: #ffa198;
366
+ }
367
+
368
+ .chip[data-tone="ok"] {
369
+ background: #133d20;
370
+ color: #7ee787;
371
+ }
372
+
373
+ .btn {
374
+ padding: 3px 9px;
375
+ border: 1px solid var(--line);
376
+ border-radius: 4px;
377
+ background: var(--bg-2);
378
+ }
379
+
380
+ .btn:hover,
381
+ .btn[data-on] {
382
+ border-color: var(--accent);
383
+ color: var(--accent);
384
+ }
385
+
386
+ .list {
387
+ border-top: 1px solid var(--line);
388
+ }
389
+
390
+ .entry {
391
+ display: grid;
392
+ grid-template-columns: 78px 1fr auto;
393
+ gap: 10px;
394
+ padding: 6px 4px;
395
+ border-bottom: 1px solid var(--line);
396
+ cursor: pointer;
397
+ }
398
+
399
+ .entry:hover {
400
+ background: var(--bg-2);
401
+ }
402
+
403
+ .entry[data-tone="warn"] {
404
+ box-shadow: inset 3px 0 0 var(--warn);
405
+ }
406
+
407
+ .entry[data-tone="bad"] {
408
+ box-shadow: inset 3px 0 0 var(--bad);
409
+ }
410
+
411
+ .entry .num {
412
+ color: var(--muted);
413
+ text-align: right;
414
+ }
415
+
416
+ .entry .meter {
417
+ height: 3px;
418
+ margin-top: 4px;
419
+ background: var(--accent);
420
+ border-radius: 2px;
421
+ opacity: 0.6;
422
+ }
423
+
424
+ .entry .extra {
425
+ display: none;
426
+ grid-column: 2 / 4;
427
+ }
428
+
429
+ .entry[data-expanded] .extra {
430
+ display: block;
431
+ }
432
+
433
+ .sql {
434
+ white-space: pre-wrap;
435
+ overflow-wrap: anywhere;
436
+ }
437
+
438
+ .meta {
439
+ color: var(--muted);
440
+ }
441
+
442
+ .bad {
443
+ color: var(--bad);
444
+ }
445
+
446
+ pre {
447
+ margin: 6px 0 0;
448
+ padding: 8px;
449
+ max-height: 320px;
450
+ overflow: auto;
451
+ border-radius: 4px;
452
+ background: var(--bg-2);
453
+ white-space: pre-wrap;
454
+ overflow-wrap: anywhere;
455
+ }
456
+
457
+ h3 {
458
+ margin: 14px 0 6px;
459
+ font-size: 11px;
460
+ font-weight: 600;
461
+ letter-spacing: 0.06em;
462
+ text-transform: uppercase;
463
+ color: var(--muted);
464
+ }
465
+
466
+ h3:first-child {
467
+ margin-top: 0;
468
+ }
469
+
470
+ table {
471
+ width: 100%;
472
+ border-collapse: collapse;
473
+ }
474
+
475
+ td,
476
+ th {
477
+ padding: 4px 8px;
478
+ border-bottom: 1px solid var(--line);
479
+ text-align: left;
480
+ vertical-align: top;
481
+ }
482
+
483
+ th {
484
+ color: var(--muted);
485
+ font-weight: 500;
486
+ }
487
+
488
+ td.key {
489
+ width: 200px;
490
+ color: var(--muted);
491
+ }
492
+
493
+ tr.pick {
494
+ cursor: pointer;
495
+ }
496
+
497
+ tr.pick:hover,
498
+ tr.pick[data-active] {
499
+ background: var(--bg-2);
500
+ }
501
+
502
+ .empty {
503
+ padding: 18px 4px;
504
+ color: var(--muted);
505
+ }
506
+
507
+ /* ── Timeline ────────────────────────────────────────────── */
508
+
509
+ .lane {
510
+ display: grid;
511
+ grid-template-columns: 260px 1fr 70px;
512
+ align-items: center;
513
+ gap: 10px;
514
+ padding: 3px 0;
515
+ }
516
+
517
+ .lane .name {
518
+ overflow: hidden;
519
+ text-overflow: ellipsis;
520
+ white-space: nowrap;
521
+ }
522
+
523
+ .track {
524
+ position: relative;
525
+ height: 12px;
526
+ background: var(--bg-2);
527
+ border-radius: 2px;
528
+ }
529
+
530
+ .span {
531
+ position: absolute;
532
+ top: 0;
533
+ bottom: 0;
534
+ min-width: 2px;
535
+ border-radius: 2px;
536
+ background: var(--accent);
537
+ }
538
+
539
+ .legend::before {
540
+ content: "";
541
+ display: inline-block;
542
+ width: 8px;
543
+ height: 8px;
544
+ margin-right: 5px;
545
+ border-radius: 2px;
546
+ background: var(--accent);
547
+ }
548
+
549
+ .legend[data-kind="request"]::before {
550
+ background: #3b4250;
551
+ }
552
+
553
+ .legend[data-kind="query"]::before {
554
+ background: #a371f7;
555
+ }
556
+
557
+ .legend[data-kind="log"]::before {
558
+ background: var(--warn);
559
+ }
560
+
561
+ .legend[data-kind="event"]::before {
562
+ background: var(--ok);
563
+ }
564
+
565
+ .span[data-kind="request"] {
566
+ background: #3b4250;
567
+ }
568
+
569
+ .span[data-kind="query"] {
570
+ background: #a371f7;
571
+ }
572
+
573
+ .span[data-kind="log"] {
574
+ background: var(--warn);
575
+ }
576
+
577
+ .span[data-kind="event"] {
578
+ background: var(--ok);
579
+ }
580
+
581
+ @media (max-width: 760px) {
582
+ .item .label {
583
+ display: none;
584
+ }
585
+
586
+ .lane {
587
+ grid-template-columns: 140px 1fr 56px;
588
+ }
589
+ }
590
+
591
+ @media print {
592
+ .rp {
593
+ display: none;
594
+ }
595
+ }