@apisurf/wireui 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +157 -0
  3. package/bin/wireui.mjs +233 -0
  4. package/dist/nitro.json +17 -0
  5. package/dist/public/assets/collections-CLHcfRfi.js +1 -0
  6. package/dist/public/assets/globals-CZiNFGaK.css +1 -0
  7. package/dist/public/assets/index-D5VFd_3H.js +14 -0
  8. package/dist/public/assets/kv-table-oB5gcq0i.js +2 -0
  9. package/dist/public/assets/query-BKAhHNIi.js +19 -0
  10. package/dist/public/assets/requests._requestId-Bu7E2eoI.js +1 -0
  11. package/dist/public/assets/routes-DDY2CfzA.js +1 -0
  12. package/dist/public/assets/runs._runId-CzwtVjYq.js +1 -0
  13. package/dist/public/assets/scoped-DB8raIWx.js +1 -0
  14. package/dist/public/assets/split-Br1RX2I4.js +1 -0
  15. package/dist/public/favicon.svg +1 -0
  16. package/dist/server/_chunks/ssr-renderer.mjs +26 -0
  17. package/dist/server/_libs/@tanstack/react-router+[...].mjs +15246 -0
  18. package/dist/server/_libs/h3+rou3+srvx.mjs +2086 -0
  19. package/dist/server/_libs/hookable.mjs +41 -0
  20. package/dist/server/_libs/tanstack__history.mjs +369 -0
  21. package/dist/server/_libs/ufo.mjs +64 -0
  22. package/dist/server/_runtime.mjs +35 -0
  23. package/dist/server/_ssr/api-Dw1Zb_PK.mjs +931 -0
  24. package/dist/server/_ssr/collections-CqidTQpw.mjs +495 -0
  25. package/dist/server/_ssr/empty-plugin-adapters-CCuiUfKt.mjs +5 -0
  26. package/dist/server/_ssr/kv-table-DQUkoItO.mjs +458 -0
  27. package/dist/server/_ssr/query-D4so9xiY.mjs +416 -0
  28. package/dist/server/_ssr/requests._requestId-BFukRwqL.mjs +942 -0
  29. package/dist/server/_ssr/router-CPcgc_kh.mjs +3176 -0
  30. package/dist/server/_ssr/routes-DaV9vGHn.mjs +375 -0
  31. package/dist/server/_ssr/runs._runId-Df_LmPHa.mjs +836 -0
  32. package/dist/server/_ssr/scoped-CnQ56K8h.mjs +42 -0
  33. package/dist/server/_ssr/split-DWrMIs7K.mjs +115 -0
  34. package/dist/server/_ssr/ssr.mjs +6827 -0
  35. package/dist/server/_ssr/start-zk_ZfrWl.mjs +4 -0
  36. package/dist/server/_tanstack-start-manifest_v-CARKjHfs.mjs +50 -0
  37. package/dist/server/index.mjs +368 -0
  38. package/package.json +71 -0
@@ -0,0 +1,3176 @@
1
+ import { __toESM } from "../_runtime.mjs";
2
+ import { HeadContent, Link, Outlet, Scripts, createFileRoute, createRootRoute, createRouter, getRouteApi, lazyRouteComponent, notFound, require_jsx_runtime, require_react, useLocation, useNavigate, useRouter, useRouterState } from "../_libs/@tanstack/react-router+[...].mjs";
3
+ import { TSS_SERVER_FUNCTION, createServerFn, getServerFnById } from "./ssr.mjs";
4
+ //#region node_modules/.nitro/vite/services/ssr/assets/api-li-c8dNB.js
5
+ var import_react = /* @__PURE__ */ __toESM(require_react());
6
+ var import_jsx_runtime = require_jsx_runtime();
7
+ function isObject(value) {
8
+ return typeof value === "object" && value != null && !Array.isArray(value);
9
+ }
10
+ var isObjectOrArray = (obj) => typeof obj === "object" && obj !== null;
11
+ function compact(value) {
12
+ return Object.fromEntries(Object.entries(value ?? {}).filter(([_, value2]) => value2 !== void 0));
13
+ }
14
+ var isBaseCondition = (v) => v === "base";
15
+ function filterBaseConditions(c) {
16
+ return c.slice().filter((v) => !isBaseCondition(v));
17
+ }
18
+ function toChar(code) {
19
+ return String.fromCharCode(code + (code > 25 ? 39 : 97));
20
+ }
21
+ function toName(code) {
22
+ let name = "";
23
+ let x;
24
+ for (x = Math.abs(code); x > 52; x = x / 52 | 0) name = toChar(x % 52) + name;
25
+ return toChar(x % 52) + name;
26
+ }
27
+ function toPhash(h, x) {
28
+ let i = x.length;
29
+ while (i) h = h * 33 ^ x.charCodeAt(--i);
30
+ return h;
31
+ }
32
+ function toHash(value) {
33
+ return toName(toPhash(5381, value) >>> 0);
34
+ }
35
+ var importantRegex = /\s*!(important)?/i;
36
+ function isImportant(value) {
37
+ return typeof value === "string" ? importantRegex.test(value) : false;
38
+ }
39
+ function withoutImportant(value) {
40
+ return typeof value === "string" ? value.replace(importantRegex, "").trim() : value;
41
+ }
42
+ function withoutSpace(str) {
43
+ return typeof str === "string" ? str.replaceAll(" ", "_") : str;
44
+ }
45
+ var memo = (fn) => {
46
+ const cache = /* @__PURE__ */ new Map();
47
+ const get = (...args) => {
48
+ const key = JSON.stringify(args);
49
+ if (cache.has(key)) return cache.get(key);
50
+ const result = fn(...args);
51
+ cache.set(key, result);
52
+ return result;
53
+ };
54
+ return get;
55
+ };
56
+ var MERGE_OMIT = /* @__PURE__ */ new Set([
57
+ "__proto__",
58
+ "constructor",
59
+ "prototype"
60
+ ]);
61
+ function mergeProps(...sources) {
62
+ return sources.reduce((prev, obj) => {
63
+ if (!obj) return prev;
64
+ Object.keys(obj).forEach((key) => {
65
+ if (MERGE_OMIT.has(key)) return;
66
+ const prevValue = prev[key];
67
+ const value = obj[key];
68
+ if (isObject(prevValue) && isObject(value)) prev[key] = mergeProps(prevValue, value);
69
+ else prev[key] = value;
70
+ });
71
+ return prev;
72
+ }, {});
73
+ }
74
+ var isNotNullish = (element) => element != null;
75
+ function walkObject(target, predicate, options = {}) {
76
+ const { stop, getKey } = options;
77
+ function inner(value, path = []) {
78
+ if (isObjectOrArray(value)) {
79
+ const result = {};
80
+ for (const [prop, child] of Object.entries(value)) {
81
+ const key = getKey?.(prop, child) ?? prop;
82
+ const childPath = [...path, key];
83
+ if (stop?.(value, childPath)) return predicate(value, path);
84
+ const next = inner(child, childPath);
85
+ if (isNotNullish(next)) result[key] = next;
86
+ }
87
+ return result;
88
+ }
89
+ return predicate(value, path);
90
+ }
91
+ return inner(target);
92
+ }
93
+ function toResponsiveObject(values, breakpoints) {
94
+ return values.reduce((acc, current, index) => {
95
+ const key = breakpoints[index];
96
+ if (current != null) acc[key] = current;
97
+ return acc;
98
+ }, {});
99
+ }
100
+ function normalizeStyleObject(styles, context, shorthand = true) {
101
+ const { utility, conditions } = context;
102
+ const { hasShorthand, resolveShorthand } = utility;
103
+ return walkObject(styles, (value) => {
104
+ return Array.isArray(value) ? toResponsiveObject(value, conditions.breakpoints.keys) : value;
105
+ }, {
106
+ stop: (value) => Array.isArray(value),
107
+ getKey: shorthand ? (prop) => hasShorthand ? resolveShorthand(prop) : prop : void 0
108
+ });
109
+ }
110
+ var fallbackCondition = {
111
+ shift: (v) => v,
112
+ finalize: (v) => v,
113
+ breakpoints: { keys: [] }
114
+ };
115
+ var sanitize = (value) => typeof value === "string" ? value.replaceAll(/[\n\s]+/g, " ") : value;
116
+ function createCss(context) {
117
+ const { utility, hash, conditions: conds = fallbackCondition } = context;
118
+ const formatClassName = (str) => [utility.prefix, str].filter(Boolean).join("-");
119
+ const hashFn = (conditions, className) => {
120
+ let result;
121
+ if (hash) {
122
+ const baseArray = [...conds.finalize(conditions), className];
123
+ result = formatClassName(utility.toHash(baseArray, toHash));
124
+ } else result = [...conds.finalize(conditions), formatClassName(className)].join(":");
125
+ return result;
126
+ };
127
+ return memo(({ base, ...styles } = {}) => {
128
+ const normalizedObject = normalizeStyleObject(Object.assign(styles, base), context);
129
+ const classNames = /* @__PURE__ */ new Set();
130
+ walkObject(normalizedObject, (value, paths) => {
131
+ if (value == null) return;
132
+ const important = isImportant(value);
133
+ const [prop, ...allConditions] = conds.shift(paths);
134
+ const conditions = filterBaseConditions(allConditions);
135
+ const transformed = utility.transform(prop, withoutImportant(sanitize(value)));
136
+ let className = hashFn(conditions, transformed.className);
137
+ if (important) className = `${className}!`;
138
+ classNames.add(className);
139
+ });
140
+ return Array.from(classNames).join(" ");
141
+ });
142
+ }
143
+ function compactStyles(...styles) {
144
+ return styles.flat().filter((style) => isObject(style) && Object.keys(compact(style)).length > 0);
145
+ }
146
+ function createMergeCss(context) {
147
+ function resolve(styles) {
148
+ const allStyles = compactStyles(...styles);
149
+ if (allStyles.length === 1) return allStyles;
150
+ return allStyles.map((style) => normalizeStyleObject(style, context));
151
+ }
152
+ function mergeCss(...styles) {
153
+ return mergeProps(...resolve(styles));
154
+ }
155
+ function assignCss(...styles) {
156
+ return Object.assign({}, ...resolve(styles));
157
+ }
158
+ return {
159
+ mergeCss: memo(mergeCss),
160
+ assignCss
161
+ };
162
+ }
163
+ var wordRegex = /([A-Z])/g;
164
+ var msRegex = /^ms-/;
165
+ var hypenateProperty = memo((property) => {
166
+ if (property.startsWith("--")) return property;
167
+ return property.replace(wordRegex, "-$1").replace(msRegex, "-ms-").toLowerCase();
168
+ });
169
+ new RegExp(`^(${[
170
+ "min",
171
+ "max",
172
+ "clamp",
173
+ "calc"
174
+ ].join("|")})\\(.*\\)`);
175
+ var lengthUnitsPattern = `(?:${"cm,mm,Q,in,pc,pt,px,em,ex,ch,rem,lh,rlh,vw,vh,vmin,vmax,vb,vi,svw,svh,lvw,lvh,dvw,dvh,cqw,cqh,cqi,cqb,cqmin,cqmax,%".split(",").join("|")})`;
176
+ new RegExp(`^[+-]?[0-9]*.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`);
177
+ var htmlProps = [
178
+ "htmlSize",
179
+ "htmlTranslate",
180
+ "htmlWidth",
181
+ "htmlHeight"
182
+ ];
183
+ function convert(key) {
184
+ return htmlProps.includes(key) ? key.replace("html", "").toLowerCase() : key;
185
+ }
186
+ function normalizeHTMLProps(props) {
187
+ return Object.fromEntries(Object.entries(props).map(([key, value]) => [convert(key), value]));
188
+ }
189
+ normalizeHTMLProps.keys = htmlProps;
190
+ var conditions = new Set("_hover,_focus,_focusWithin,_focusVisible,_disabled,_active,_visited,_target,_readOnly,_readWrite,_empty,_checked,_enabled,_expanded,_highlighted,_complete,_incomplete,_dragging,_before,_after,_firstLetter,_firstLine,_marker,_selection,_file,_backdrop,_first,_last,_only,_even,_odd,_firstOfType,_lastOfType,_onlyOfType,_peerFocus,_peerHover,_peerActive,_peerFocusWithin,_peerFocusVisible,_peerDisabled,_peerChecked,_peerInvalid,_peerExpanded,_peerPlaceholderShown,_groupFocus,_groupHover,_groupActive,_groupFocusWithin,_groupFocusVisible,_groupDisabled,_groupChecked,_groupExpanded,_groupInvalid,_indeterminate,_required,_valid,_invalid,_autofill,_inRange,_outOfRange,_placeholder,_placeholderShown,_pressed,_selected,_grabbed,_underValue,_overValue,_atValue,_default,_optional,_open,_closed,_fullscreen,_loading,_hidden,_current,_currentPage,_currentStep,_today,_unavailable,_rangeStart,_rangeEnd,_now,_topmost,_motionReduce,_motionSafe,_print,_landscape,_portrait,_dark,_light,_osDark,_osLight,_highContrast,_lessContrast,_moreContrast,_ltr,_rtl,_scrollbar,_scrollbarThumb,_scrollbarTrack,_horizontal,_vertical,_icon,_starting,_noscript,_invertedColors,sm,smOnly,smDown,md,mdOnly,mdDown,lg,lgOnly,lgDown,xl,xlOnly,xlDown,2xl,2xlOnly,2xlDown,smToMd,smToLg,smToXl,smTo2xl,mdToLg,mdToXl,mdTo2xl,lgToXl,lgTo2xl,xlTo2xl,@/xs,@/sm,@/md,@/lg,@/xl,@/2xl,@/3xl,@/4xl,@/5xl,@/6xl,@/7xl,@/8xl,base".split(","));
191
+ var conditionRegex = /^@|&|&$/;
192
+ function isCondition(value) {
193
+ return conditions.has(value) || conditionRegex.test(value);
194
+ }
195
+ var underscoreRegex = /^_/;
196
+ var conditionsSelectorRegex = /&|@/;
197
+ function finalizeConditions(paths) {
198
+ return paths.map((path) => {
199
+ if (conditions.has(path)) return path.replace(underscoreRegex, "");
200
+ if (conditionsSelectorRegex.test(path)) return `[${withoutSpace(path.trim())}]`;
201
+ return path;
202
+ });
203
+ }
204
+ function sortConditions(paths) {
205
+ return paths.sort((a, b) => {
206
+ const aa = isCondition(a);
207
+ const bb = isCondition(b);
208
+ if (aa && !bb) return 1;
209
+ if (!aa && bb) return -1;
210
+ return 0;
211
+ });
212
+ }
213
+ var utilities = "aspectRatio:asp,boxDecorationBreak:bx-db,zIndex:z,boxSizing:bx-s,objectPosition:obj-p,objectFit:obj-f,overscrollBehavior:ovs-b,overscrollBehaviorX:ovs-bx,overscrollBehaviorY:ovs-by,position:pos/1,top:top,left:left,inset:inset,insetInline:inset-x/insetX,insetBlock:inset-y/insetY,insetBlockEnd:inset-be,insetBlockStart:inset-bs,insetInlineEnd:inset-e/insetEnd/end,insetInlineStart:inset-s/insetStart/start,right:right,bottom:bottom,float:float,visibility:vis,display:d,hideFrom:hide,hideBelow:show,flexBasis:flex-b,flex:flex,flexDirection:flex-d/flexDir,flexGrow:flex-g,flexShrink:flex-sh,gridTemplateColumns:grid-tc,gridTemplateRows:grid-tr,gridColumn:grid-c,gridRow:grid-r,gridColumnStart:grid-cs,gridColumnEnd:grid-ce,gridAutoFlow:grid-af,gridAutoColumns:grid-ac,gridAutoRows:grid-ar,gap:gap,gridGap:grid-g,gridRowGap:grid-rg,gridColumnGap:grid-cg,rowGap:rg,columnGap:cg,justifyContent:jc,alignContent:ac,alignItems:ai,alignSelf:as,padding:p/1,paddingLeft:pl/1,paddingRight:pr/1,paddingTop:pt/1,paddingBottom:pb/1,paddingBlock:py/1/paddingY,paddingBlockEnd:pbe,paddingBlockStart:pbs,paddingInline:px/paddingX/1,paddingInlineEnd:pe/1/paddingEnd,paddingInlineStart:ps/1/paddingStart,marginLeft:ml/1,marginRight:mr/1,marginTop:mt/1,marginBottom:mb/1,margin:m/1,marginBlock:my/1/marginY,marginBlockEnd:mbe,marginBlockStart:mbs,marginInline:mx/1/marginX,marginInlineEnd:me/1/marginEnd,marginInlineStart:ms/1/marginStart,spaceX:sx,spaceY:sy,outlineWidth:ring-w/ringWidth,outlineColor:ring-c/ringColor,outline:ring/1,outlineOffset:ring-o/ringOffset,focusRing:focus-ring,focusVisibleRing:focus-v-ring,focusRingColor:focus-ring-c,focusRingOffset:focus-ring-o,focusRingWidth:focus-ring-w,focusRingStyle:focus-ring-s,divideX:dvd-x,divideY:dvd-y,divideColor:dvd-c,divideStyle:dvd-s,width:w/1,inlineSize:w-is,minWidth:min-w/minW,minInlineSize:min-w-is,maxWidth:max-w/maxW,maxInlineSize:max-w-is,height:h/1,blockSize:h-bs,minHeight:min-h/minH,minBlockSize:min-h-bs,maxHeight:max-h/maxH,maxBlockSize:max-b,boxSize:size,color:c,fontFamily:ff,fontSize:fs,fontSizeAdjust:fs-a,fontPalette:fp,fontKerning:fk,fontFeatureSettings:ff-s,fontWeight:fw,fontSmoothing:fsmt,fontVariant:fv,fontVariantAlternates:fv-alt,fontVariantCaps:fv-caps,fontVariationSettings:fv-s,fontVariantNumeric:fv-num,letterSpacing:ls,lineHeight:lh,textAlign:ta,textDecoration:td,textDecorationColor:td-c,textEmphasisColor:te-c,textDecorationStyle:td-s,textDecorationThickness:td-t,textUnderlineOffset:tu-o,textTransform:tt,textIndent:ti,textShadow:tsh,textShadowColor:tsh-c/textShadowColor,WebkitTextFillColor:wktf-c,textOverflow:tov,verticalAlign:va,wordBreak:wb,textWrap:tw,truncate:trunc,lineClamp:lc,listStyleType:li-t,listStylePosition:li-pos,listStyleImage:li-img,listStyle:li-s,backgroundPosition:bg-p/bgPosition,backgroundPositionX:bg-p-x/bgPositionX,backgroundPositionY:bg-p-y/bgPositionY,backgroundAttachment:bg-a/bgAttachment,backgroundClip:bg-cp/bgClip,background:bg/1,backgroundColor:bg-c/bgColor,backgroundOrigin:bg-o/bgOrigin,backgroundImage:bg-i/bgImage,backgroundRepeat:bg-r/bgRepeat,backgroundBlendMode:bg-bm/bgBlendMode,backgroundSize:bg-s/bgSize,backgroundGradient:bg-grad/bgGradient,backgroundLinear:bg-linear/bgLinear,backgroundRadial:bg-radial/bgRadial,backgroundConic:bg-conic/bgConic,textGradient:txt-grad,gradientFromPosition:grad-from-pos,gradientToPosition:grad-to-pos,gradientFrom:grad-from,gradientTo:grad-to,gradientVia:grad-via,gradientViaPosition:grad-via-pos,borderRadius:bdr/rounded,borderTopLeftRadius:bdr-tl/roundedTopLeft,borderTopRightRadius:bdr-tr/roundedTopRight,borderBottomRightRadius:bdr-br/roundedBottomRight,borderBottomLeftRadius:bdr-bl/roundedBottomLeft,borderTopRadius:bdr-t/roundedTop,borderRightRadius:bdr-r/roundedRight,borderBottomRadius:bdr-b/roundedBottom,borderLeftRadius:bdr-l/roundedLeft,borderStartStartRadius:bdr-ss/roundedStartStart,borderStartEndRadius:bdr-se/roundedStartEnd,borderStartRadius:bdr-s/roundedStart,borderEndStartRadius:bdr-es/roundedEndStart,borderEndEndRadius:bdr-ee/roundedEndEnd,borderEndRadius:bdr-e/roundedEnd,border:bd,borderWidth:bd-w,borderTopWidth:bd-t-w,borderLeftWidth:bd-l-w,borderRightWidth:bd-r-w,borderBottomWidth:bd-b-w,borderBlockStartWidth:bd-bs-w,borderBlockEndWidth:bd-be-w,borderColor:bd-c,borderInline:bd-x/borderX,borderInlineWidth:bd-x-w/borderXWidth,borderInlineColor:bd-x-c/borderXColor,borderBlock:bd-y/borderY,borderBlockWidth:bd-y-w/borderYWidth,borderBlockColor:bd-y-c/borderYColor,borderLeft:bd-l,borderLeftColor:bd-l-c,borderInlineStart:bd-s/borderStart,borderInlineStartWidth:bd-s-w/borderStartWidth,borderInlineStartColor:bd-s-c/borderStartColor,borderRight:bd-r,borderRightColor:bd-r-c,borderInlineEnd:bd-e/borderEnd,borderInlineEndWidth:bd-e-w/borderEndWidth,borderInlineEndColor:bd-e-c/borderEndColor,borderTop:bd-t,borderTopColor:bd-t-c,borderBottom:bd-b,borderBottomColor:bd-b-c,borderBlockEnd:bd-be,borderBlockEndColor:bd-be-c,borderBlockStart:bd-bs,borderBlockStartColor:bd-bs-c,opacity:op,boxShadow:bx-sh/shadow,boxShadowColor:bx-sh-c/shadowColor,mixBlendMode:mix-bm,filter:filter,brightness:brightness,contrast:contrast,grayscale:grayscale,hueRotate:hue-rotate,invert:invert,saturate:saturate,sepia:sepia,dropShadow:drop-shadow,blur:blur,backdropFilter:bkdp,backdropBlur:bkdp-blur,backdropBrightness:bkdp-brightness,backdropContrast:bkdp-contrast,backdropGrayscale:bkdp-grayscale,backdropHueRotate:bkdp-hue-rotate,backdropInvert:bkdp-invert,backdropOpacity:bkdp-opacity,backdropSaturate:bkdp-saturate,backdropSepia:bkdp-sepia,borderCollapse:bd-cl,borderSpacing:bd-sp,borderSpacingX:bd-sx,borderSpacingY:bd-sy,tableLayout:tbl,transitionTimingFunction:trs-tmf,transitionDelay:trs-dly,transitionDuration:trs-dur,transitionProperty:trs-prop,transition:trs,animation:anim,animationName:anim-n,animationTimingFunction:anim-tmf,animationDuration:anim-dur,animationDelay:anim-dly,animationPlayState:anim-ps,animationComposition:anim-comp,animationFillMode:anim-fm,animationDirection:anim-dir,animationIterationCount:anim-ic,animationRange:anim-r,animationState:anim-s,animationRangeStart:anim-rs,animationRangeEnd:anim-re,animationTimeline:anim-tl,transformOrigin:trf-o,transformBox:trf-b,transformStyle:trf-s,transform:trf,rotate:rotate,rotateX:rotate-x,rotateY:rotate-y,rotateZ:rotate-z,scale:scale,scaleX:scale-x,scaleY:scale-y,translate:translate,translateX:translate-x/x,translateY:translate-y/y,translateZ:translate-z/z,accentColor:ac-c,caretColor:ca-c,scrollBehavior:scr-bhv,scrollbar:scr-bar,scrollbarColor:scr-bar-c,scrollbarGutter:scr-bar-g,scrollbarWidth:scr-bar-w,scrollMargin:scr-m,scrollMarginLeft:scr-ml,scrollMarginRight:scr-mr,scrollMarginTop:scr-mt,scrollMarginBottom:scr-mb,scrollMarginBlock:scr-my/scrollMarginY,scrollMarginBlockEnd:scr-mbe,scrollMarginBlockStart:scr-mbt,scrollMarginInline:scr-mx/scrollMarginX,scrollMarginInlineEnd:scr-me,scrollMarginInlineStart:scr-ms,scrollPadding:scr-p,scrollPaddingBlock:scr-py/scrollPaddingY,scrollPaddingBlockStart:scr-pbs,scrollPaddingBlockEnd:scr-pbe,scrollPaddingInline:scr-px/scrollPaddingX,scrollPaddingInlineEnd:scr-pe,scrollPaddingInlineStart:scr-ps,scrollPaddingLeft:scr-pl,scrollPaddingRight:scr-pr,scrollPaddingTop:scr-pt,scrollPaddingBottom:scr-pb,scrollSnapAlign:scr-sa,scrollSnapStop:scrs-s,scrollSnapType:scrs-t,scrollSnapStrictness:scrs-strt,scrollSnapMargin:scrs-m,scrollSnapMarginTop:scrs-mt,scrollSnapMarginBottom:scrs-mb,scrollSnapMarginLeft:scrs-ml,scrollSnapMarginRight:scrs-mr,scrollSnapCoordinate:scrs-c,scrollSnapDestination:scrs-d,scrollSnapPointsX:scrs-px,scrollSnapPointsY:scrs-py,scrollSnapTypeX:scrs-tx,scrollSnapTypeY:scrs-ty,scrollTimeline:scrtl,scrollTimelineAxis:scrtl-a,scrollTimelineName:scrtl-n,touchAction:tch-a,userSelect:us,overflow:ov,overflowWrap:ov-wrap,overflowX:ov-x,overflowY:ov-y,overflowAnchor:ov-a,overflowBlock:ov-b,overflowInline:ov-i,overflowClipBox:ovcp-bx,overflowClipMargin:ovcp-m,overscrollBehaviorBlock:ovs-bb,overscrollBehaviorInline:ovs-bi,fill:fill,stroke:stk,strokeWidth:stk-w,strokeDasharray:stk-dsh,strokeDashoffset:stk-do,strokeLinecap:stk-lc,strokeLinejoin:stk-lj,strokeMiterlimit:stk-ml,strokeOpacity:stk-op,srOnly:sr,debug:debug,appearance:ap,backfaceVisibility:bfv,clipPath:cp-path,hyphens:hy,mask:msk,maskImage:msk-i,maskSize:msk-s,textSizeAdjust:txt-adj,container:cq,containerName:cq-n,containerType:cq-t,cursor:cursor,textStyle:textStyle";
214
+ var classNameByProp = /* @__PURE__ */ new Map();
215
+ var shorthands = /* @__PURE__ */ new Map();
216
+ utilities.split(",").forEach((utility) => {
217
+ const [prop, meta] = utility.split(":");
218
+ const [className, ...shorthandList] = meta.split("/");
219
+ classNameByProp.set(prop, className);
220
+ if (shorthandList.length) shorthandList.forEach((shorthand) => {
221
+ shorthands.set(shorthand === "1" ? className : shorthand, prop);
222
+ });
223
+ });
224
+ var resolveShorthand = (prop) => shorthands.get(prop) || prop;
225
+ var context = {
226
+ conditions: {
227
+ shift: sortConditions,
228
+ finalize: finalizeConditions,
229
+ breakpoints: { keys: [
230
+ "base",
231
+ "sm",
232
+ "md",
233
+ "lg",
234
+ "xl",
235
+ "2xl"
236
+ ] }
237
+ },
238
+ utility: {
239
+ transform: (prop, value) => {
240
+ const key = resolveShorthand(prop);
241
+ return { className: `${classNameByProp.get(key) || hypenateProperty(key)}_${withoutSpace(value)}` };
242
+ },
243
+ hasShorthand: true,
244
+ toHash: (path, hashFn) => hashFn(path.join(":")),
245
+ resolveShorthand
246
+ }
247
+ };
248
+ var cssFn = createCss(context);
249
+ var css = (...styles) => cssFn(mergeCss(...styles));
250
+ css.raw = (...styles) => mergeCss(...styles);
251
+ var { mergeCss, assignCss } = createMergeCss(context);
252
+ function cx() {
253
+ let str = "", i = 0, arg;
254
+ for (; i < arguments.length;) if ((arg = arguments[i++]) && typeof arg === "string") {
255
+ str && (str += " ");
256
+ str += arg;
257
+ }
258
+ return str;
259
+ }
260
+ function icon(paths) {
261
+ return function Icon({ size = 16, title, ...rest }) {
262
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
263
+ width: size,
264
+ height: size,
265
+ viewBox: "0 0 24 24",
266
+ fill: "none",
267
+ stroke: "currentColor",
268
+ strokeWidth: 1.75,
269
+ strokeLinecap: "round",
270
+ strokeLinejoin: "round",
271
+ "aria-hidden": title ? void 0 : true,
272
+ role: title ? "img" : void 0,
273
+ ...rest,
274
+ children: [title ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("title", { children: title }) : null, paths]
275
+ });
276
+ };
277
+ }
278
+ var IconCollections = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" }) }));
279
+ var IconHistory = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
280
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 12a9 9 0 1 0 3-6.7L3 8" }),
281
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 3v5h5" }),
282
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 7v5l3 2" })
283
+ ] }));
284
+ var IconEnvironments = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
285
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
286
+ cx: "12",
287
+ cy: "12",
288
+ r: "9"
289
+ }),
290
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 12h18" }),
291
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 3a14 14 0 0 1 0 18a14 14 0 0 1 0-18" })
292
+ ] }));
293
+ var IconDatabase = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
294
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", {
295
+ cx: "12",
296
+ cy: "5",
297
+ rx: "8",
298
+ ry: "3"
299
+ }),
300
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 5v14c0 1.7 3.6 3 8 3s8-1.3 8-3V5" }),
301
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 12c0 1.7 3.6 3 8 3s8-1.3 8-3" })
302
+ ] }));
303
+ var IconOverview = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
304
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", {
305
+ x: "3",
306
+ y: "3",
307
+ width: "7",
308
+ height: "9",
309
+ rx: "1.5"
310
+ }),
311
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", {
312
+ x: "14",
313
+ y: "3",
314
+ width: "7",
315
+ height: "5",
316
+ rx: "1.5"
317
+ }),
318
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", {
319
+ x: "14",
320
+ y: "12",
321
+ width: "7",
322
+ height: "9",
323
+ rx: "1.5"
324
+ }),
325
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", {
326
+ x: "3",
327
+ y: "16",
328
+ width: "7",
329
+ height: "5",
330
+ rx: "1.5"
331
+ })
332
+ ] }));
333
+ var IconRun = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M7 4v16l13-8z" }));
334
+ var IconRequest = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 12h16" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M14 6l6 6-6 6" })] }));
335
+ var IconChevronRight = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9 6l6 6-6 6" }));
336
+ var IconChevronDown = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M6 9l6 6 6-6" }));
337
+ var IconChevronLeft = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M15 6l-6 6 6 6" }));
338
+ var IconClose = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M6 6l12 12" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M18 6L6 18" })] }));
339
+ var IconRefresh = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
340
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M20 11a8 8 0 0 0-14.6-4.5L4 8" }),
341
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 4v4h4" }),
342
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 13a8 8 0 0 0 14.6 4.5L20 16" }),
343
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M20 20v-4h-4" })
344
+ ] }));
345
+ var IconSun = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
346
+ cx: "12",
347
+ cy: "12",
348
+ r: "4"
349
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4" })] }));
350
+ var IconMoon = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M20 14.5A8 8 0 0 1 9.5 4a8 8 0 1 0 10.5 10.5z" }));
351
+ var IconMonitor = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", {
352
+ x: "3",
353
+ y: "4",
354
+ width: "18",
355
+ height: "12",
356
+ rx: "2"
357
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 20h8M12 16v4" })] }));
358
+ var IconCopy = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", {
359
+ x: "9",
360
+ y: "9",
361
+ width: "11",
362
+ height: "11",
363
+ rx: "2"
364
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5 15V6a2 2 0 0 1 2-2h8" })] }));
365
+ var IconCheck = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5 12l5 5L20 7" }));
366
+ var IconSearch = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
367
+ cx: "11",
368
+ cy: "11",
369
+ r: "7"
370
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M20 20l-3.5-3.5" })] }));
371
+ var IconSplitSide = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", {
372
+ x: "3",
373
+ y: "4",
374
+ width: "18",
375
+ height: "16",
376
+ rx: "2"
377
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 4v16" })] }));
378
+ var IconSplitStacked = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", {
379
+ x: "3",
380
+ y: "4",
381
+ width: "18",
382
+ height: "16",
383
+ rx: "2"
384
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 12h18" })] }));
385
+ var IconSidebar = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", {
386
+ x: "3",
387
+ y: "4",
388
+ width: "18",
389
+ height: "16",
390
+ rx: "2"
391
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9 4v16" })] }));
392
+ var IconUp = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 19V5" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M6 11l6-6 6 6" })] }));
393
+ var IconDown = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 5v14" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M6 13l6 6 6-6" })] }));
394
+ var IconAlert = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 3l9.5 17h-19z" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 10v4M12 17.5v.01" })] }));
395
+ var IconCheckCircle = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
396
+ cx: "12",
397
+ cy: "12",
398
+ r: "9"
399
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 12.5l2.5 2.5L16 9.5" })] }));
400
+ var IconXCircle = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
401
+ cx: "12",
402
+ cy: "12",
403
+ r: "9"
404
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9 9l6 6M15 9l-6 6" })] }));
405
+ var IconPlay = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 5v14l11-7z" }));
406
+ var IconFile = icon(/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M14 3v5h5" })] }));
407
+ var STATUS_TEXT = {
408
+ 100: "Continue",
409
+ 101: "Switching Protocols",
410
+ 200: "OK",
411
+ 201: "Created",
412
+ 202: "Accepted",
413
+ 204: "No Content",
414
+ 206: "Partial Content",
415
+ 301: "Moved Permanently",
416
+ 302: "Found",
417
+ 303: "See Other",
418
+ 304: "Not Modified",
419
+ 307: "Temporary Redirect",
420
+ 308: "Permanent Redirect",
421
+ 400: "Bad Request",
422
+ 401: "Unauthorized",
423
+ 403: "Forbidden",
424
+ 404: "Not Found",
425
+ 405: "Method Not Allowed",
426
+ 406: "Not Acceptable",
427
+ 408: "Request Timeout",
428
+ 409: "Conflict",
429
+ 410: "Gone",
430
+ 413: "Payload Too Large",
431
+ 415: "Unsupported Media Type",
432
+ 422: "Unprocessable Content",
433
+ 429: "Too Many Requests",
434
+ 500: "Internal Server Error",
435
+ 501: "Not Implemented",
436
+ 502: "Bad Gateway",
437
+ 503: "Service Unavailable",
438
+ 504: "Gateway Timeout"
439
+ };
440
+ /** How a finished exchange went, as a colour family. */
441
+ function statusTone(status, errorName) {
442
+ if (errorName || status == null) return "bad";
443
+ if (status >= 500) return "bad";
444
+ if (status >= 400) return "warn";
445
+ if (status >= 300) return "info";
446
+ if (status >= 100) return "ok";
447
+ return "neutral";
448
+ }
449
+ function isFailure(row) {
450
+ return row.error_name != null || row.status == null || row.status >= 400;
451
+ }
452
+ /** The token a method is painted with. */
453
+ function methodToken(method, kind = "http") {
454
+ if (kind === "ws") return "ws";
455
+ if (kind === "sse") return "sse";
456
+ switch (method.toUpperCase()) {
457
+ case "GET": return "get";
458
+ case "POST": return "post";
459
+ case "PUT": return "put";
460
+ case "PATCH": return "patch";
461
+ case "DELETE": return "delete";
462
+ default: return "other";
463
+ }
464
+ }
465
+ /** What a badge says: the method, or the protocol for a connection. */
466
+ function methodLabel(method, kind = "http") {
467
+ if (kind === "ws") return "WS";
468
+ if (kind === "sse") return "SSE";
469
+ return method.toUpperCase();
470
+ }
471
+ function queryParams(query) {
472
+ if (!query) return [];
473
+ const out = [];
474
+ for (const [name, value] of new URLSearchParams(query)) out.push([name, value]);
475
+ return out;
476
+ }
477
+ /** Cookies the request carried, from its `Cookie` headers. */
478
+ function requestCookies(headers) {
479
+ return headers.filter(([name]) => name.toLowerCase() === "cookie").flatMap(([, value]) => value.split(";")).map((pair) => pair.trim()).filter(Boolean).map((pair) => {
480
+ const eq = pair.indexOf("=");
481
+ return eq < 0 ? {
482
+ name: pair,
483
+ value: "",
484
+ attributes: {}
485
+ } : {
486
+ name: pair.slice(0, eq),
487
+ value: pair.slice(eq + 1),
488
+ attributes: {}
489
+ };
490
+ });
491
+ }
492
+ /** Cookies the response set, one per `Set-Cookie` header. */
493
+ function responseCookies(headers) {
494
+ return headers.filter(([name]) => name.toLowerCase() === "set-cookie").map(([, value]) => {
495
+ const [first = "", ...rest] = value.split(";");
496
+ const eq = first.indexOf("=");
497
+ const attributes = {};
498
+ for (const part of rest) {
499
+ const trimmed = part.trim();
500
+ if (!trimmed) continue;
501
+ const at = trimmed.indexOf("=");
502
+ if (at < 0) attributes[trimmed] = "true";
503
+ else attributes[trimmed.slice(0, at)] = trimmed.slice(at + 1);
504
+ }
505
+ return {
506
+ name: eq < 0 ? first.trim() : first.slice(0, eq).trim(),
507
+ value: eq < 0 ? "" : first.slice(eq + 1).trim(),
508
+ attributes
509
+ };
510
+ });
511
+ }
512
+ /** A body as the text it was sent as, or null when it has none to give. */
513
+ function bodyText(body) {
514
+ if (body.kind === "json") return JSON.stringify(body.json, null, 2);
515
+ if (body.kind === "text") return body.text;
516
+ if (body.kind === "image") return body.text;
517
+ return null;
518
+ }
519
+ /** The compact form of a JSON body — what went over the wire, near enough. */
520
+ function bodyRaw(body) {
521
+ if (body.kind === "json") return JSON.stringify(body.json);
522
+ return bodyText(body);
523
+ }
524
+ /**
525
+ * Headers cURL computes on its own. Replaying them verbatim is at best noise and
526
+ * at worst wrong — a recorded Content-Length against a re-encoded body.
527
+ */
528
+ var CURL_SKIP = /* @__PURE__ */ new Set([
529
+ "content-length",
530
+ "host",
531
+ "connection",
532
+ "accept-encoding"
533
+ ]);
534
+ function shellQuote(value) {
535
+ return `'${value.replace(/'/g, `'\\''`)}'`;
536
+ }
537
+ /** The recorded request as a cURL command someone can paste and re-run. */
538
+ function toCurl(request, headers, body) {
539
+ const lines = [`curl ${request.method === "GET" ? "" : `-X ${request.method} `}${shellQuote(request.url)}`];
540
+ for (const [name, value] of headers) {
541
+ if (CURL_SKIP.has(name.toLowerCase())) continue;
542
+ lines.push(` -H ${shellQuote(`${name}: ${value}`)}`);
543
+ }
544
+ const raw = bodyRaw(body);
545
+ if (raw != null && raw !== "") lines.push(` --data-raw ${shellQuote(raw)}`);
546
+ return lines.join(" \\\n");
547
+ }
548
+ /**
549
+ * A request's duration split into phases that do not overlap and add up.
550
+ *
551
+ * `dns`, `connect` and `tls` are measured on their own; `ttfb` runs from the
552
+ * start to the first response byte, so it already contains them — the server's
553
+ * own time is what is left of it. `download` follows the first byte. Anything
554
+ * the marks do not account for (a body read late by the script, say) is shown
555
+ * as its own phase rather than being folded into one that did not take it.
556
+ *
557
+ * A connection's duration is how long it stayed open; its phases are the
558
+ * handshake and the time to the first message instead.
559
+ */
560
+ function timingPhases(r) {
561
+ const handshake = (r.dns_ms ?? 0) + (r.connect_ms ?? 0) + (r.tls_ms ?? 0);
562
+ const phases = [];
563
+ const push = (key, label, hint, ms) => {
564
+ if (ms != null && ms > .005) phases.push({
565
+ key,
566
+ label,
567
+ hint,
568
+ ms
569
+ });
570
+ };
571
+ const stream = r.kind !== "http";
572
+ push("dns", "DNS lookup", "Resolving the hostname", r.dns_ms);
573
+ push("connect", stream ? "Handshake" : "TCP connect", "Opening the connection", r.connect_ms);
574
+ push("tls", "TLS handshake", "Negotiating encryption", r.tls_ms);
575
+ if (r.ttfb_ms != null) {
576
+ const wait = Math.max(0, r.ttfb_ms - handshake);
577
+ push("wait", stream ? "First message" : "Waiting (TTFB)", stream ? "Until the first message arrived" : "Server processing, until the first byte", wait);
578
+ }
579
+ if (!stream) push("download", "Content download", "Reading the response body", r.download_ms);
580
+ const accounted = phases.reduce((sum, p) => sum + p.ms, 0);
581
+ const rest = r.duration_ms - accounted;
582
+ push("other", stream ? "Open" : "Other", stream ? "The rest of the connection's lifetime" : "Time the phase marks do not cover", rest > .5 ? rest : null);
583
+ return phases;
584
+ }
585
+ /**
586
+ * How a run went, in one colour.
587
+ *
588
+ * A failed check leaves the exit code at 0 by design, so it has to be read here
589
+ * or a run that asserted something false would look green everywhere. Failed
590
+ * requests are amber rather than red: a script that probes a 404 on purpose is
591
+ * not broken.
592
+ */
593
+ function runTone(run) {
594
+ if (run.exit_status === "error" || run.failed_check_count > 0) return "bad";
595
+ if (run.finished_at == null) return "info";
596
+ if (run.error_count > 0) return "warn";
597
+ return "ok";
598
+ }
599
+ function runVerdict(run) {
600
+ if (run.exit_status === "error") return "Threw";
601
+ if (run.failed_check_count > 0) return `${run.failed_check_count} failed check${run.failed_check_count === 1 ? "" : "s"}`;
602
+ if (run.finished_at == null) return "Running or killed";
603
+ if (run.error_count > 0) return `${run.error_count} failed request${run.error_count === 1 ? "" : "s"}`;
604
+ return "Passed";
605
+ }
606
+ var mono = css({
607
+ fontFamily: "mono",
608
+ fontSize: "12px"
609
+ });
610
+ var truncate = css({
611
+ overflow: "hidden",
612
+ textOverflow: "ellipsis",
613
+ whiteSpace: "nowrap"
614
+ });
615
+ var faintText = css({ color: "faint" });
616
+ css({ color: "muted" });
617
+ var METHOD_COLOR = {
618
+ get: css({ color: "get" }),
619
+ post: css({ color: "post" }),
620
+ put: css({ color: "put" }),
621
+ patch: css({ color: "patch" }),
622
+ delete: css({ color: "delete" }),
623
+ other: css({ color: "other" }),
624
+ ws: css({ color: "ws" }),
625
+ sse: css({ color: "sse" })
626
+ };
627
+ function MethodBadge({ method, kind = "http", width }) {
628
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
629
+ className: cx(css({
630
+ fontFamily: "mono",
631
+ fontSize: "10.5px",
632
+ fontWeight: "700",
633
+ letterSpacing: "0.02em",
634
+ flexShrink: 0
635
+ }), width === "list" && css({
636
+ display: "inline-block",
637
+ w: "46px"
638
+ }), METHOD_COLOR[methodToken(method, kind)]),
639
+ children: methodLabel(method, kind)
640
+ });
641
+ }
642
+ var TONE_TEXT = {
643
+ ok: css({ color: "ok" }),
644
+ info: css({ color: "info" }),
645
+ warn: css({ color: "warn" }),
646
+ bad: css({ color: "bad" }),
647
+ neutral: css({ color: "muted" })
648
+ };
649
+ var TONE_PILL = {
650
+ ok: css({
651
+ color: "ok",
652
+ bg: "okSoft"
653
+ }),
654
+ info: css({
655
+ color: "info",
656
+ bg: "accentSoft"
657
+ }),
658
+ warn: css({
659
+ color: "warn",
660
+ bg: "warnSoft"
661
+ }),
662
+ bad: css({
663
+ color: "bad",
664
+ bg: "badSoft"
665
+ }),
666
+ neutral: css({
667
+ color: "muted",
668
+ bg: "hover"
669
+ })
670
+ };
671
+ var TONE_DOT = {
672
+ ok: css({ bg: "ok" }),
673
+ info: css({ bg: "info" }),
674
+ warn: css({ bg: "warn" }),
675
+ bad: css({ bg: "bad" }),
676
+ neutral: css({ bg: "faint" })
677
+ };
678
+ function toneText(tone) {
679
+ return TONE_TEXT[tone];
680
+ }
681
+ /** `200` in a list, `200 OK` as a pill in a header. */
682
+ function StatusBadge({ status, error, pill = false }) {
683
+ const tone = statusTone(status, error);
684
+ const label = status == null ? error ?? "ERR" : String(status);
685
+ if (!pill) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
686
+ className: cx(mono, css({
687
+ fontWeight: "600",
688
+ flexShrink: 0
689
+ }), TONE_TEXT[tone]),
690
+ children: status == null ? "ERR" : label
691
+ });
692
+ const reason = status != null ? STATUS_TEXT[status] : null;
693
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
694
+ className: cx(css({
695
+ display: "inline-flex",
696
+ alignItems: "center",
697
+ gap: "1",
698
+ px: "2",
699
+ py: "0.5",
700
+ rounded: "sm",
701
+ fontWeight: "600",
702
+ fontSize: "12px",
703
+ whiteSpace: "nowrap"
704
+ }), TONE_PILL[tone]),
705
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
706
+ className: mono,
707
+ children: label
708
+ }), reason ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: reason }) : null]
709
+ });
710
+ }
711
+ function Dot({ tone, title }) {
712
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
713
+ title,
714
+ className: cx(css({
715
+ display: "inline-block",
716
+ w: "7px",
717
+ h: "7px",
718
+ rounded: "full",
719
+ flexShrink: 0
720
+ }), TONE_DOT[tone])
721
+ });
722
+ }
723
+ function Pill({ children, tone = "neutral", title }) {
724
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
725
+ title,
726
+ className: cx(css({
727
+ display: "inline-flex",
728
+ alignItems: "center",
729
+ gap: "1",
730
+ px: "1.5",
731
+ py: "0",
732
+ rounded: "sm",
733
+ fontSize: "11px",
734
+ fontWeight: "500",
735
+ whiteSpace: "nowrap",
736
+ lineHeight: "18px"
737
+ }), TONE_PILL[tone]),
738
+ children
739
+ });
740
+ }
741
+ var buttonBase = css({
742
+ display: "inline-flex",
743
+ alignItems: "center",
744
+ justifyContent: "center",
745
+ gap: "1.5",
746
+ h: "28px",
747
+ px: "2.5",
748
+ rounded: "md",
749
+ border: "1px solid",
750
+ borderColor: "line",
751
+ bg: "raised",
752
+ color: "fg",
753
+ cursor: "pointer",
754
+ whiteSpace: "nowrap",
755
+ fontWeight: "500",
756
+ fontSize: "12px",
757
+ transition: "background 80ms",
758
+ _hover: { bg: "hover" },
759
+ _disabled: {
760
+ opacity: .45,
761
+ cursor: "default",
762
+ _hover: { bg: "raised" }
763
+ },
764
+ _focusVisible: {
765
+ outline: "2px solid",
766
+ outlineColor: "accent",
767
+ outlineOffset: "1px"
768
+ }
769
+ });
770
+ function Button({ className, ...props }) {
771
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
772
+ type: "button",
773
+ className: cx(buttonBase, className),
774
+ ...props
775
+ });
776
+ }
777
+ var iconButton = css({
778
+ display: "inline-flex",
779
+ alignItems: "center",
780
+ justifyContent: "center",
781
+ w: "28px",
782
+ h: "28px",
783
+ rounded: "md",
784
+ border: "none",
785
+ bg: "transparent",
786
+ color: "muted",
787
+ cursor: "pointer",
788
+ flexShrink: 0,
789
+ _hover: {
790
+ bg: "hover",
791
+ color: "fg"
792
+ },
793
+ _disabled: {
794
+ opacity: .35,
795
+ cursor: "default",
796
+ _hover: { bg: "transparent" }
797
+ },
798
+ _focusVisible: {
799
+ outline: "2px solid",
800
+ outlineColor: "accent"
801
+ },
802
+ "&[aria-pressed=true]": {
803
+ color: "accent",
804
+ bg: "accentSoft"
805
+ }
806
+ });
807
+ function IconButton({ label, className, ...props }) {
808
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
809
+ type: "button",
810
+ "aria-label": label,
811
+ title: label,
812
+ className: cx(iconButton, className),
813
+ ...props
814
+ });
815
+ }
816
+ function CopyButton({ text, label = "Copy" }) {
817
+ const [copied, setCopied] = import_react.useState(false);
818
+ import_react.useEffect(() => {
819
+ if (!copied) return;
820
+ const timer = window.setTimeout(() => setCopied(false), 1200);
821
+ return () => window.clearTimeout(timer);
822
+ }, [copied]);
823
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
824
+ disabled: text == null,
825
+ onClick: () => {
826
+ if (text == null) return;
827
+ navigator.clipboard?.writeText(text).then(() => setCopied(true));
828
+ },
829
+ children: [copied ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconCheck, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconCopy, { size: 14 }), copied ? "Copied" : label]
830
+ });
831
+ }
832
+ function TabList({ items, value, onSelect, right, dense = false }) {
833
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
834
+ role: "tablist",
835
+ className: css({
836
+ display: "flex",
837
+ alignItems: "stretch",
838
+ gap: "0.5",
839
+ px: "3",
840
+ borderBottom: "1px solid",
841
+ borderColor: "line",
842
+ flexShrink: 0,
843
+ minH: dense ? "34px" : "38px",
844
+ overflowX: "auto",
845
+ scrollbarWidth: "none"
846
+ }),
847
+ children: [items.filter((item) => !item.hidden).map((item) => {
848
+ const active = item.id === value;
849
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
850
+ type: "button",
851
+ role: "tab",
852
+ "aria-selected": active,
853
+ onClick: () => onSelect(item.id),
854
+ className: css({
855
+ position: "relative",
856
+ display: "inline-flex",
857
+ alignItems: "center",
858
+ gap: "1.5",
859
+ px: "2",
860
+ border: "none",
861
+ bg: "transparent",
862
+ cursor: "pointer",
863
+ color: "muted",
864
+ fontWeight: "500",
865
+ whiteSpace: "nowrap",
866
+ _hover: { color: "fg" },
867
+ "&[aria-selected=true]": {
868
+ color: "fg",
869
+ _after: {
870
+ content: "\"\"",
871
+ position: "absolute",
872
+ left: "2",
873
+ right: "2",
874
+ bottom: "-1px",
875
+ h: "2px",
876
+ rounded: "full",
877
+ bg: "accent"
878
+ }
879
+ }
880
+ }),
881
+ children: [item.label, item.count !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
882
+ className: cx(css({
883
+ fontSize: "11px",
884
+ fontVariantNumeric: "tabular-nums"
885
+ }), item.tone ? TONE_TEXT[item.tone] : css({ color: "faint" })),
886
+ children: item.count
887
+ }) : null]
888
+ }, item.id);
889
+ }), right ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
890
+ className: css({
891
+ ml: "auto",
892
+ display: "flex",
893
+ alignItems: "center",
894
+ gap: "1.5",
895
+ pl: "2"
896
+ }),
897
+ children: right
898
+ }) : null]
899
+ });
900
+ }
901
+ function Segmented({ items, value, onSelect }) {
902
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
903
+ className: css({
904
+ display: "inline-flex",
905
+ p: "2px",
906
+ gap: "2px",
907
+ rounded: "md",
908
+ bg: "hover",
909
+ flexShrink: 0
910
+ }),
911
+ children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
912
+ type: "button",
913
+ title: item.title,
914
+ "aria-pressed": item.id === value,
915
+ onClick: () => onSelect(item.id),
916
+ className: css({
917
+ display: "inline-flex",
918
+ alignItems: "center",
919
+ gap: "1",
920
+ h: "22px",
921
+ px: "2",
922
+ rounded: "sm",
923
+ border: "none",
924
+ bg: "transparent",
925
+ color: "muted",
926
+ cursor: "pointer",
927
+ fontSize: "12px",
928
+ fontWeight: "500",
929
+ _hover: { color: "fg" },
930
+ "&[aria-pressed=true]": {
931
+ bg: "raised",
932
+ color: "fg",
933
+ boxShadow: "0 1px 2px rgba(0,0,0,0.08)"
934
+ }
935
+ }),
936
+ children: item.label
937
+ }, item.id))
938
+ });
939
+ }
940
+ var FilterInput = import_react.forwardRef(function FilterInput({ shortcut, className, ...props }, ref) {
941
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", {
942
+ className: cx(css({
943
+ display: "flex",
944
+ alignItems: "center",
945
+ gap: "1.5",
946
+ h: "28px",
947
+ px: "2",
948
+ rounded: "md",
949
+ border: "1px solid",
950
+ borderColor: "line",
951
+ bg: "canvas",
952
+ color: "faint",
953
+ minW: "0",
954
+ _focusWithin: {
955
+ borderColor: "accent",
956
+ color: "muted"
957
+ }
958
+ }), className),
959
+ children: [
960
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconSearch, { size: 14 }),
961
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", {
962
+ ref,
963
+ type: "search",
964
+ spellCheck: false,
965
+ autoComplete: "off",
966
+ className: css({
967
+ flex: "1",
968
+ minW: "0",
969
+ border: "none",
970
+ outline: "none",
971
+ bg: "transparent",
972
+ color: "fg",
973
+ fontSize: "12px",
974
+ "&::placeholder": { color: "faint" },
975
+ "&::-webkit-search-cancel-button": { display: "none" }
976
+ }),
977
+ ...props
978
+ }),
979
+ shortcut ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Kbd, { children: shortcut }) : null
980
+ ]
981
+ });
982
+ });
983
+ function Kbd({ children }) {
984
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("kbd", {
985
+ className: css({
986
+ fontFamily: "mono",
987
+ fontSize: "10px",
988
+ color: "faint",
989
+ border: "1px solid",
990
+ borderColor: "line",
991
+ rounded: "xs",
992
+ px: "1",
993
+ lineHeight: "16px",
994
+ flexShrink: 0
995
+ }),
996
+ children
997
+ });
998
+ }
999
+ /** A number with a label under it — the header of every summary. */
1000
+ function Stat({ label, value, sub, tone }) {
1001
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
1002
+ className: css({
1003
+ display: "flex",
1004
+ flexDir: "column",
1005
+ gap: "0.5",
1006
+ px: "3.5",
1007
+ py: "2.5",
1008
+ rounded: "lg",
1009
+ border: "1px solid",
1010
+ borderColor: "line",
1011
+ bg: "raised",
1012
+ minW: "0"
1013
+ }),
1014
+ children: [
1015
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
1016
+ className: css({
1017
+ fontSize: "11px",
1018
+ color: "muted",
1019
+ fontWeight: "500"
1020
+ }),
1021
+ children: label
1022
+ }),
1023
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
1024
+ className: cx(css({
1025
+ fontSize: "20px",
1026
+ fontWeight: "600",
1027
+ fontVariantNumeric: "tabular-nums",
1028
+ lineHeight: "1.2"
1029
+ }), tone ? TONE_TEXT[tone] : void 0),
1030
+ children: value
1031
+ }),
1032
+ sub ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
1033
+ className: cx(css({ fontSize: "11px" }), faintText, truncate),
1034
+ children: sub
1035
+ }) : null
1036
+ ]
1037
+ });
1038
+ }
1039
+ function StatGrid({ children }) {
1040
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
1041
+ className: css({
1042
+ display: "grid",
1043
+ gridTemplateColumns: "repeat(auto-fill, minmax(150px, 1fr))",
1044
+ gap: "2.5"
1045
+ }),
1046
+ children
1047
+ });
1048
+ }
1049
+ function SectionTitle({ children, right }) {
1050
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
1051
+ className: css({
1052
+ display: "flex",
1053
+ alignItems: "center",
1054
+ gap: "2",
1055
+ mb: "2",
1056
+ mt: "1"
1057
+ }),
1058
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", {
1059
+ className: css({
1060
+ fontSize: "11px",
1061
+ fontWeight: "600",
1062
+ textTransform: "uppercase",
1063
+ letterSpacing: "0.06em",
1064
+ color: "muted",
1065
+ m: "0"
1066
+ }),
1067
+ children
1068
+ }), right ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
1069
+ className: css({ ml: "auto" }),
1070
+ children: right
1071
+ }) : null]
1072
+ });
1073
+ }
1074
+ function Card({ children, className }) {
1075
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
1076
+ className: cx(css({
1077
+ rounded: "lg",
1078
+ border: "1px solid",
1079
+ borderColor: "line",
1080
+ bg: "raised",
1081
+ overflow: "hidden"
1082
+ }), className),
1083
+ children
1084
+ });
1085
+ }
1086
+ function Callout({ tone, title, children, icon }) {
1087
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
1088
+ className: cx(css({
1089
+ display: "flex",
1090
+ gap: "2.5",
1091
+ px: "3",
1092
+ py: "2.5",
1093
+ rounded: "md",
1094
+ alignItems: "flex-start"
1095
+ }), TONE_PILL[tone]),
1096
+ children: [icon ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
1097
+ className: css({
1098
+ mt: "1px",
1099
+ flexShrink: 0
1100
+ }),
1101
+ children: icon
1102
+ }) : null, /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
1103
+ className: css({
1104
+ minW: "0",
1105
+ flex: "1"
1106
+ }),
1107
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
1108
+ className: css({ fontWeight: "600" }),
1109
+ children: title
1110
+ }), children ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
1111
+ className: css({
1112
+ color: "fg",
1113
+ mt: "0.5",
1114
+ wordBreak: "break-word"
1115
+ }),
1116
+ children
1117
+ }) : null]
1118
+ })]
1119
+ });
1120
+ }
1121
+ function Empty({ title, children, icon }) {
1122
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
1123
+ className: css({
1124
+ display: "flex",
1125
+ flexDir: "column",
1126
+ alignItems: "center",
1127
+ justifyContent: "center",
1128
+ textAlign: "center",
1129
+ gap: "1.5",
1130
+ px: "6",
1131
+ py: "10",
1132
+ color: "muted",
1133
+ h: "full",
1134
+ minH: "0"
1135
+ }),
1136
+ children: [
1137
+ icon ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
1138
+ className: css({
1139
+ color: "faint",
1140
+ mb: "1"
1141
+ }),
1142
+ children: icon
1143
+ }) : null,
1144
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
1145
+ className: css({
1146
+ fontWeight: "600",
1147
+ color: "fg",
1148
+ fontSize: "14px"
1149
+ }),
1150
+ children: title
1151
+ }),
1152
+ children ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
1153
+ className: css({ maxW: "440px" }),
1154
+ children
1155
+ }) : null
1156
+ ]
1157
+ });
1158
+ }
1159
+ /** A table style shared by every grid of rows in the app. */
1160
+ var table = css({
1161
+ w: "full",
1162
+ borderCollapse: "separate",
1163
+ borderSpacing: "0",
1164
+ fontSize: "12.5px",
1165
+ "& th": {
1166
+ position: "sticky",
1167
+ top: "0",
1168
+ zIndex: "1",
1169
+ bg: "chrome",
1170
+ textAlign: "left",
1171
+ fontWeight: "500",
1172
+ fontSize: "11px",
1173
+ color: "muted",
1174
+ px: "3",
1175
+ py: "1.5",
1176
+ borderBottom: "1px solid",
1177
+ borderColor: "line",
1178
+ whiteSpace: "nowrap"
1179
+ },
1180
+ "& td": {
1181
+ px: "3",
1182
+ py: "1.5",
1183
+ borderBottom: "1px solid",
1184
+ borderColor: "line",
1185
+ verticalAlign: "middle"
1186
+ },
1187
+ "& tbody tr": { cursor: "default" },
1188
+ "& tbody tr[data-link]": { cursor: "pointer" },
1189
+ "& tbody tr:hover td": { bg: "hover" },
1190
+ "& td.num, & th.num": {
1191
+ textAlign: "right",
1192
+ fontVariantNumeric: "tabular-nums",
1193
+ whiteSpace: "nowrap"
1194
+ }
1195
+ });
1196
+ /** A scrolling pane that fills its parent. */
1197
+ var scrollPane = css({
1198
+ flex: "1",
1199
+ minH: "0",
1200
+ minW: "0",
1201
+ overflow: "auto"
1202
+ });
1203
+ /** Padding for a page's scrolling content. */
1204
+ var pagePad = css({
1205
+ px: "5",
1206
+ py: "4",
1207
+ display: "flex",
1208
+ flexDir: "column",
1209
+ gap: "5"
1210
+ });
1211
+ function formatMs(ms) {
1212
+ if (ms == null) return "—";
1213
+ if (ms < 1) return `${ms.toFixed(2)} ms`;
1214
+ if (ms < 1e3) return `${Math.round(ms)} ms`;
1215
+ if (ms < 6e4) return `${(ms / 1e3).toFixed(2)} s`;
1216
+ return `${Math.floor(ms / 6e4)}m ${Math.round(ms % 6e4 / 1e3)}s`;
1217
+ }
1218
+ function formatBytes(bytes) {
1219
+ if (bytes == null) return "—";
1220
+ if (bytes < 1024) return `${bytes} B`;
1221
+ if (bytes < 1048576) return `${(bytes / 1024).toFixed(1)} kB`;
1222
+ if (bytes < 1073741824) return `${(bytes / 1048576).toFixed(1)} MB`;
1223
+ return `${(bytes / 1073741824).toFixed(2)} GB`;
1224
+ }
1225
+ function formatCount(n) {
1226
+ if (n == null) return "—";
1227
+ return n.toLocaleString("en-US");
1228
+ }
1229
+ /** `3 runs`, `1 run`. */
1230
+ function plural(n, noun, many = `${noun}s`) {
1231
+ return `${formatCount(n)} ${n === 1 ? noun : many}`;
1232
+ }
1233
+ var MONTHS = [
1234
+ "Jan",
1235
+ "Feb",
1236
+ "Mar",
1237
+ "Apr",
1238
+ "May",
1239
+ "Jun",
1240
+ "Jul",
1241
+ "Aug",
1242
+ "Sep",
1243
+ "Oct",
1244
+ "Nov",
1245
+ "Dec"
1246
+ ];
1247
+ var pad = (n, width = 2) => String(n).padStart(width, "0");
1248
+ /** `14:32:05`. */
1249
+ function formatClock(ms) {
1250
+ const d = new Date(ms);
1251
+ return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
1252
+ }
1253
+ /** `14:32:05.123` — for timelines where the millisecond is the point. */
1254
+ function formatClockMs(ms) {
1255
+ return `${formatClock(ms)}.${pad(new Date(ms).getMilliseconds(), 3)}`;
1256
+ }
1257
+ /** `2 Aug`, or `2 Aug 2025` once the year stops being obvious. */
1258
+ function formatDay(now, ms) {
1259
+ const d = new Date(ms);
1260
+ const day = `${d.getDate()} ${MONTHS[d.getMonth()]}`;
1261
+ return d.getFullYear() === new Date(now).getFullYear() ? day : `${day} ${d.getFullYear()}`;
1262
+ }
1263
+ /** `2 Aug, 14:32:05`. */
1264
+ function formatDateTime(now, ms) {
1265
+ return `${formatDay(now, ms)}, ${formatClock(ms)}`;
1266
+ }
1267
+ /** The heading a row sits under in a chronological list. */
1268
+ function formatDayHeading(now, ms) {
1269
+ const days = calendarDaysBetween(ms, now);
1270
+ if (days === 0) return "Today";
1271
+ if (days === 1) return "Yesterday";
1272
+ return formatDay(now, ms);
1273
+ }
1274
+ /** `4 min ago`; a date once "ago" stops being a useful answer. */
1275
+ function formatAgo(now, ms) {
1276
+ const seconds = Math.max(0, now - ms) / 1e3;
1277
+ if (seconds < 10) return "just now";
1278
+ if (seconds < 60) return `${Math.floor(seconds)} s ago`;
1279
+ const minutes = seconds / 60;
1280
+ if (minutes < 60) return `${Math.floor(minutes)} min ago`;
1281
+ const hours = minutes / 60;
1282
+ if (hours < 24) return `${Math.floor(hours)} h ago`;
1283
+ const days = calendarDaysBetween(ms, now);
1284
+ if (days < 7) return `${days} d ago`;
1285
+ return formatDay(now, ms);
1286
+ }
1287
+ /** `+1.24 s` — where something sits relative to the start of its run. */
1288
+ function formatOffset(ms) {
1289
+ return `+${formatMs(Math.max(0, ms))}`;
1290
+ }
1291
+ function calendarDaysBetween(from, to) {
1292
+ const a = new Date(from);
1293
+ const b = new Date(to);
1294
+ const start = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate());
1295
+ const end = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate());
1296
+ return Math.round((end - start) / 864e5);
1297
+ }
1298
+ /** `/Users/me/work/api/sync.ts` → `sync.ts`. */
1299
+ function basename(path) {
1300
+ const cut = path.lastIndexOf("/");
1301
+ return cut < 0 ? path : path.slice(cut + 1);
1302
+ }
1303
+ var tabKey = {
1304
+ overview: () => "overview",
1305
+ query: () => "query",
1306
+ run: (id) => `run:${id}`,
1307
+ request: (id) => `request:${id}`,
1308
+ script: (entry) => `script:${entry}`
1309
+ };
1310
+ var TabsContext = import_react.createContext(null);
1311
+ function useTabs() {
1312
+ const value = import_react.useContext(TabsContext);
1313
+ if (!value) throw new Error("useTabs outside TabsProvider");
1314
+ return value;
1315
+ }
1316
+ var STORAGE_KEY$1 = "wireui:tabs";
1317
+ /** A page's own tab. Call once at the top of a route component. */
1318
+ function useTab(tab) {
1319
+ const { register } = useTabs();
1320
+ const { key, title, icon, method, kind, failed } = tab;
1321
+ import_react.useEffect(() => {
1322
+ register({
1323
+ key,
1324
+ title,
1325
+ icon,
1326
+ method,
1327
+ kind,
1328
+ failed
1329
+ });
1330
+ }, [
1331
+ register,
1332
+ key,
1333
+ title,
1334
+ icon,
1335
+ method,
1336
+ kind,
1337
+ failed
1338
+ ]);
1339
+ }
1340
+ function TabsProvider({ children }) {
1341
+ const location = useLocation();
1342
+ const navigate = useNavigate();
1343
+ const [tabs, setTabs] = import_react.useState([]);
1344
+ const [activeKey, setActiveKey] = import_react.useState(null);
1345
+ const [loaded, setLoaded] = import_react.useState(false);
1346
+ const href = location.href;
1347
+ import_react.useEffect(() => {
1348
+ try {
1349
+ const raw = sessionStorage.getItem(STORAGE_KEY$1);
1350
+ if (raw) setTabs((current) => merge(JSON.parse(raw), current));
1351
+ } catch {}
1352
+ setLoaded(true);
1353
+ }, []);
1354
+ import_react.useEffect(() => {
1355
+ if (!loaded) return;
1356
+ try {
1357
+ sessionStorage.setItem(STORAGE_KEY$1, JSON.stringify(tabs));
1358
+ } catch {}
1359
+ }, [tabs, loaded]);
1360
+ import_react.useEffect(() => {
1361
+ if (!activeKey) return;
1362
+ setTabs((current) => current.map((t) => t.key === activeKey && t.href !== href ? {
1363
+ ...t,
1364
+ href
1365
+ } : t));
1366
+ }, [href, activeKey]);
1367
+ const register = import_react.useCallback((tab) => {
1368
+ setActiveKey(tab.key);
1369
+ setTabs((current) => {
1370
+ const existing = current.findIndex((t) => t.key === tab.key);
1371
+ if (existing >= 0) {
1372
+ const next = [...current];
1373
+ next[existing] = {
1374
+ ...next[existing],
1375
+ ...tab,
1376
+ href
1377
+ };
1378
+ return next;
1379
+ }
1380
+ const fresh = {
1381
+ ...tab,
1382
+ href,
1383
+ preview: true
1384
+ };
1385
+ const preview = current.findIndex((t) => t.preview);
1386
+ if (preview >= 0) {
1387
+ const next = [...current];
1388
+ next[preview] = fresh;
1389
+ return next;
1390
+ }
1391
+ return [...current, fresh];
1392
+ });
1393
+ }, [href]);
1394
+ const pin = import_react.useCallback((key) => {
1395
+ setTabs((current) => current.map((t) => t.key === key ? {
1396
+ ...t,
1397
+ preview: false
1398
+ } : t));
1399
+ }, []);
1400
+ const close = import_react.useCallback((key) => {
1401
+ const index = tabs.findIndex((t) => t.key === key);
1402
+ if (index < 0) return;
1403
+ const next = tabs.filter((t) => t.key !== key);
1404
+ setTabs(next);
1405
+ if (key === activeKey) {
1406
+ const neighbour = next[Math.min(index, next.length - 1)];
1407
+ if (!neighbour) setActiveKey(null);
1408
+ navigate({ href: neighbour?.href ?? "/" });
1409
+ }
1410
+ }, [
1411
+ tabs,
1412
+ activeKey,
1413
+ navigate
1414
+ ]);
1415
+ const closeOthers = import_react.useCallback((key) => {
1416
+ setTabs((current) => current.filter((t) => t.key === key));
1417
+ }, []);
1418
+ const value = import_react.useMemo(() => ({
1419
+ tabs,
1420
+ activeKey,
1421
+ register,
1422
+ pin,
1423
+ close,
1424
+ closeOthers
1425
+ }), [
1426
+ tabs,
1427
+ activeKey,
1428
+ register,
1429
+ pin,
1430
+ close,
1431
+ closeOthers
1432
+ ]);
1433
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TabsContext.Provider, {
1434
+ value,
1435
+ children
1436
+ });
1437
+ }
1438
+ /** Stored tabs first, then any the current page registered before they loaded. */
1439
+ function merge(stored, current) {
1440
+ const valid = Array.isArray(stored) ? stored.filter((t) => t && typeof t.key === "string" && typeof t.href === "string") : [];
1441
+ const keys = new Set(valid.map((t) => t.key));
1442
+ const extra = current.filter((t) => !keys.has(t.key));
1443
+ const merged = [...valid, ...extra];
1444
+ let seenPreview = false;
1445
+ return merged.toReversed().map((t) => {
1446
+ if (!t.preview) return t;
1447
+ if (seenPreview) return {
1448
+ ...t,
1449
+ preview: false
1450
+ };
1451
+ seenPreview = true;
1452
+ return t;
1453
+ }).toReversed();
1454
+ }
1455
+ var createSsrRpc = (functionId) => {
1456
+ const url = "/_serverFn/" + functionId;
1457
+ const serverFnMeta = { id: functionId };
1458
+ const fn = async (...args) => {
1459
+ return (await getServerFnById(functionId, { origin: "server" }))(...args);
1460
+ };
1461
+ return Object.assign(fn, {
1462
+ url,
1463
+ serverFnMeta,
1464
+ [TSS_SERVER_FUNCTION]: true
1465
+ });
1466
+ };
1467
+ function record(input) {
1468
+ return input && typeof input === "object" ? input : {};
1469
+ }
1470
+ function id(value, name) {
1471
+ const n = typeof value === "string" ? Number(value) : value;
1472
+ if (typeof n !== "number" || !Number.isInteger(n) || n <= 0) throw new Error(`${name} must be a positive integer`);
1473
+ return n;
1474
+ }
1475
+ function optionalString(value) {
1476
+ return typeof value === "string" ? value : void 0;
1477
+ }
1478
+ /** `undefined` → every environment, `null` → runs recorded without one. */
1479
+ function env(value) {
1480
+ if (value === null) return null;
1481
+ return typeof value === "string" ? value : void 0;
1482
+ }
1483
+ /** The open database when its schema is one these queries can read, else null. */
1484
+ /** Runs the sidebar holds. Older ones stay reachable from their script's page. */
1485
+ var getWorkspace = createServerFn({ method: "GET" }).handler(createSsrRpc("65bc418eb60581304ebde68d2b8b775b58aa758789bcdd2e616a2bdd5657ef20"));
1486
+ var getOverview = createServerFn({ method: "GET" }).validator((input) => ({ env: env(record(input).env) })).handler(createSsrRpc("edb0cb28f3af0347a499a4c076ecc5f8247f0ace0fb524957f40f6a706d7224d"));
1487
+ var getHistory = createServerFn({ method: "GET" }).validator((input) => {
1488
+ const r = record(input);
1489
+ const kind = r.kind === "http" || r.kind === "stream" ? r.kind : void 0;
1490
+ return {
1491
+ q: optionalString(r.q),
1492
+ env: env(r.env),
1493
+ kind,
1494
+ failed: r.failed === true,
1495
+ bodies: r.bodies === true,
1496
+ limit: typeof r.limit === "number" ? r.limit : void 0
1497
+ };
1498
+ }).handler(createSsrRpc("c1e4e973ed505d1515bcb9192482c65b1680975a5daa6973befb704515a618e3"));
1499
+ var getScript = createServerFn({ method: "GET" }).validator((input) => {
1500
+ const r = record(input);
1501
+ const entry = optionalString(r.entry);
1502
+ if (!entry) throw new Error("entry is required");
1503
+ return {
1504
+ entry,
1505
+ env: env(r.env)
1506
+ };
1507
+ }).handler(createSsrRpc("5eff62884e56f81742c81b44dc7dcd1afc2e67323a30591a8b94b8895eda0dc9"));
1508
+ /** A run's requests, in capture order. The sidebar tree loads these on expand. */
1509
+ var getRunRequests = createServerFn({ method: "GET" }).validator((input) => ({ runId: id(record(input).runId, "runId") })).handler(createSsrRpc("3828e982aebdd19568d199b4820f9fb3ca9fab2c60ce502ee35e3f6075d422c9"));
1510
+ var getRun = createServerFn({ method: "GET" }).validator((input) => ({ runId: id(record(input).runId, "runId") })).handler(createSsrRpc("56c165307cd91159eb72bfa882932f9552f05a5bbd6b5725f0fd5f4ad6b8295d"));
1511
+ var getRequest = createServerFn({ method: "GET" }).validator((input) => ({ requestId: id(record(input).requestId, "requestId") })).handler(createSsrRpc("3772b5ea3e53d85a63e4df11f128b1c907e508d82cca6e71e6ee48dba1664133"));
1512
+ var getSchema = createServerFn({ method: "GET" }).handler(createSsrRpc("06ff3639e7164884f56665ea621dc233dbfc78fa1557b1cb20105ff2fa90521e"));
1513
+ var runSql = createServerFn({ method: "POST" }).validator((input) => {
1514
+ const sql = optionalString(record(input).sql)?.trim();
1515
+ if (!sql) throw new Error("sql is required");
1516
+ return { sql };
1517
+ }).handler(createSsrRpc("0f45629470ab3fbe618e9693d8685920d6ce48b2384512e5d9eb88f6b46ec2d9"));
1518
+ //#endregion
1519
+ //#region node_modules/.nitro/vite/services/ssr/assets/router-CPcgc_kh.js
1520
+ var __defProp = Object.defineProperty;
1521
+ var __exportAll = (all, no_symbols) => {
1522
+ let target = {};
1523
+ for (var name in all) __defProp(target, name, {
1524
+ get: all[name],
1525
+ enumerable: true
1526
+ });
1527
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
1528
+ return target;
1529
+ };
1530
+ var root$4 = getRouteApi("__root__");
1531
+ var command = cx(mono, css({
1532
+ display: "block",
1533
+ textAlign: "left",
1534
+ bg: "well",
1535
+ border: "1px solid",
1536
+ borderColor: "line",
1537
+ rounded: "md",
1538
+ px: "3",
1539
+ py: "2",
1540
+ mt: "3",
1541
+ whiteSpace: "pre-wrap"
1542
+ }));
1543
+ function NotFound() {
1544
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Empty, {
1545
+ title: "Nothing here",
1546
+ children: [
1547
+ "That run or request is not in this recording — it may be from another file.",
1548
+ " ",
1549
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Link, {
1550
+ to: "/",
1551
+ className: css({ color: "accent" }),
1552
+ children: "Back to the overview"
1553
+ })
1554
+ ]
1555
+ });
1556
+ }
1557
+ function RouteError({ error }) {
1558
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Empty, {
1559
+ title: "Something went wrong reading the recording",
1560
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconAlert, { size: 22 }),
1561
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", {
1562
+ className: cx(command, css({ color: "bad" })),
1563
+ children: error instanceof Error ? error.message : String(error)
1564
+ })
1565
+ });
1566
+ }
1567
+ /**
1568
+ * What stands in for every page while there is nothing it could show: no file
1569
+ * yet, or a file on a schema these queries cannot read. Null otherwise, so a
1570
+ * page returns it early without knowing which case applies.
1571
+ */
1572
+ function useUnreadable() {
1573
+ const ws = root$4.useLoaderData();
1574
+ if (ws.schema.state === "missing") return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Empty, {
1575
+ title: "No recording yet",
1576
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconDatabase, { size: 24 }),
1577
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
1578
+ className: css({ m: "0" }),
1579
+ children: [
1580
+ "wireui is reading ",
1581
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
1582
+ className: mono,
1583
+ children: ws.path
1584
+ }),
1585
+ ", which has nothing in it yet. Record a script and it appears here — turn on ",
1586
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("b", { children: "Live" }),
1587
+ " to watch it land."
1588
+ ]
1589
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", {
1590
+ className: command,
1591
+ children: "wire execute ./scripts/sync.ts"
1592
+ })]
1593
+ });
1594
+ if (ws.schema.state === "stale") return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Empty, {
1595
+ title: "This recording is older than wireui",
1596
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconAlert, { size: 22 }),
1597
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
1598
+ className: css({ m: "0" }),
1599
+ children: [
1600
+ "The file is on schema version ",
1601
+ ws.schema.file,
1602
+ "; this build reads version",
1603
+ " ",
1604
+ ws.schema.expected,
1605
+ ". wireui opens files read-only, so it cannot upgrade it. Recording a run into it with the current CLI does:"
1606
+ ]
1607
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", {
1608
+ className: command,
1609
+ children: `wire execute ./scripts/sync.ts --db ${ws.path}`
1610
+ })]
1611
+ });
1612
+ return null;
1613
+ }
1614
+ var DEFAULTS = {
1615
+ theme: "system",
1616
+ env: "*",
1617
+ layout: "side",
1618
+ sidebarWidth: 300,
1619
+ sidebarOpen: true,
1620
+ panel: "collections",
1621
+ live: false
1622
+ };
1623
+ var STORAGE_KEY = "wireui:prefs";
1624
+ /** The server-side value of an environment selection. */
1625
+ function envFilter(env) {
1626
+ if (env === "*") return void 0;
1627
+ return env === "" ? null : env;
1628
+ }
1629
+ /** Whether a run belongs to the selected environment. */
1630
+ function matchesEnv(env, runEnv) {
1631
+ if (env === "*") return true;
1632
+ return env === "" ? runEnv == null : runEnv === env;
1633
+ }
1634
+ var PrefsContext = import_react.createContext(null);
1635
+ function usePrefs() {
1636
+ const value = import_react.useContext(PrefsContext);
1637
+ if (!value) throw new Error("usePrefs outside PrefsProvider");
1638
+ return value;
1639
+ }
1640
+ /** How often Live re-reads the file. A local SQLite read; this is cheap. */
1641
+ var LIVE_INTERVAL_MS = 2e3;
1642
+ function PrefsProvider({ children }) {
1643
+ const router = useRouter();
1644
+ const [prefs, setPrefs] = import_react.useState(DEFAULTS);
1645
+ const [loaded, setLoaded] = import_react.useState(false);
1646
+ const [refreshKey, setRefreshKey] = import_react.useState(0);
1647
+ const [lastRefresh, setLastRefresh] = import_react.useState(null);
1648
+ import_react.useEffect(() => {
1649
+ setPrefs((current) => ({
1650
+ ...current,
1651
+ ...readStored()
1652
+ }));
1653
+ setLoaded(true);
1654
+ }, []);
1655
+ import_react.useEffect(() => {
1656
+ if (!loaded) return;
1657
+ try {
1658
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(prefs));
1659
+ } catch {}
1660
+ }, [prefs, loaded]);
1661
+ import_react.useEffect(() => applyTheme(prefs.theme), [prefs.theme]);
1662
+ const set = import_react.useCallback((key, value) => {
1663
+ setPrefs((current) => ({
1664
+ ...current,
1665
+ [key]: value
1666
+ }));
1667
+ }, []);
1668
+ const refresh = import_react.useCallback(() => {
1669
+ router.invalidate();
1670
+ setRefreshKey((k) => k + 1);
1671
+ setLastRefresh(Date.now());
1672
+ }, [router]);
1673
+ import_react.useEffect(() => {
1674
+ if (!prefs.live) return;
1675
+ const timer = window.setInterval(() => {
1676
+ if (document.visibilityState === "visible") refresh();
1677
+ }, LIVE_INTERVAL_MS);
1678
+ return () => window.clearInterval(timer);
1679
+ }, [prefs.live, refresh]);
1680
+ import_react.useEffect(() => {
1681
+ const onVisible = () => {
1682
+ if (document.visibilityState === "visible") refresh();
1683
+ };
1684
+ window.addEventListener("focus", onVisible);
1685
+ document.addEventListener("visibilitychange", onVisible);
1686
+ return () => {
1687
+ window.removeEventListener("focus", onVisible);
1688
+ document.removeEventListener("visibilitychange", onVisible);
1689
+ };
1690
+ }, [refresh]);
1691
+ const value = import_react.useMemo(() => ({
1692
+ prefs,
1693
+ set,
1694
+ refreshKey,
1695
+ refresh,
1696
+ lastRefresh
1697
+ }), [
1698
+ prefs,
1699
+ set,
1700
+ refreshKey,
1701
+ refresh,
1702
+ lastRefresh
1703
+ ]);
1704
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PrefsContext.Provider, {
1705
+ value,
1706
+ children
1707
+ });
1708
+ }
1709
+ function readStored() {
1710
+ try {
1711
+ const raw = localStorage.getItem(STORAGE_KEY);
1712
+ if (!raw) return {};
1713
+ const parsed = JSON.parse(raw);
1714
+ return typeof parsed === "object" && parsed ? parsed : {};
1715
+ } catch {
1716
+ return {};
1717
+ }
1718
+ }
1719
+ function applyTheme(theme) {
1720
+ const media = window.matchMedia("(prefers-color-scheme: dark)");
1721
+ const apply = () => {
1722
+ const dark = theme === "dark" || theme === "system" && media.matches;
1723
+ document.documentElement.dataset.theme = dark ? "dark" : "light";
1724
+ };
1725
+ apply();
1726
+ if (theme !== "system") return;
1727
+ media.addEventListener("change", apply);
1728
+ return () => media.removeEventListener("change", apply);
1729
+ }
1730
+ /**
1731
+ * Runs before first paint, inlined into <head>, so a dark-mode viewer never sees
1732
+ * a white flash while React loads. Mirrors {@link applyTheme}.
1733
+ */
1734
+ var THEME_BOOT_SCRIPT = `(function(){try{var p=JSON.parse(localStorage.getItem(${JSON.stringify(STORAGE_KEY)})||"{}").theme||"system";var d=p==="dark"||(p==="system"&&matchMedia("(prefers-color-scheme: dark)").matches);document.documentElement.dataset.theme=d?"dark":"light"}catch(e){document.documentElement.dataset.theme="light"}})()`;
1735
+ /** A clock that ticks, for "4 min ago", starting from the server's time. */
1736
+ function useNow(initial, intervalMs = 15e3) {
1737
+ const [now, setNow] = import_react.useState(initial);
1738
+ import_react.useEffect(() => {
1739
+ setNow(Date.now());
1740
+ const timer = window.setInterval(() => setNow(Date.now()), intervalMs);
1741
+ return () => window.clearInterval(timer);
1742
+ }, [intervalMs]);
1743
+ return now;
1744
+ }
1745
+ function useActive() {
1746
+ return useRouterState({
1747
+ select: (state) => {
1748
+ const active = {
1749
+ entry: null,
1750
+ runId: null,
1751
+ requestId: null
1752
+ };
1753
+ for (const match of state.matches) {
1754
+ const data = match.loaderData;
1755
+ if (!data || typeof data !== "object") continue;
1756
+ if (data.run) {
1757
+ active.runId = data.run.id;
1758
+ active.entry = data.run.entry;
1759
+ }
1760
+ if (data.script) active.entry = data.script.entry;
1761
+ if (data.detail) active.requestId = data.detail.request.id;
1762
+ }
1763
+ return active;
1764
+ },
1765
+ structuralSharing: true
1766
+ });
1767
+ }
1768
+ var root$3 = getRouteApi("__root__");
1769
+ /** Runs shown under a script before "show more". */
1770
+ var RUNS_SHOWN = 8;
1771
+ var treeRow = css({
1772
+ display: "flex",
1773
+ alignItems: "center",
1774
+ gap: "1.5",
1775
+ h: "26px",
1776
+ pr: "2",
1777
+ rounded: "sm",
1778
+ cursor: "pointer",
1779
+ color: "fg",
1780
+ textDecoration: "none",
1781
+ userSelect: "none",
1782
+ minW: "0",
1783
+ _hover: { bg: "hover" },
1784
+ "&[data-active=true]": { bg: "selected" }
1785
+ });
1786
+ var chevron = css({
1787
+ display: "inline-flex",
1788
+ alignItems: "center",
1789
+ justifyContent: "center",
1790
+ w: "16px",
1791
+ h: "16px",
1792
+ color: "faint",
1793
+ flexShrink: 0,
1794
+ rounded: "xs",
1795
+ border: "none",
1796
+ bg: "transparent",
1797
+ p: "0",
1798
+ cursor: "pointer",
1799
+ _hover: {
1800
+ color: "fg",
1801
+ bg: "hover"
1802
+ }
1803
+ });
1804
+ function CollectionsPanel({ filterRef }) {
1805
+ const ws = root$3.useLoaderData();
1806
+ const { prefs } = usePrefs();
1807
+ const active = useActive();
1808
+ const [filter, setFilter] = import_react.useState("");
1809
+ const [open, setOpen] = import_react.useState(() => /* @__PURE__ */ new Set());
1810
+ import_react.useEffect(() => {
1811
+ const keys = [active.entry ? `s:${active.entry}` : null, active.runId ? `r:${active.runId}` : null].filter((k) => k != null);
1812
+ if (keys.length === 0) return;
1813
+ setOpen((current) => keys.every((k) => current.has(k)) ? current : /* @__PURE__ */ new Set([...current, ...keys]));
1814
+ }, [active.entry, active.runId]);
1815
+ const toggle = import_react.useCallback((key, force) => {
1816
+ setOpen((current) => {
1817
+ const next = new Set(current);
1818
+ if (force ?? !next.has(key)) next.add(key);
1819
+ else next.delete(key);
1820
+ return next;
1821
+ });
1822
+ }, []);
1823
+ const runsByEntry = import_react.useMemo(() => {
1824
+ const map = /* @__PURE__ */ new Map();
1825
+ for (const run of ws.runs) {
1826
+ if (!matchesEnv(prefs.env, run.env)) continue;
1827
+ const list = map.get(run.entry) ?? [];
1828
+ list.push(run);
1829
+ map.set(run.entry, list);
1830
+ }
1831
+ return map;
1832
+ }, [ws.runs, prefs.env]);
1833
+ const needle = filter.trim().toLowerCase();
1834
+ const groups = import_react.useMemo(() => {
1835
+ const byDir = /* @__PURE__ */ new Map();
1836
+ for (const script of ws.scripts) {
1837
+ if (!runsByEntry.has(script.entry)) continue;
1838
+ if (needle && !script.rel.toLowerCase().includes(needle) && !(script.label ?? "").toLowerCase().includes(needle)) continue;
1839
+ const list = byDir.get(script.dir) ?? [];
1840
+ list.push(script);
1841
+ byDir.set(script.dir, list);
1842
+ }
1843
+ return [...byDir.entries()];
1844
+ }, [
1845
+ ws.scripts,
1846
+ runsByEntry,
1847
+ needle
1848
+ ]);
1849
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
1850
+ className: css({
1851
+ display: "flex",
1852
+ flexDir: "column",
1853
+ h: "full",
1854
+ minH: "0"
1855
+ }),
1856
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
1857
+ className: css({
1858
+ px: "2.5",
1859
+ pb: "2",
1860
+ flexShrink: 0
1861
+ }),
1862
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FilterInput, {
1863
+ ref: filterRef,
1864
+ placeholder: "Filter collections",
1865
+ shortcut: "/",
1866
+ value: filter,
1867
+ onChange: (e) => setFilter(e.target.value)
1868
+ })
1869
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
1870
+ className: css({
1871
+ flex: "1",
1872
+ minH: "0",
1873
+ overflow: "auto",
1874
+ px: "1.5",
1875
+ pb: "3"
1876
+ }),
1877
+ children: groups.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Empty, {
1878
+ title: ws.scripts.length === 0 ? "No collections yet" : "No matches",
1879
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconCollections, { size: 20 }),
1880
+ children: ws.scripts.length === 0 ? "Every script you record with wire execute becomes a collection here." : "No script matches the filter in this environment."
1881
+ }) : groups.map(([dir, scripts]) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
1882
+ className: css({ mb: "2" }),
1883
+ children: [dir ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
1884
+ title: dir,
1885
+ className: cx(truncate, css({
1886
+ fontSize: "10.5px",
1887
+ color: "faint",
1888
+ px: "2",
1889
+ pt: "1.5",
1890
+ pb: "0.5",
1891
+ fontFamily: "mono"
1892
+ })),
1893
+ children: dir
1894
+ }) : null, scripts.map((script) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ScriptNode, {
1895
+ script,
1896
+ runs: runsByEntry.get(script.entry) ?? [],
1897
+ open,
1898
+ toggle,
1899
+ active
1900
+ }, script.entry))]
1901
+ }, dir))
1902
+ })]
1903
+ });
1904
+ }
1905
+ function ScriptNode({ script, runs, open, toggle, active }) {
1906
+ const { pin } = useTabs();
1907
+ const key = `s:${script.entry}`;
1908
+ const expanded = open.has(key);
1909
+ const [showAll, setShowAll] = import_react.useState(false);
1910
+ const failing = runs[0] ? runTone(runs[0]) === "bad" : false;
1911
+ const shown = showAll ? runs : runs.slice(0, RUNS_SHOWN);
1912
+ const isActive = active.entry === script.entry && active.runId == null;
1913
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Link, {
1914
+ to: "/collections",
1915
+ search: { entry: script.entry },
1916
+ "data-active": isActive,
1917
+ className: cx(treeRow, css({ pl: "1" })),
1918
+ onClick: () => toggle(key, true),
1919
+ onDoubleClick: () => pin(tabKey.script(script.entry)),
1920
+ title: script.rel,
1921
+ children: [
1922
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
1923
+ role: "button",
1924
+ tabIndex: -1,
1925
+ className: chevron,
1926
+ "aria-label": expanded ? "Collapse" : "Expand",
1927
+ onClick: (e) => {
1928
+ e.preventDefault();
1929
+ e.stopPropagation();
1930
+ toggle(key);
1931
+ },
1932
+ children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconChevronDown, { size: 12 }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconChevronRight, { size: 12 })
1933
+ }),
1934
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
1935
+ className: css({
1936
+ color: "muted",
1937
+ display: "inline-flex"
1938
+ }),
1939
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconCollections, { size: 14 })
1940
+ }),
1941
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
1942
+ className: cx(truncate, css({
1943
+ flex: "1",
1944
+ fontWeight: "500"
1945
+ })),
1946
+ children: script.file
1947
+ }),
1948
+ failing ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Dot, {
1949
+ tone: "bad",
1950
+ title: "Latest run failed"
1951
+ }) : null,
1952
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
1953
+ className: css({
1954
+ fontSize: "11px",
1955
+ color: "faint",
1956
+ fontVariantNumeric: "tabular-nums"
1957
+ }),
1958
+ children: runs.length
1959
+ })
1960
+ ]
1961
+ }), expanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [shown.map((run) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RunNode, {
1962
+ run,
1963
+ open,
1964
+ toggle,
1965
+ active
1966
+ }, run.id)), runs.length > shown.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
1967
+ type: "button",
1968
+ onClick: () => setShowAll(true),
1969
+ className: cx(treeRow, css({
1970
+ pl: "9",
1971
+ border: "none",
1972
+ bg: "transparent",
1973
+ w: "full",
1974
+ color: "accent",
1975
+ fontSize: "12px"
1976
+ })),
1977
+ children: [
1978
+ "Show ",
1979
+ runs.length - shown.length,
1980
+ " older runs"
1981
+ ]
1982
+ }) : null] }) : null] });
1983
+ }
1984
+ function RunNode({ run, open, toggle, active }) {
1985
+ const now = useNow(root$3.useLoaderData().now, 6e4);
1986
+ const { pin } = useTabs();
1987
+ const key = `r:${run.id}`;
1988
+ const expanded = open.has(key);
1989
+ const isActive = active.runId === run.id && active.requestId == null;
1990
+ const day = formatDayHeading(now, run.started_at);
1991
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Link, {
1992
+ to: "/runs/$runId",
1993
+ params: { runId: String(run.id) },
1994
+ "data-active": isActive,
1995
+ className: cx(treeRow, css({ pl: "5" })),
1996
+ onClick: () => toggle(key, true),
1997
+ onDoubleClick: () => pin(tabKey.run(run.id)),
1998
+ title: `Run ${run.id}${run.label ? ` · ${run.label}` : ""}`,
1999
+ children: [
2000
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2001
+ role: "button",
2002
+ tabIndex: -1,
2003
+ className: chevron,
2004
+ "aria-label": expanded ? "Collapse" : "Expand",
2005
+ onClick: (e) => {
2006
+ e.preventDefault();
2007
+ e.stopPropagation();
2008
+ toggle(key);
2009
+ },
2010
+ children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconChevronDown, { size: 12 }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconChevronRight, { size: 12 })
2011
+ }),
2012
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Dot, { tone: runTone(run) }),
2013
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
2014
+ className: cx(truncate, css({ flex: "1" })),
2015
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2016
+ className: css({ color: "muted" }),
2017
+ children: day === "Today" ? "" : `${day} `
2018
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2019
+ className: mono,
2020
+ children: formatClock(run.started_at)
2021
+ })]
2022
+ }),
2023
+ run.env ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Pill, { children: run.env }) : null,
2024
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2025
+ className: cx(mono, css({
2026
+ fontSize: "11px",
2027
+ color: "faint"
2028
+ })),
2029
+ children: run.finished_at ? formatMs(run.finished_at - run.started_at) : "…"
2030
+ })
2031
+ ]
2032
+ }), expanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RunRequests, {
2033
+ runId: run.id,
2034
+ activeRequestId: active.requestId
2035
+ }) : null] });
2036
+ }
2037
+ /** Module-level, so collapsing and re-expanding a run does not refetch it. */
2038
+ var requestCache = /* @__PURE__ */ new Map();
2039
+ function RunRequests({ runId, activeRequestId }) {
2040
+ const { refreshKey } = usePrefs();
2041
+ const { pin } = useTabs();
2042
+ const cached = requestCache.get(runId);
2043
+ const [rows, setRows] = import_react.useState(cached?.rows ?? null);
2044
+ import_react.useEffect(() => {
2045
+ if (cached && cached.key === refreshKey) return;
2046
+ let cancelled = false;
2047
+ getRunRequests({ data: { runId } }).then((result) => {
2048
+ requestCache.set(runId, {
2049
+ key: refreshKey,
2050
+ rows: result
2051
+ });
2052
+ if (!cancelled) setRows(result);
2053
+ });
2054
+ return () => {
2055
+ cancelled = true;
2056
+ };
2057
+ }, [
2058
+ runId,
2059
+ refreshKey,
2060
+ cached
2061
+ ]);
2062
+ if (rows == null) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
2063
+ className: css({
2064
+ pl: "12",
2065
+ h: "26px",
2066
+ color: "faint",
2067
+ fontSize: "12px",
2068
+ display: "flex",
2069
+ alignItems: "center"
2070
+ }),
2071
+ children: "Loading…"
2072
+ });
2073
+ if (rows.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
2074
+ className: css({
2075
+ pl: "12",
2076
+ h: "26px",
2077
+ color: "faint",
2078
+ fontSize: "12px",
2079
+ display: "flex",
2080
+ alignItems: "center"
2081
+ }),
2082
+ children: "No requests"
2083
+ });
2084
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Link, {
2085
+ to: "/requests/$requestId",
2086
+ params: { requestId: String(row.id) },
2087
+ "data-active": row.id === activeRequestId,
2088
+ onDoubleClick: () => pin(tabKey.request(row.id)),
2089
+ className: cx(treeRow, css({ pl: "10" })),
2090
+ title: `${row.method} ${row.host}${row.path}`,
2091
+ children: [
2092
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MethodBadge, {
2093
+ method: row.method,
2094
+ kind: row.kind,
2095
+ width: "list"
2096
+ }),
2097
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2098
+ className: cx(truncate, mono, css({ flex: "1" })),
2099
+ children: row.path
2100
+ }),
2101
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusBadge, {
2102
+ status: row.status,
2103
+ error: row.error_name
2104
+ })
2105
+ ]
2106
+ }, row.id)) });
2107
+ }
2108
+ var root$2 = getRouteApi("__root__");
2109
+ function EnvironmentsPanel() {
2110
+ const ws = root$2.useLoaderData();
2111
+ const now = useNow(ws.now, 6e4);
2112
+ const { prefs, set } = usePrefs();
2113
+ const totalRuns = ws.envs.reduce((sum, e) => sum + e.run_count, 0);
2114
+ if (ws.envs.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Empty, {
2115
+ title: "No environments",
2116
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconEnvironments, { size: 20 }),
2117
+ children: [
2118
+ "Runs made with ",
2119
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: "wire execute --env staging" }),
2120
+ " are grouped here."
2121
+ ]
2122
+ });
2123
+ const rows = [{
2124
+ value: "*",
2125
+ name: "All environments",
2126
+ sub: plural(totalRuns, "run"),
2127
+ failed: 0
2128
+ }, ...ws.envs.map((e) => ({
2129
+ value: e.env ?? "",
2130
+ name: e.env ?? "No environment",
2131
+ sub: `${plural(e.run_count, "run")} · ${plural(e.script_count, "script")} · ${formatAgo(now, e.last_started_at)}`,
2132
+ failed: e.failed_run_count
2133
+ }))];
2134
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
2135
+ className: css({
2136
+ px: "1.5",
2137
+ overflow: "auto",
2138
+ h: "full"
2139
+ }),
2140
+ children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
2141
+ type: "button",
2142
+ "data-active": prefs.env === row.value,
2143
+ onClick: () => set("env", row.value),
2144
+ className: cx(treeRow, css({
2145
+ h: "auto",
2146
+ py: "1.5",
2147
+ pl: "2",
2148
+ w: "full",
2149
+ border: "none",
2150
+ bg: "transparent",
2151
+ textAlign: "left"
2152
+ })),
2153
+ children: [
2154
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2155
+ className: css({
2156
+ color: prefs.env === row.value ? "accent" : "faint",
2157
+ display: "inline-flex"
2158
+ }),
2159
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconEnvironments, { size: 14 })
2160
+ }),
2161
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
2162
+ className: css({
2163
+ flex: "1",
2164
+ minW: "0",
2165
+ display: "flex",
2166
+ flexDir: "column"
2167
+ }),
2168
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2169
+ className: cx(truncate, css({ fontWeight: "500" })),
2170
+ children: row.name
2171
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2172
+ className: cx(truncate, css({
2173
+ fontSize: "11px",
2174
+ color: "faint"
2175
+ })),
2176
+ children: row.sub
2177
+ })]
2178
+ }),
2179
+ row.failed > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Dot, {
2180
+ tone: "bad",
2181
+ title: `${plural(row.failed, "run")} threw`
2182
+ }) : null
2183
+ ]
2184
+ }, row.value))
2185
+ });
2186
+ }
2187
+ var root$1 = getRouteApi("__root__");
2188
+ function HistoryPanel({ filterRef }) {
2189
+ const now = useNow(root$1.useLoaderData().now, 6e4);
2190
+ const { prefs, refreshKey } = usePrefs();
2191
+ const { pin } = useTabs();
2192
+ const active = useActive();
2193
+ const [q, setQ] = import_react.useState("");
2194
+ const [kind, setKind] = import_react.useState("all");
2195
+ const [failed, setFailed] = import_react.useState(false);
2196
+ const [bodies, setBodies] = import_react.useState(false);
2197
+ const [rows, setRows] = import_react.useState(null);
2198
+ const debounced = useDebounced(q, 180);
2199
+ import_react.useEffect(() => {
2200
+ let cancelled = false;
2201
+ getHistory({ data: {
2202
+ q: debounced,
2203
+ env: envFilter(prefs.env),
2204
+ kind: kind === "all" ? void 0 : kind,
2205
+ failed,
2206
+ bodies,
2207
+ limit: 500
2208
+ } }).then((result) => {
2209
+ if (!cancelled) setRows(result);
2210
+ });
2211
+ return () => {
2212
+ cancelled = true;
2213
+ };
2214
+ }, [
2215
+ debounced,
2216
+ kind,
2217
+ failed,
2218
+ bodies,
2219
+ prefs.env,
2220
+ refreshKey
2221
+ ]);
2222
+ const grouped = import_react.useMemo(() => {
2223
+ const out = [];
2224
+ for (const row of rows ?? []) {
2225
+ const day = formatDayHeading(now, row.ts);
2226
+ const last = out[out.length - 1];
2227
+ if (last && last.day === day) last.rows.push(row);
2228
+ else out.push({
2229
+ day,
2230
+ rows: [row]
2231
+ });
2232
+ }
2233
+ return out;
2234
+ }, [rows, now]);
2235
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
2236
+ className: css({
2237
+ display: "flex",
2238
+ flexDir: "column",
2239
+ h: "full",
2240
+ minH: "0"
2241
+ }),
2242
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
2243
+ className: css({
2244
+ px: "2.5",
2245
+ pb: "2",
2246
+ display: "flex",
2247
+ flexDir: "column",
2248
+ gap: "1.5",
2249
+ flexShrink: 0
2250
+ }),
2251
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FilterInput, {
2252
+ ref: filterRef,
2253
+ placeholder: bodies ? "Search URLs and payloads" : "Search URL, method or status",
2254
+ shortcut: "/",
2255
+ value: q,
2256
+ onChange: (e) => setQ(e.target.value)
2257
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
2258
+ className: css({
2259
+ display: "flex",
2260
+ alignItems: "center",
2261
+ gap: "1.5",
2262
+ flexWrap: "wrap"
2263
+ }),
2264
+ children: [
2265
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Segmented, {
2266
+ items: [
2267
+ {
2268
+ id: "all",
2269
+ label: "All"
2270
+ },
2271
+ {
2272
+ id: "http",
2273
+ label: "HTTP"
2274
+ },
2275
+ {
2276
+ id: "stream",
2277
+ label: "WS/SSE"
2278
+ }
2279
+ ],
2280
+ value: kind,
2281
+ onSelect: setKind
2282
+ }),
2283
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Toggle, {
2284
+ checked: failed,
2285
+ onChange: setFailed,
2286
+ label: "Failed"
2287
+ }),
2288
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Toggle, {
2289
+ checked: bodies,
2290
+ onChange: setBodies,
2291
+ label: "In payloads"
2292
+ })
2293
+ ]
2294
+ })]
2295
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
2296
+ className: css({
2297
+ flex: "1",
2298
+ minH: "0",
2299
+ overflow: "auto",
2300
+ px: "1.5",
2301
+ pb: "3"
2302
+ }),
2303
+ children: rows == null ? null : rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Empty, {
2304
+ title: "No requests",
2305
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconHistory, { size: 20 }),
2306
+ children: q || failed || kind !== "all" ? "Nothing matches these filters." : "Nothing recorded in this environment yet."
2307
+ }) : grouped.map((group) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
2308
+ className: css({
2309
+ position: "sticky",
2310
+ top: "0",
2311
+ zIndex: "1",
2312
+ bg: "chrome",
2313
+ fontSize: "10.5px",
2314
+ fontWeight: "600",
2315
+ textTransform: "uppercase",
2316
+ letterSpacing: "0.06em",
2317
+ color: "faint",
2318
+ px: "2",
2319
+ pt: "2",
2320
+ pb: "1"
2321
+ }),
2322
+ children: group.day
2323
+ }), group.rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Link, {
2324
+ to: "/requests/$requestId",
2325
+ params: { requestId: String(row.id) },
2326
+ "data-active": row.id === active.requestId,
2327
+ onDoubleClick: () => pin(tabKey.request(row.id)),
2328
+ className: cx(treeRow, css({
2329
+ h: "auto",
2330
+ py: "1",
2331
+ pl: "2",
2332
+ alignItems: "flex-start"
2333
+ })),
2334
+ title: `${row.method} ${row.host}${row.path}${row.query ? `?${row.query}` : ""}`,
2335
+ children: [
2336
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2337
+ className: css({ pt: "1px" }),
2338
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MethodBadge, {
2339
+ method: row.method,
2340
+ kind: row.kind,
2341
+ width: "list"
2342
+ })
2343
+ }),
2344
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
2345
+ className: css({
2346
+ flex: "1",
2347
+ minW: "0",
2348
+ display: "flex",
2349
+ flexDir: "column"
2350
+ }),
2351
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2352
+ className: cx(truncate, mono),
2353
+ children: row.path
2354
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
2355
+ className: cx(truncate, css({
2356
+ fontSize: "11px",
2357
+ color: "faint"
2358
+ })),
2359
+ children: [
2360
+ formatClock(row.ts),
2361
+ " · ",
2362
+ row.file,
2363
+ " · ",
2364
+ row.host
2365
+ ]
2366
+ })]
2367
+ }),
2368
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
2369
+ className: css({
2370
+ display: "flex",
2371
+ flexDir: "column",
2372
+ alignItems: "flex-end",
2373
+ flexShrink: 0
2374
+ }),
2375
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusBadge, {
2376
+ status: row.status,
2377
+ error: row.error_name
2378
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2379
+ className: cx(mono, css({
2380
+ fontSize: "11px",
2381
+ color: "faint"
2382
+ })),
2383
+ children: formatMs(row.duration_ms)
2384
+ })]
2385
+ })
2386
+ ]
2387
+ }, row.id))] }, group.day))
2388
+ })]
2389
+ });
2390
+ }
2391
+ function Toggle({ checked, onChange, label }) {
2392
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
2393
+ type: "button",
2394
+ "aria-pressed": checked,
2395
+ onClick: () => onChange(!checked),
2396
+ className: css({
2397
+ h: "26px",
2398
+ px: "2",
2399
+ rounded: "md",
2400
+ border: "1px solid",
2401
+ borderColor: "line",
2402
+ bg: "transparent",
2403
+ color: "muted",
2404
+ cursor: "pointer",
2405
+ fontSize: "12px",
2406
+ _hover: { color: "fg" },
2407
+ "&[aria-pressed=true]": {
2408
+ color: "accent",
2409
+ borderColor: "accent",
2410
+ bg: "accentSoft"
2411
+ }
2412
+ }),
2413
+ children: label
2414
+ });
2415
+ }
2416
+ function useDebounced(value, ms) {
2417
+ const [current, setCurrent] = import_react.useState(value);
2418
+ import_react.useEffect(() => {
2419
+ const timer = window.setTimeout(() => setCurrent(value), ms);
2420
+ return () => window.clearTimeout(timer);
2421
+ }, [value, ms]);
2422
+ return current;
2423
+ }
2424
+ var root = getRouteApi("__root__");
2425
+ function Shell({ children }) {
2426
+ const { prefs } = usePrefs();
2427
+ const filterRef = import_react.useRef(null);
2428
+ useSlashToFilter(filterRef);
2429
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
2430
+ className: css({
2431
+ display: "flex",
2432
+ flexDir: "column",
2433
+ h: "100vh",
2434
+ bg: "chrome"
2435
+ }),
2436
+ children: [
2437
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TopBar, {}),
2438
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
2439
+ className: css({
2440
+ display: "flex",
2441
+ flex: "1",
2442
+ minH: "0"
2443
+ }),
2444
+ children: [
2445
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Rail, {}),
2446
+ prefs.sidebarOpen ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Sidebar, { filterRef }) : null,
2447
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("main", {
2448
+ className: css({
2449
+ display: "flex",
2450
+ flexDir: "column",
2451
+ flex: "1",
2452
+ minW: "0",
2453
+ bg: "canvas",
2454
+ borderLeft: "1px solid",
2455
+ borderTop: "1px solid",
2456
+ borderColor: "line",
2457
+ roundedTopLeft: "lg",
2458
+ overflow: "hidden"
2459
+ }),
2460
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TabStrip, {}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
2461
+ className: css({
2462
+ flex: "1",
2463
+ minH: "0",
2464
+ display: "flex",
2465
+ flexDir: "column"
2466
+ }),
2467
+ children
2468
+ })]
2469
+ })
2470
+ ]
2471
+ }),
2472
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusBar, {})
2473
+ ]
2474
+ });
2475
+ }
2476
+ /** `/` focuses the sidebar's filter, as in most tools with one. */
2477
+ function useSlashToFilter(ref) {
2478
+ const { prefs, set } = usePrefs();
2479
+ import_react.useEffect(() => {
2480
+ const onKey = (event) => {
2481
+ if (event.key !== "/" || event.metaKey || event.ctrlKey || event.altKey) return;
2482
+ const target = event.target;
2483
+ if (target && (target.isContentEditable || /^(INPUT|TEXTAREA|SELECT)$/.test(target.tagName))) return;
2484
+ event.preventDefault();
2485
+ if (!prefs.sidebarOpen) set("sidebarOpen", true);
2486
+ if (prefs.panel === "environments") set("panel", "collections");
2487
+ window.requestAnimationFrame(() => ref.current?.focus());
2488
+ };
2489
+ window.addEventListener("keydown", onKey);
2490
+ return () => window.removeEventListener("keydown", onKey);
2491
+ }, [
2492
+ prefs.sidebarOpen,
2493
+ prefs.panel,
2494
+ set,
2495
+ ref
2496
+ ]);
2497
+ }
2498
+ var THEME_NEXT = {
2499
+ system: "light",
2500
+ light: "dark",
2501
+ dark: "system"
2502
+ };
2503
+ function TopBar() {
2504
+ const ws = root.useLoaderData();
2505
+ const { prefs, set, refresh } = usePrefs();
2506
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", {
2507
+ className: css({
2508
+ display: "flex",
2509
+ alignItems: "center",
2510
+ gap: "3",
2511
+ h: "44px",
2512
+ px: "3",
2513
+ flexShrink: 0
2514
+ }),
2515
+ children: [
2516
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Link, {
2517
+ to: "/",
2518
+ className: css({
2519
+ display: "flex",
2520
+ alignItems: "center",
2521
+ gap: "2",
2522
+ color: "fg",
2523
+ textDecoration: "none"
2524
+ }),
2525
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
2526
+ src: "/favicon.svg",
2527
+ alt: "",
2528
+ width: 22,
2529
+ height: 22
2530
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
2531
+ className: css({
2532
+ fontWeight: "700",
2533
+ letterSpacing: "-0.01em",
2534
+ fontSize: "14px"
2535
+ }),
2536
+ children: ["wire", /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2537
+ className: css({
2538
+ color: "muted",
2539
+ fontWeight: "500"
2540
+ }),
2541
+ children: "ui"
2542
+ })]
2543
+ })]
2544
+ }),
2545
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2546
+ className: css({ color: "lineStrong" }),
2547
+ children: "/"
2548
+ }),
2549
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2550
+ title: ws.path,
2551
+ className: cx(mono, truncate, css({
2552
+ color: "muted",
2553
+ minW: "0"
2554
+ })),
2555
+ children: basename(ws.path)
2556
+ }),
2557
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
2558
+ className: css({
2559
+ ml: "auto",
2560
+ display: "flex",
2561
+ alignItems: "center",
2562
+ gap: "1.5"
2563
+ }),
2564
+ children: [
2565
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnvSelect, {}),
2566
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
2567
+ type: "button",
2568
+ "aria-pressed": prefs.live,
2569
+ onClick: () => set("live", !prefs.live),
2570
+ title: prefs.live ? "Live: re-reading the file every 2 s" : "Follow the file as runs write to it",
2571
+ className: css({
2572
+ display: "inline-flex",
2573
+ alignItems: "center",
2574
+ gap: "1.5",
2575
+ h: "28px",
2576
+ px: "2.5",
2577
+ rounded: "md",
2578
+ border: "1px solid",
2579
+ borderColor: "line",
2580
+ bg: "raised",
2581
+ color: "muted",
2582
+ cursor: "pointer",
2583
+ fontSize: "12px",
2584
+ fontWeight: "500",
2585
+ _hover: { color: "fg" },
2586
+ "&[aria-pressed=true]": {
2587
+ color: "ok",
2588
+ borderColor: "ok",
2589
+ bg: "okSoft"
2590
+ }
2591
+ }),
2592
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: cx(css({
2593
+ w: "7px",
2594
+ h: "7px",
2595
+ rounded: "full",
2596
+ bg: "faint"
2597
+ }), prefs.live && css({
2598
+ bg: "ok",
2599
+ animation: "pulse 1.6s ease-in-out infinite"
2600
+ })) }), "Live"]
2601
+ }),
2602
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconButton, {
2603
+ label: "Refresh",
2604
+ onClick: refresh,
2605
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconRefresh, {})
2606
+ }),
2607
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconButton, {
2608
+ label: prefs.layout === "side" ? "Stack request above response" : "Request and response side by side",
2609
+ onClick: () => set("layout", prefs.layout === "side" ? "stacked" : "side"),
2610
+ children: prefs.layout === "side" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconSplitSide, {}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconSplitStacked, {})
2611
+ }),
2612
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconButton, {
2613
+ label: `Theme: ${prefs.theme}`,
2614
+ onClick: () => set("theme", THEME_NEXT[prefs.theme]),
2615
+ children: prefs.theme === "system" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconMonitor, {}) : prefs.theme === "light" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconSun, {}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconMoon, {})
2616
+ })
2617
+ ]
2618
+ })
2619
+ ]
2620
+ });
2621
+ }
2622
+ function EnvSelect() {
2623
+ const ws = root.useLoaderData();
2624
+ const { prefs, set } = usePrefs();
2625
+ const known = ws.envs.map((e) => e.env ?? "");
2626
+ const value = prefs.env === "*" || known.includes(prefs.env) ? prefs.env : "*";
2627
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", {
2628
+ className: css({
2629
+ display: "inline-flex",
2630
+ alignItems: "center",
2631
+ gap: "1.5",
2632
+ h: "28px",
2633
+ pl: "2",
2634
+ pr: "1",
2635
+ rounded: "md",
2636
+ border: "1px solid",
2637
+ borderColor: value === "*" ? "line" : "accent",
2638
+ bg: value === "*" ? "raised" : "accentSoft",
2639
+ color: value === "*" ? "muted" : "accent"
2640
+ }),
2641
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconEnvironments, { size: 14 }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", {
2642
+ "aria-label": "Environment",
2643
+ value,
2644
+ onChange: (e) => set("env", e.target.value),
2645
+ className: css({
2646
+ border: "none",
2647
+ bg: "transparent",
2648
+ outline: "none",
2649
+ fontSize: "12px",
2650
+ fontWeight: "500",
2651
+ color: "fg",
2652
+ cursor: "pointer",
2653
+ maxW: "180px"
2654
+ }),
2655
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
2656
+ value: "*",
2657
+ children: "All environments"
2658
+ }), ws.envs.map((e) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
2659
+ value: e.env ?? "",
2660
+ children: e.env ?? "No environment"
2661
+ }, e.env ?? ""))]
2662
+ })]
2663
+ });
2664
+ }
2665
+ var PANELS = [
2666
+ {
2667
+ id: "collections",
2668
+ label: "Collections",
2669
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconCollections, { size: 18 })
2670
+ },
2671
+ {
2672
+ id: "history",
2673
+ label: "History",
2674
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconHistory, { size: 18 })
2675
+ },
2676
+ {
2677
+ id: "environments",
2678
+ label: "Environments",
2679
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconEnvironments, { size: 18 })
2680
+ }
2681
+ ];
2682
+ var railButton = css({
2683
+ display: "flex",
2684
+ flexDir: "column",
2685
+ alignItems: "center",
2686
+ gap: "0.5",
2687
+ w: "56px",
2688
+ py: "1.5",
2689
+ rounded: "md",
2690
+ border: "none",
2691
+ bg: "transparent",
2692
+ color: "muted",
2693
+ cursor: "pointer",
2694
+ fontSize: "10px",
2695
+ fontWeight: "500",
2696
+ textDecoration: "none",
2697
+ _hover: {
2698
+ color: "fg",
2699
+ bg: "hover"
2700
+ },
2701
+ "&[data-active=true]": {
2702
+ color: "fg",
2703
+ bg: "hover"
2704
+ },
2705
+ "&[data-active=true] svg": { color: "accent" }
2706
+ });
2707
+ function Rail() {
2708
+ const { prefs, set } = usePrefs();
2709
+ const select = (panel) => {
2710
+ if (prefs.panel === panel && prefs.sidebarOpen) set("sidebarOpen", false);
2711
+ else {
2712
+ set("panel", panel);
2713
+ set("sidebarOpen", true);
2714
+ }
2715
+ };
2716
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("nav", {
2717
+ "aria-label": "Sections",
2718
+ className: css({
2719
+ display: "flex",
2720
+ flexDir: "column",
2721
+ alignItems: "center",
2722
+ gap: "1",
2723
+ w: "64px",
2724
+ pt: "1",
2725
+ pb: "2",
2726
+ flexShrink: 0
2727
+ }),
2728
+ children: [
2729
+ PANELS.map((panel) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
2730
+ type: "button",
2731
+ className: railButton,
2732
+ "data-active": prefs.sidebarOpen && prefs.panel === panel.id,
2733
+ onClick: () => select(panel.id),
2734
+ children: [panel.icon, panel.label === "Environments" ? "Envs" : panel.label]
2735
+ }, panel.id)),
2736
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: css({
2737
+ w: "28px",
2738
+ h: "1px",
2739
+ bg: "line",
2740
+ my: "1.5"
2741
+ }) }),
2742
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Link, {
2743
+ to: "/",
2744
+ className: railButton,
2745
+ activeProps: { "data-active": true },
2746
+ activeOptions: { exact: true },
2747
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconOverview, { size: 18 }), "Overview"]
2748
+ }),
2749
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Link, {
2750
+ to: "/query",
2751
+ className: railButton,
2752
+ activeProps: { "data-active": true },
2753
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconDatabase, { size: 18 }), "SQL"]
2754
+ }),
2755
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
2756
+ className: css({ mt: "auto" }),
2757
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconButton, {
2758
+ label: prefs.sidebarOpen ? "Hide sidebar" : "Show sidebar",
2759
+ "aria-pressed": prefs.sidebarOpen,
2760
+ onClick: () => set("sidebarOpen", !prefs.sidebarOpen),
2761
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconSidebar, {})
2762
+ })
2763
+ })
2764
+ ]
2765
+ });
2766
+ }
2767
+ var MIN_SIDEBAR = 220;
2768
+ var MAX_SIDEBAR = 560;
2769
+ function Sidebar({ filterRef }) {
2770
+ const { prefs, set } = usePrefs();
2771
+ const [dragging, setDragging] = import_react.useState(false);
2772
+ const [width, setWidth] = import_react.useState(prefs.sidebarWidth);
2773
+ import_react.useEffect(() => setWidth(prefs.sidebarWidth), [prefs.sidebarWidth]);
2774
+ const title = PANELS.find((p) => p.id === prefs.panel)?.label ?? "";
2775
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("aside", {
2776
+ className: css({
2777
+ position: "relative",
2778
+ display: "flex",
2779
+ flexDir: "column",
2780
+ flexShrink: 0,
2781
+ minH: "0",
2782
+ pt: "1"
2783
+ }),
2784
+ style: { width },
2785
+ children: [
2786
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
2787
+ className: css({
2788
+ display: "flex",
2789
+ alignItems: "center",
2790
+ h: "30px",
2791
+ px: "3",
2792
+ flexShrink: 0
2793
+ }),
2794
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2795
+ className: css({
2796
+ fontWeight: "600",
2797
+ fontSize: "12px"
2798
+ }),
2799
+ children: title
2800
+ })
2801
+ }),
2802
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
2803
+ className: css({
2804
+ flex: "1",
2805
+ minH: "0"
2806
+ }),
2807
+ children: [
2808
+ prefs.panel === "collections" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CollectionsPanel, { filterRef }) : null,
2809
+ prefs.panel === "history" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HistoryPanel, { filterRef }) : null,
2810
+ prefs.panel === "environments" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EnvironmentsPanel, {}) : null
2811
+ ]
2812
+ }),
2813
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
2814
+ role: "separator",
2815
+ "aria-orientation": "vertical",
2816
+ "aria-label": "Resize sidebar",
2817
+ onPointerDown: (e) => {
2818
+ e.preventDefault();
2819
+ e.target.setPointerCapture(e.pointerId);
2820
+ setDragging(true);
2821
+ },
2822
+ onPointerMove: (e) => {
2823
+ if (!dragging) return;
2824
+ const aside = e.target.parentElement;
2825
+ if (!aside) return;
2826
+ const left = aside.getBoundingClientRect().left;
2827
+ setWidth(Math.min(MAX_SIDEBAR, Math.max(MIN_SIDEBAR, e.clientX - left)));
2828
+ },
2829
+ onPointerUp: () => {
2830
+ if (!dragging) return;
2831
+ setDragging(false);
2832
+ set("sidebarWidth", width);
2833
+ },
2834
+ className: cx(css({
2835
+ position: "absolute",
2836
+ top: "0",
2837
+ bottom: "0",
2838
+ right: "-3px",
2839
+ w: "6px",
2840
+ cursor: "col-resize",
2841
+ zIndex: "2",
2842
+ _hover: {
2843
+ bg: "accent",
2844
+ opacity: .4
2845
+ }
2846
+ }), dragging && css({
2847
+ bg: "accent",
2848
+ opacity: .4
2849
+ }))
2850
+ })
2851
+ ]
2852
+ });
2853
+ }
2854
+ function TabStrip() {
2855
+ const { tabs, activeKey, pin, close } = useTabs();
2856
+ const navigate = useNavigate();
2857
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
2858
+ role: "tablist",
2859
+ "aria-label": "Open tabs",
2860
+ className: css({
2861
+ display: "flex",
2862
+ alignItems: "stretch",
2863
+ h: "36px",
2864
+ flexShrink: 0,
2865
+ bg: "chrome",
2866
+ borderBottom: "1px solid",
2867
+ borderColor: "line",
2868
+ overflowX: "auto",
2869
+ scrollbarWidth: "none"
2870
+ }),
2871
+ children: tabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
2872
+ role: "tab",
2873
+ tabIndex: 0,
2874
+ "aria-selected": tab.key === activeKey,
2875
+ "data-preview": tab.preview,
2876
+ title: tab.preview ? `${tab.title} — preview; double-click to keep open` : tab.title,
2877
+ onClick: () => void navigate({ href: tab.href }),
2878
+ onKeyDown: (e) => {
2879
+ if (e.key === "Enter") navigate({ href: tab.href });
2880
+ },
2881
+ onDoubleClick: () => pin(tab.key),
2882
+ onAuxClick: (e) => {
2883
+ if (e.button === 1) close(tab.key);
2884
+ },
2885
+ className: css({
2886
+ position: "relative",
2887
+ display: "flex",
2888
+ alignItems: "center",
2889
+ gap: "1.5",
2890
+ pl: "3",
2891
+ pr: "1",
2892
+ minW: "0",
2893
+ maxW: "220px",
2894
+ flexShrink: 0,
2895
+ borderRight: "1px solid",
2896
+ borderColor: "line",
2897
+ cursor: "pointer",
2898
+ color: "muted",
2899
+ userSelect: "none",
2900
+ _hover: {
2901
+ color: "fg",
2902
+ bg: "hover"
2903
+ },
2904
+ "&[aria-selected=true]": {
2905
+ bg: "canvas",
2906
+ color: "fg",
2907
+ _before: {
2908
+ content: "\"\"",
2909
+ position: "absolute",
2910
+ left: "0",
2911
+ right: "0",
2912
+ top: "0",
2913
+ h: "2px",
2914
+ bg: "accent"
2915
+ }
2916
+ },
2917
+ "&[data-preview=true] .tab-title": { fontStyle: "italic" },
2918
+ "& .tab-close": { opacity: 0 },
2919
+ "&:hover .tab-close, &[aria-selected=true] .tab-close": { opacity: 1 }
2920
+ }),
2921
+ children: [
2922
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TabGlyph, { tab }),
2923
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2924
+ className: cx("tab-title", truncate, css({ fontSize: "12px" }), tab.failed ? css({ color: "bad" }) : void 0),
2925
+ children: tab.title
2926
+ }),
2927
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconButton, {
2928
+ label: "Close tab",
2929
+ className: cx("tab-close", css({
2930
+ w: "20px",
2931
+ h: "20px"
2932
+ })),
2933
+ onClick: (e) => {
2934
+ e.stopPropagation();
2935
+ close(tab.key);
2936
+ },
2937
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconClose, { size: 12 })
2938
+ })
2939
+ ]
2940
+ }, tab.key))
2941
+ });
2942
+ }
2943
+ function TabGlyph({ tab }) {
2944
+ if (tab.icon === "request" && tab.method) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MethodBadge, {
2945
+ method: tab.method,
2946
+ kind: tab.kind
2947
+ });
2948
+ const glyph = {
2949
+ overview: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconOverview, { size: 13 }),
2950
+ collection: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconCollections, { size: 13 }),
2951
+ run: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconRun, { size: 12 }),
2952
+ request: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconRequest, { size: 13 }),
2953
+ query: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconDatabase, { size: 13 })
2954
+ }[tab.icon];
2955
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2956
+ className: css({
2957
+ display: "inline-flex",
2958
+ color: "faint",
2959
+ flexShrink: 0
2960
+ }),
2961
+ children: glyph
2962
+ });
2963
+ }
2964
+ function StatusBar() {
2965
+ const ws = root.useLoaderData();
2966
+ const { prefs, lastRefresh } = usePrefs();
2967
+ const now = useNow(ws.now, 1e3);
2968
+ const c = ws.counts;
2969
+ const item = css({
2970
+ display: "inline-flex",
2971
+ alignItems: "center",
2972
+ gap: "1",
2973
+ whiteSpace: "nowrap"
2974
+ });
2975
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("footer", {
2976
+ className: css({
2977
+ display: "flex",
2978
+ alignItems: "center",
2979
+ gap: "4",
2980
+ h: "24px",
2981
+ px: "3",
2982
+ flexShrink: 0,
2983
+ fontSize: "11px",
2984
+ color: "muted",
2985
+ borderTop: "1px solid",
2986
+ borderColor: "line",
2987
+ overflow: "hidden"
2988
+ }),
2989
+ children: [
2990
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
2991
+ className: cx(item, mono, truncate, css({
2992
+ minW: "0",
2993
+ flexShrink: 1
2994
+ })),
2995
+ title: ws.path,
2996
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconDatabase, { size: 12 }), ws.path]
2997
+ }),
2998
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
2999
+ className: item,
3000
+ children: formatBytes(ws.bytes)
3001
+ }),
3002
+ c ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
3003
+ className: item,
3004
+ children: [
3005
+ formatCount(c.runs),
3006
+ " runs · ",
3007
+ formatCount(c.requests + c.connections),
3008
+ " requests"
3009
+ ]
3010
+ }) : null,
3011
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
3012
+ className: item,
3013
+ children: ["schema v", ws.schema.file]
3014
+ }),
3015
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
3016
+ className: cx(item, css({ ml: "auto" })),
3017
+ children: [prefs.live ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
3018
+ className: css({ color: "ok" }),
3019
+ children: "● Live"
3020
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Read-only" }), lastRefresh ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
3021
+ className: css({ color: "faint" }),
3022
+ children: ["· read ", formatAgo(now, lastRefresh)]
3023
+ }) : null]
3024
+ })
3025
+ ]
3026
+ });
3027
+ }
3028
+ var globals_default = "/assets/globals-CZiNFGaK.css";
3029
+ var Route$5 = createRootRoute({
3030
+ head: () => ({
3031
+ meta: [
3032
+ { charSet: "utf-8" },
3033
+ {
3034
+ name: "viewport",
3035
+ content: "width=device-width, initial-scale=1"
3036
+ },
3037
+ {
3038
+ name: "color-scheme",
3039
+ content: "light dark"
3040
+ },
3041
+ { title: "wireui" }
3042
+ ],
3043
+ links: [{
3044
+ rel: "stylesheet",
3045
+ href: globals_default
3046
+ }, {
3047
+ rel: "icon",
3048
+ href: "/favicon.svg",
3049
+ type: "image/svg+xml"
3050
+ }]
3051
+ }),
3052
+ loader: () => getWorkspace(),
3053
+ staleTime: 0,
3054
+ errorComponent: RouteError,
3055
+ notFoundComponent: NotFound,
3056
+ component: RootLayout,
3057
+ shellComponent: RootDocument
3058
+ });
3059
+ function RootLayout() {
3060
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Frame, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Outlet, {}) });
3061
+ }
3062
+ function Frame({ children }) {
3063
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PrefsProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TabsProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Shell, { children }) }) });
3064
+ }
3065
+ function RootDocument({ children }) {
3066
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("html", {
3067
+ lang: "en",
3068
+ suppressHydrationWarning: true,
3069
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("head", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("script", { dangerouslySetInnerHTML: { __html: THEME_BOOT_SCRIPT } }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HeadContent, {})] }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("body", { children: [children, /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Scripts, {})] })]
3070
+ });
3071
+ }
3072
+ var $$splitComponentImporter$4 = () => import("./routes-DaV9vGHn.mjs");
3073
+ var Route$4 = createFileRoute("/")({
3074
+ loader: () => getOverview({ data: {} }),
3075
+ component: lazyRouteComponent($$splitComponentImporter$4, "component")
3076
+ });
3077
+ var $$splitComponentImporter$3 = () => import("./collections-CqidTQpw.mjs");
3078
+ var Route$3 = createFileRoute("/collections")({
3079
+ validateSearch: (search) => ({
3080
+ entry: typeof search.entry === "string" ? search.entry : "",
3081
+ tab: search.tab === "requests" || search.tab === "checks" ? search.tab : void 0
3082
+ }),
3083
+ loaderDeps: ({ search }) => ({ entry: search.entry }),
3084
+ loader: async ({ deps }) => {
3085
+ if (!deps.entry) throw notFound();
3086
+ const page = await getScript({ data: { entry: deps.entry } });
3087
+ if (!page) throw notFound();
3088
+ return page;
3089
+ },
3090
+ component: lazyRouteComponent($$splitComponentImporter$3, "component")
3091
+ });
3092
+ /** Most recent {@link STRIP_RUNS} runs as bars, oldest on the left. */
3093
+ var $$splitComponentImporter$2 = () => import("./query-D4so9xiY.mjs");
3094
+ var Route$2 = createFileRoute("/query")({
3095
+ validateSearch: (search) => ({ sql: typeof search.sql === "string" ? search.sql : void 0 }),
3096
+ loader: () => getSchema(),
3097
+ component: lazyRouteComponent($$splitComponentImporter$2, "component")
3098
+ });
3099
+ var $$splitComponentImporter$1 = () => import("./requests._requestId-BFukRwqL.mjs");
3100
+ var REQ_TABS = [
3101
+ "params",
3102
+ "headers",
3103
+ "body",
3104
+ "cookies",
3105
+ "tags"
3106
+ ];
3107
+ var RES_TABS = [
3108
+ "body",
3109
+ "messages",
3110
+ "headers",
3111
+ "cookies",
3112
+ "timeline"
3113
+ ];
3114
+ var Route$1 = createFileRoute("/requests/$requestId")({
3115
+ validateSearch: (search) => ({
3116
+ req: REQ_TABS.includes(search.req) ? search.req : void 0,
3117
+ res: RES_TABS.includes(search.res) ? search.res : void 0
3118
+ }),
3119
+ loader: async ({ params }) => {
3120
+ const page = await getRequest({ data: { requestId: params.requestId } });
3121
+ if (!page) throw notFound();
3122
+ return page;
3123
+ },
3124
+ component: lazyRouteComponent($$splitComponentImporter$1, "component")
3125
+ });
3126
+ var $$splitComponentImporter = () => import("./runs._runId-Df_LmPHa.mjs");
3127
+ var Route = createFileRoute("/runs/$runId")({
3128
+ validateSearch: (search) => ({ tab: search.tab === "checks" || search.tab === "insights" || search.tab === "details" ? search.tab : void 0 }),
3129
+ loader: async ({ params }) => {
3130
+ const page = await getRun({ data: { runId: params.runId } });
3131
+ if (!page) throw notFound();
3132
+ return page;
3133
+ },
3134
+ component: lazyRouteComponent($$splitComponentImporter, "component")
3135
+ });
3136
+ var rootRouteChildren = {
3137
+ IndexRoute: Route$4.update({
3138
+ id: "/",
3139
+ path: "/",
3140
+ getParentRoute: () => Route$5
3141
+ }),
3142
+ CollectionsRoute: Route$3.update({
3143
+ id: "/collections",
3144
+ path: "/collections",
3145
+ getParentRoute: () => Route$5
3146
+ }),
3147
+ QueryRoute: Route$2.update({
3148
+ id: "/query",
3149
+ path: "/query",
3150
+ getParentRoute: () => Route$5
3151
+ }),
3152
+ RequestsRequestIdRoute: Route$1.update({
3153
+ id: "/requests/$requestId",
3154
+ path: "/requests/$requestId",
3155
+ getParentRoute: () => Route$5
3156
+ }),
3157
+ RunsRunIdRoute: Route.update({
3158
+ id: "/runs/$runId",
3159
+ path: "/runs/$runId",
3160
+ getParentRoute: () => Route$5
3161
+ })
3162
+ };
3163
+ var routeTree = Route$5._addFileChildren(rootRouteChildren)._addFileTypes();
3164
+ var router_exports = /* @__PURE__ */ __exportAll({ getRouter: () => getRouter });
3165
+ function getRouter() {
3166
+ return createRouter({
3167
+ routeTree,
3168
+ defaultPreload: "intent",
3169
+ defaultPreloadStaleTime: 0,
3170
+ scrollRestoration: true,
3171
+ defaultNotFoundComponent: NotFound,
3172
+ defaultErrorComponent: RouteError
3173
+ });
3174
+ }
3175
+ //#endregion
3176
+ export { Button, Callout, Card, CopyButton, Dot, Empty, FilterInput, IconAlert, IconButton, IconCheckCircle, IconChevronDown, IconChevronLeft, IconChevronRight, IconCollections, IconDatabase, IconDown, IconFile, IconPlay, IconRun, IconUp, IconXCircle, Kbd, MethodBadge, Pill, Route, Route$1, Route$2, Route$3, Route$4, STATUS_TEXT, SectionTitle, Segmented, Stat, StatGrid, StatusBadge, TabList, bodyRaw, bodyText, css, cx, envFilter, faintText, formatAgo, formatBytes, formatClockMs, formatCount, formatDateTime, formatDay, formatMs, formatOffset, getOverview, getScript, isFailure, mono, pagePad, plural, queryParams, requestCookies, responseCookies, router_exports, runSql, runTone, runVerdict, scrollPane, statusTone, tabKey, table, timingPhases, toCurl, toneText, truncate, useNow, usePrefs, useTab, useUnreadable };