@websublime/vite-plugin-open-api-devtools 0.8.0 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ModelsPage-DgFhUiBH.js +750 -0
- package/dist/ModelsPage-DgFhUiBH.js.map +1 -0
- package/dist/{RoutesPage-DJQFqkO5.js → RoutesPage-DpasQCnt.js} +4 -4
- package/dist/{RoutesPage-DJQFqkO5.js.map → RoutesPage-DpasQCnt.js.map} +1 -1
- package/dist/{SimulatorPage-DAwHHeu0.js → SimulatorPage-CDTgl8ax.js} +154 -149
- package/dist/SimulatorPage-CDTgl8ax.js.map +1 -0
- package/dist/{TimelinePage-DdznQBTd.js → TimelinePage-CLlD6uZ8.js} +7 -7
- package/dist/{TimelinePage-DdznQBTd.js.map → TimelinePage-CLlD6uZ8.js.map} +1 -1
- package/dist/{check-CZ-YsL8n.js → check-D8w72KaI.js} +2 -2
- package/dist/{check-CZ-YsL8n.js.map → check-D8w72KaI.js.map} +1 -1
- package/dist/devtools.css +1 -1
- package/dist/devtools.js +1 -1
- package/dist/devtools.umd.cjs +3 -3
- package/dist/devtools.umd.cjs.map +1 -1
- package/dist/{format-xvYNYz8d.js → format-Bs9S93C7.js} +2 -2
- package/dist/{format-xvYNYz8d.js.map → format-Bs9S93C7.js.map} +1 -1
- package/dist/{main-C-2gO_cM.js → main-DUNgny3E.js} +6 -6
- package/dist/{main-C-2gO_cM.js.map → main-DUNgny3E.js.map} +1 -1
- package/dist/spa/assets/ModelsPage-BslYlawu.css +1 -0
- package/dist/spa/assets/ModelsPage-Ef8Z_K5t.js +4 -0
- package/dist/spa/assets/ModelsPage-Ef8Z_K5t.js.map +1 -0
- package/dist/spa/assets/{RoutesPage-DVkEOssu.js → RoutesPage-Rs-CBlOu.js} +2 -2
- package/dist/spa/assets/{RoutesPage-DVkEOssu.js.map → RoutesPage-Rs-CBlOu.js.map} +1 -1
- package/dist/spa/assets/SimulatorPage-CNh6VflM.js +2 -0
- package/dist/spa/assets/SimulatorPage-CNh6VflM.js.map +1 -0
- package/dist/spa/assets/SimulatorPage-DGEq_rzM.css +1 -0
- package/dist/spa/assets/{TimelinePage-C_LK2wKS.js → TimelinePage-2YaDXdDB.js} +2 -2
- package/dist/spa/assets/{TimelinePage-C_LK2wKS.js.map → TimelinePage-2YaDXdDB.js.map} +1 -1
- package/dist/spa/assets/check-CLk5nWxQ.js +2 -0
- package/dist/spa/assets/{check-B_DaLrgB.js.map → check-CLk5nWxQ.js.map} +1 -1
- package/dist/spa/assets/{format-r8dlo_ab.js → format-YtVMCGJx.js} +2 -2
- package/dist/spa/assets/{format-r8dlo_ab.js.map → format-YtVMCGJx.js.map} +1 -1
- package/dist/spa/assets/index-BSvrS_tt.css +1 -0
- package/dist/spa/assets/{index-Dff2RvrN.js → index-sPgNGnaU.js} +3 -3
- package/dist/spa/assets/{index-Dff2RvrN.js.map → index-sPgNGnaU.js.map} +1 -1
- package/dist/spa/assets/{trash-2-6KJWHoOC.js → trash-2-DCsOAZPr.js} +2 -2
- package/dist/spa/assets/{trash-2-6KJWHoOC.js.map → trash-2-DCsOAZPr.js.map} +1 -1
- package/dist/spa/assets/{triangle-alert-Dx8lMHrF.js → triangle-alert-DD8Mz05K.js} +2 -2
- package/dist/spa/assets/{triangle-alert-Dx8lMHrF.js.map → triangle-alert-DD8Mz05K.js.map} +1 -1
- package/dist/spa/assets/x-5pbhNHo3.js +2 -0
- package/dist/spa/assets/{x-B6bG8oob.js.map → x-5pbhNHo3.js.map} +1 -1
- package/dist/spa/index.html +2 -2
- package/dist/{trash-2-BiCAm7lq.js → trash-2-BaiQpXqE.js} +2 -2
- package/dist/{trash-2-BiCAm7lq.js.map → trash-2-BaiQpXqE.js.map} +1 -1
- package/dist/{triangle-alert-C8PD5_Zo.js → triangle-alert-CIaC9iQP.js} +2 -2
- package/dist/{triangle-alert-C8PD5_Zo.js.map → triangle-alert-CIaC9iQP.js.map} +1 -1
- package/dist/{x-Boe7tiDp.js → x-BI73Bc0z.js} +2 -2
- package/dist/{x-Boe7tiDp.js.map → x-BI73Bc0z.js.map} +1 -1
- package/package.json +14 -14
- package/dist/ModelsPage-DEKnJYaY.js +0 -629
- package/dist/ModelsPage-DEKnJYaY.js.map +0 -1
- package/dist/SimulatorPage-DAwHHeu0.js.map +0 -1
- package/dist/spa/assets/ModelsPage-DQN_XP0u.css +0 -1
- package/dist/spa/assets/ModelsPage-Dlw4slrw.js +0 -4
- package/dist/spa/assets/ModelsPage-Dlw4slrw.js.map +0 -1
- package/dist/spa/assets/SimulatorPage-B1voZDRi.css +0 -1
- package/dist/spa/assets/SimulatorPage-C2EEtkx8.js +0 -2
- package/dist/spa/assets/SimulatorPage-C2EEtkx8.js.map +0 -1
- package/dist/spa/assets/check-B_DaLrgB.js +0 -2
- package/dist/spa/assets/index-CFIFFTBf.css +0 -1
- package/dist/spa/assets/x-B6bG8oob.js +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devtools.umd.cjs","sources":["../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/shared/src/utils.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/defaultAttributes.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/Icon.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/createLucideIcon.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/check.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/chevron-down.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/chevron-right.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/chevron-up.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/circle-alert.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/circle-check-big.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/clock.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/code.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/copy.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/database.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/file-json.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/funnel.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/lock.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/plus.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/refresh-cw.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/route.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/save.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/search.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/shield.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/sprout.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/tag.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/trash-2.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/triangle-alert.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/wifi-off.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/wifi.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/x.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/zap.js","../src/composables/useWebSocket.ts","../src/router.ts","../src/App.vue","../src/stores/models.ts","../src/stores/registry.ts","../src/stores/simulation.ts","../src/stores/timeline.ts","../src/composables/useTheme.ts","../src/main.ts","../src/utils/format.ts","../src/components/EndpointDetail.vue","../src/components/EndpointList.vue","../src/pages/RoutesPage.vue","../src/components/TimelineDetail.vue","../src/components/TimelineEntry.vue","../src/pages/TimelinePage.vue","../src/components/JsonEditor.vue","../src/composables/useNotifications.ts","../src/pages/ModelsPage.vue","../src/pages/SimulatorPage.vue"],"sourcesContent":["/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, \"$1-$2\").toLowerCase();\nconst toCamelCase = (string) => string.replace(\n /^([A-Z])|[\\s-_]+(\\w)/g,\n (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()\n);\nconst toPascalCase = (string) => {\n const camelCase = toCamelCase(string);\n return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);\n};\nconst mergeClasses = (...classes) => classes.filter((className, index, array) => {\n return Boolean(className) && className.trim() !== \"\" && array.indexOf(className) === index;\n}).join(\" \").trim();\n\nexport { mergeClasses, toCamelCase, toKebabCase, toPascalCase };\n//# sourceMappingURL=utils.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nvar defaultAttributes = {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: 24,\n height: 24,\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n \"stroke-width\": 2,\n \"stroke-linecap\": \"round\",\n \"stroke-linejoin\": \"round\"\n};\n\nexport { defaultAttributes as default };\n//# sourceMappingURL=defaultAttributes.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { h } from 'vue';\nimport { mergeClasses, toKebabCase, toPascalCase } from './shared/src/utils.js';\nimport defaultAttributes from './defaultAttributes.js';\n\nconst Icon = ({ size, strokeWidth = 2, absoluteStrokeWidth, color, iconNode, name, class: classes, ...props }, { slots }) => {\n return h(\n \"svg\",\n {\n ...defaultAttributes,\n width: size || defaultAttributes.width,\n height: size || defaultAttributes.height,\n stroke: color || defaultAttributes.stroke,\n \"stroke-width\": absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,\n class: mergeClasses(\n \"lucide\",\n ...name ? [`lucide-${toKebabCase(toPascalCase(name))}-icon`, `lucide-${toKebabCase(name)}`] : [\"lucide-icon\"]\n ),\n ...props\n },\n [...iconNode.map((child) => h(...child)), ...slots.default ? [slots.default()] : []]\n );\n};\n\nexport { Icon as default };\n//# sourceMappingURL=Icon.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { h } from 'vue';\nimport Icon from './Icon.js';\n\nconst createLucideIcon = (iconName, iconNode) => (props, { slots }) => h(\n Icon,\n {\n ...props,\n iconNode,\n name: iconName\n },\n slots\n);\n\nexport { createLucideIcon as default };\n//# sourceMappingURL=createLucideIcon.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Check = createLucideIcon(\"check\", [[\"path\", { d: \"M20 6 9 17l-5-5\", key: \"1gmf2c\" }]]);\n\nexport { Check as default };\n//# sourceMappingURL=check.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst ChevronDown = createLucideIcon(\"chevron-down\", [\n [\"path\", { d: \"m6 9 6 6 6-6\", key: \"qrunsl\" }]\n]);\n\nexport { ChevronDown as default };\n//# sourceMappingURL=chevron-down.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst ChevronRight = createLucideIcon(\"chevron-right\", [\n [\"path\", { d: \"m9 18 6-6-6-6\", key: \"mthhwq\" }]\n]);\n\nexport { ChevronRight as default };\n//# sourceMappingURL=chevron-right.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst ChevronUp = createLucideIcon(\"chevron-up\", [\n [\"path\", { d: \"m18 15-6-6-6 6\", key: \"153udz\" }]\n]);\n\nexport { ChevronUp as default };\n//# sourceMappingURL=chevron-up.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst CircleAlert = createLucideIcon(\"circle-alert\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"line\", { x1: \"12\", x2: \"12\", y1: \"8\", y2: \"12\", key: \"1pkeuh\" }],\n [\"line\", { x1: \"12\", x2: \"12.01\", y1: \"16\", y2: \"16\", key: \"4dfq90\" }]\n]);\n\nexport { CircleAlert as default };\n//# sourceMappingURL=circle-alert.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst CircleCheckBig = createLucideIcon(\"circle-check-big\", [\n [\"path\", { d: \"M21.801 10A10 10 0 1 1 17 3.335\", key: \"yps3ct\" }],\n [\"path\", { d: \"m9 11 3 3L22 4\", key: \"1pflzl\" }]\n]);\n\nexport { CircleCheckBig as default };\n//# sourceMappingURL=circle-check-big.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Clock = createLucideIcon(\"clock\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"polyline\", { points: \"12 6 12 12 16 14\", key: \"68esgv\" }]\n]);\n\nexport { Clock as default };\n//# sourceMappingURL=clock.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Code = createLucideIcon(\"code\", [\n [\"path\", { d: \"m16 18 6-6-6-6\", key: \"eg8j8\" }],\n [\"path\", { d: \"m8 6-6 6 6 6\", key: \"ppft3o\" }]\n]);\n\nexport { Code as default };\n//# sourceMappingURL=code.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Copy = createLucideIcon(\"copy\", [\n [\"rect\", { width: \"14\", height: \"14\", x: \"8\", y: \"8\", rx: \"2\", ry: \"2\", key: \"17jyea\" }],\n [\"path\", { d: \"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\", key: \"zix9uf\" }]\n]);\n\nexport { Copy as default };\n//# sourceMappingURL=copy.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Database = createLucideIcon(\"database\", [\n [\"ellipse\", { cx: \"12\", cy: \"5\", rx: \"9\", ry: \"3\", key: \"msslwz\" }],\n [\"path\", { d: \"M3 5V19A9 3 0 0 0 21 19V5\", key: \"1wlel7\" }],\n [\"path\", { d: \"M3 12A9 3 0 0 0 21 12\", key: \"mv7ke4\" }]\n]);\n\nexport { Database as default };\n//# sourceMappingURL=database.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst FileJson = createLucideIcon(\"file-json\", [\n [\"path\", { d: \"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\", key: \"1rqfz7\" }],\n [\"path\", { d: \"M14 2v4a2 2 0 0 0 2 2h4\", key: \"tnqrlb\" }],\n [\n \"path\",\n { d: \"M10 12a1 1 0 0 0-1 1v1a1 1 0 0 1-1 1 1 1 0 0 1 1 1v1a1 1 0 0 0 1 1\", key: \"1oajmo\" }\n ],\n [\n \"path\",\n { d: \"M14 18a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1 1 1 0 0 1-1-1v-1a1 1 0 0 0-1-1\", key: \"mpwhp6\" }\n ]\n]);\n\nexport { FileJson as default };\n//# sourceMappingURL=file-json.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Funnel = createLucideIcon(\"funnel\", [\n [\n \"path\",\n {\n d: \"M10 20a1 1 0 0 0 .553.895l2 1A1 1 0 0 0 14 21v-7a2 2 0 0 1 .517-1.341L21.74 4.67A1 1 0 0 0 21 3H3a1 1 0 0 0-.742 1.67l7.225 7.989A2 2 0 0 1 10 14z\",\n key: \"sc7q7i\"\n }\n ]\n]);\n\nexport { Funnel as default };\n//# sourceMappingURL=funnel.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Lock = createLucideIcon(\"lock\", [\n [\"rect\", { width: \"18\", height: \"11\", x: \"3\", y: \"11\", rx: \"2\", ry: \"2\", key: \"1w4ew1\" }],\n [\"path\", { d: \"M7 11V7a5 5 0 0 1 10 0v4\", key: \"fwvmzm\" }]\n]);\n\nexport { Lock as default };\n//# sourceMappingURL=lock.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Plus = createLucideIcon(\"plus\", [\n [\"path\", { d: \"M5 12h14\", key: \"1ays0h\" }],\n [\"path\", { d: \"M12 5v14\", key: \"s699le\" }]\n]);\n\nexport { Plus as default };\n//# sourceMappingURL=plus.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst RefreshCw = createLucideIcon(\"refresh-cw\", [\n [\"path\", { d: \"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8\", key: \"v9h5vc\" }],\n [\"path\", { d: \"M21 3v5h-5\", key: \"1q7to0\" }],\n [\"path\", { d: \"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16\", key: \"3uifl3\" }],\n [\"path\", { d: \"M8 16H3v5\", key: \"1cv678\" }]\n]);\n\nexport { RefreshCw as default };\n//# sourceMappingURL=refresh-cw.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Route = createLucideIcon(\"route\", [\n [\"circle\", { cx: \"6\", cy: \"19\", r: \"3\", key: \"1kj8tv\" }],\n [\"path\", { d: \"M9 19h8.5a3.5 3.5 0 0 0 0-7h-11a3.5 3.5 0 0 1 0-7H15\", key: \"1d8sl\" }],\n [\"circle\", { cx: \"18\", cy: \"5\", r: \"3\", key: \"gq8acd\" }]\n]);\n\nexport { Route as default };\n//# sourceMappingURL=route.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Save = createLucideIcon(\"save\", [\n [\n \"path\",\n {\n d: \"M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z\",\n key: \"1c8476\"\n }\n ],\n [\"path\", { d: \"M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7\", key: \"1ydtos\" }],\n [\"path\", { d: \"M7 3v4a1 1 0 0 0 1 1h7\", key: \"t51u73\" }]\n]);\n\nexport { Save as default };\n//# sourceMappingURL=save.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Search = createLucideIcon(\"search\", [\n [\"path\", { d: \"m21 21-4.34-4.34\", key: \"14j7rj\" }],\n [\"circle\", { cx: \"11\", cy: \"11\", r: \"8\", key: \"4ej97u\" }]\n]);\n\nexport { Search as default };\n//# sourceMappingURL=search.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Shield = createLucideIcon(\"shield\", [\n [\n \"path\",\n {\n d: \"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z\",\n key: \"oel41y\"\n }\n ]\n]);\n\nexport { Shield as default };\n//# sourceMappingURL=shield.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Sprout = createLucideIcon(\"sprout\", [\n [\"path\", { d: \"M7 20h10\", key: \"e6iznv\" }],\n [\"path\", { d: \"M10 20c5.5-2.5.8-6.4 3-10\", key: \"161w41\" }],\n [\n \"path\",\n {\n d: \"M9.5 9.4c1.1.8 1.8 2.2 2.3 3.7-2 .4-3.5.4-4.8-.3-1.2-.6-2.3-1.9-3-4.2 2.8-.5 4.4 0 5.5.8z\",\n key: \"9gtqwd\"\n }\n ],\n [\n \"path\",\n {\n d: \"M14.1 6a7 7 0 0 0-1.1 4c1.9-.1 3.3-.6 4.3-1.4 1-1 1.6-2.3 1.7-4.6-2.7.1-4 1-4.9 2z\",\n key: \"bkxnd2\"\n }\n ]\n]);\n\nexport { Sprout as default };\n//# sourceMappingURL=sprout.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Tag = createLucideIcon(\"tag\", [\n [\n \"path\",\n {\n d: \"M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z\",\n key: \"vktsd0\"\n }\n ],\n [\"circle\", { cx: \"7.5\", cy: \"7.5\", r: \".5\", fill: \"currentColor\", key: \"kqv944\" }]\n]);\n\nexport { Tag as default };\n//# sourceMappingURL=tag.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Trash2 = createLucideIcon(\"trash-2\", [\n [\"path\", { d: \"M3 6h18\", key: \"d0wm0j\" }],\n [\"path\", { d: \"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6\", key: \"4alrt4\" }],\n [\"path\", { d: \"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2\", key: \"v07s0e\" }],\n [\"line\", { x1: \"10\", x2: \"10\", y1: \"11\", y2: \"17\", key: \"1uufr5\" }],\n [\"line\", { x1: \"14\", x2: \"14\", y1: \"11\", y2: \"17\", key: \"xtxkd\" }]\n]);\n\nexport { Trash2 as default };\n//# sourceMappingURL=trash-2.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst TriangleAlert = createLucideIcon(\"triangle-alert\", [\n [\n \"path\",\n {\n d: \"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\",\n key: \"wmoenq\"\n }\n ],\n [\"path\", { d: \"M12 9v4\", key: \"juzpu7\" }],\n [\"path\", { d: \"M12 17h.01\", key: \"p32p05\" }]\n]);\n\nexport { TriangleAlert as default };\n//# sourceMappingURL=triangle-alert.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst WifiOff = createLucideIcon(\"wifi-off\", [\n [\"path\", { d: \"M12 20h.01\", key: \"zekei9\" }],\n [\"path\", { d: \"M8.5 16.429a5 5 0 0 1 7 0\", key: \"1bycff\" }],\n [\"path\", { d: \"M5 12.859a10 10 0 0 1 5.17-2.69\", key: \"1dl1wf\" }],\n [\"path\", { d: \"M19 12.859a10 10 0 0 0-2.007-1.523\", key: \"4k23kn\" }],\n [\"path\", { d: \"M2 8.82a15 15 0 0 1 4.177-2.643\", key: \"1grhjp\" }],\n [\"path\", { d: \"M22 8.82a15 15 0 0 0-11.288-3.764\", key: \"z3jwby\" }],\n [\"path\", { d: \"m2 2 20 20\", key: \"1ooewy\" }]\n]);\n\nexport { WifiOff as default };\n//# sourceMappingURL=wifi-off.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Wifi = createLucideIcon(\"wifi\", [\n [\"path\", { d: \"M12 20h.01\", key: \"zekei9\" }],\n [\"path\", { d: \"M2 8.82a15 15 0 0 1 20 0\", key: \"dnpr2z\" }],\n [\"path\", { d: \"M5 12.859a10 10 0 0 1 14 0\", key: \"1x1e6c\" }],\n [\"path\", { d: \"M8.5 16.429a5 5 0 0 1 7 0\", key: \"1bycff\" }]\n]);\n\nexport { Wifi as default };\n//# sourceMappingURL=wifi.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst X = createLucideIcon(\"x\", [\n [\"path\", { d: \"M18 6 6 18\", key: \"1bl5f8\" }],\n [\"path\", { d: \"m6 6 12 12\", key: \"d8bk6v\" }]\n]);\n\nexport { X as default };\n//# sourceMappingURL=x.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Zap = createLucideIcon(\"zap\", [\n [\n \"path\",\n {\n d: \"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z\",\n key: \"1xq2db\"\n }\n ]\n]);\n\nexport { Zap as default };\n//# sourceMappingURL=zap.js.map\n","/**\n * useWebSocket Composable\n *\n * What: Provides reactive WebSocket connection management for the DevTools SPA\n * How: Manages WebSocket lifecycle with auto-reconnect and event subscription\n * Why: Enables real-time communication between DevTools and the mock server\n *\n * @module composables/useWebSocket\n */\n\nimport type { ComputedRef } from 'vue';\nimport { computed, getCurrentInstance, onMounted, ref } from 'vue';\n\n/**\n * Server event types that can be received from the server\n * These match the ServerEvent types defined in @websublime/vite-plugin-open-api-core\n */\nexport type ServerEventType =\n | 'connected'\n | 'request'\n | 'response'\n | 'timeline:cleared'\n | 'store:updated'\n | 'handler:reloaded'\n | 'handlers:updated'\n | 'seed:reloaded'\n | 'seeds:updated'\n | 'simulation:active'\n | 'simulation:added'\n | 'simulation:removed'\n | 'simulations:cleared'\n | 'registry'\n | 'timeline'\n | 'store'\n | 'store:set'\n | 'store:cleared'\n | 'simulation:set'\n | 'simulation:cleared'\n | 'reseeded'\n | 'error';\n\n/**\n * Server event structure\n */\nexport interface ServerEvent<T = unknown> {\n type: ServerEventType;\n data: T;\n}\n\n/**\n * Connected event data\n */\nexport interface ConnectedEventData {\n serverVersion: string;\n}\n\n/**\n * Client command types that can be sent to the server\n */\nexport type ClientCommandType =\n | 'get:registry'\n | 'get:timeline'\n | 'get:store'\n | 'set:store'\n | 'clear:store'\n | 'set:simulation'\n | 'clear:simulation'\n | 'clear:timeline'\n | 'reseed';\n\n/**\n * Client command structure\n */\nexport interface ClientCommand<T = unknown> {\n type: ClientCommandType;\n data?: T;\n}\n\n/**\n * WebSocket connection state\n */\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting';\n\n/**\n * Event handler function type\n */\nexport type EventHandler<T = unknown> = (data: T) => void;\n\n/**\n * Configuration options for useWebSocket\n */\nexport interface UseWebSocketOptions {\n /**\n * WebSocket URL path (default: '/_ws')\n */\n path?: string;\n\n /**\n * Reconnection delay in milliseconds (default: 2000)\n */\n reconnectDelay?: number;\n\n /**\n * Maximum reconnection attempts (default: Infinity)\n */\n maxReconnectAttempts?: number;\n\n /**\n * Whether to auto-connect on mount (default: true)\n */\n autoConnect?: boolean;\n}\n\n/**\n * Return type for useWebSocket composable\n *\n * Provides explicit typing for the composable return value as required by CLAUDE.md\n */\nexport interface UseWebSocketReturn {\n /** Current connection state */\n connectionState: ComputedRef<ConnectionState>;\n /** Whether the WebSocket is connected */\n connected: ComputedRef<boolean>;\n /** Whether the WebSocket is attempting to reconnect */\n isReconnecting: ComputedRef<boolean>;\n /** Server version received on connection */\n serverVersion: ComputedRef<string | null>;\n /** Number of reconnection attempts made */\n reconnectAttempts: ComputedRef<number>;\n /** Connect to the WebSocket server */\n connect: () => void;\n /** Disconnect from the WebSocket server */\n disconnect: () => void;\n /** Send a command to the server */\n send: <T = unknown>(command: ClientCommand<T>) => boolean;\n /** Subscribe to a server event */\n on: <T = unknown>(event: ServerEventType | '*', handler: EventHandler<T>) => () => void;\n /** Unsubscribe from a server event */\n off: <T = unknown>(event: ServerEventType | '*', handler: EventHandler<T>) => void;\n /**\n * Subscribe to an event and automatically unsubscribe after the first invocation.\n * This is a standard one-shot subscription.\n */\n once: <T = unknown>(event: ServerEventType | '*', handler: EventHandler<T>) => () => void;\n /**\n * Subscribe to an event and unsubscribe when the handler returns true.\n * Useful for conditional one-time events where you need to wait for specific data.\n */\n onUntil: <T = unknown>(\n event: ServerEventType | '*',\n handler: (data: T) => boolean | undefined,\n ) => () => void;\n /** Reset the composable state (useful for testing) */\n resetState: () => void;\n}\n\n/**\n * Default options\n */\nconst DEFAULT_OPTIONS: Required<UseWebSocketOptions> = {\n path: '/_ws',\n reconnectDelay: 2000,\n maxReconnectAttempts: Number.POSITIVE_INFINITY,\n autoConnect: true,\n};\n\n/**\n * Singleton state for WebSocket - shared across all component instances\n */\nconst connectionState = ref<ConnectionState>('disconnected');\nconst serverVersion = ref<string | null>(null);\nconst reconnectAttempts = ref(0);\n\n/**\n * Store the WebSocket instance and configuration\n */\nlet ws: WebSocket | null = null;\nlet reconnectTimer: ReturnType<typeof setTimeout> | null = null;\nlet currentOptions: Required<UseWebSocketOptions> = { ...DEFAULT_OPTIONS };\n\n/**\n * Flag to track if options have been initialized\n * Options are only set on the first call to useWebSocket or when disconnected\n */\nlet optionsInitialized = false;\n\n/**\n * Event handlers map - stores handlers for each event type\n */\nconst eventHandlers = new Map<string, Set<EventHandler>>();\n\n/**\n * Check if we're running in a browser environment\n */\nfunction isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof WebSocket !== 'undefined';\n}\n\n/**\n * Check if we're inside a Vue component context\n */\nfunction hasComponentContext(): boolean {\n return getCurrentInstance() !== null;\n}\n\n/**\n * Build the WebSocket URL based on current location\n */\nfunction buildWebSocketUrl(path: string): string {\n if (!isBrowser()) {\n return `ws://localhost${path}`;\n }\n\n const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';\n return `${protocol}//${window.location.host}${path}`;\n}\n\n/**\n * Clear the reconnect timer if active\n */\nfunction clearReconnectTimer(): void {\n if (reconnectTimer !== null) {\n clearTimeout(reconnectTimer);\n reconnectTimer = null;\n }\n}\n\n/**\n * Dispatch an event to all registered handlers\n */\nfunction dispatchEvent(type: string, data: unknown): void {\n const handlers = eventHandlers.get(type);\n if (handlers) {\n for (const handler of handlers) {\n try {\n handler(data);\n } catch (error) {\n console.error(`[DevTools WebSocket] Error in event handler for '${type}':`, error);\n }\n }\n }\n\n // Also dispatch to wildcard handlers\n const wildcardHandlers = eventHandlers.get('*');\n if (wildcardHandlers) {\n for (const handler of wildcardHandlers) {\n try {\n handler({ type, data });\n } catch (error) {\n console.error('[DevTools WebSocket] Error in wildcard event handler:', error);\n }\n }\n }\n}\n\n/**\n * Handle WebSocket open event\n */\nfunction handleOpen(): void {\n connectionState.value = 'connected';\n reconnectAttempts.value = 0;\n clearReconnectTimer();\n\n if (import.meta.env.DEV) {\n console.log('[DevTools WebSocket] Connected');\n }\n}\n\n/**\n * Handle WebSocket message event\n */\nfunction handleMessage(event: MessageEvent): void {\n try {\n const message = JSON.parse(event.data) as ServerEvent;\n\n // Handle connected event specially to extract server version\n if (message.type === 'connected') {\n const connectedData = message.data as ConnectedEventData;\n serverVersion.value = connectedData.serverVersion;\n\n if (import.meta.env.DEV) {\n console.log(`[DevTools WebSocket] Server version: ${connectedData.serverVersion}`);\n }\n }\n\n // Dispatch to registered handlers\n dispatchEvent(message.type, message.data);\n } catch (error) {\n console.error('[DevTools WebSocket] Failed to parse message:', error);\n }\n}\n\n/**\n * Handle WebSocket close event\n */\nfunction handleClose(): void {\n const wasConnected = connectionState.value === 'connected';\n connectionState.value = 'disconnected';\n ws = null;\n\n if (wasConnected && import.meta.env.DEV) {\n console.log('[DevTools WebSocket] Disconnected');\n }\n\n // Attempt to reconnect if within limits\n if (reconnectAttempts.value < currentOptions.maxReconnectAttempts) {\n connectionState.value = 'reconnecting';\n reconnectAttempts.value++;\n\n if (import.meta.env.DEV) {\n console.log(\n `[DevTools WebSocket] Reconnecting in ${currentOptions.reconnectDelay}ms (attempt ${reconnectAttempts.value})`,\n );\n }\n\n reconnectTimer = setTimeout(() => {\n connect();\n }, currentOptions.reconnectDelay);\n } else if (import.meta.env.DEV) {\n console.warn('[DevTools WebSocket] Max reconnection attempts reached');\n }\n}\n\n/**\n * Handle WebSocket error event\n */\nfunction handleError(event: Event): void {\n console.error('[DevTools WebSocket] Error:', event);\n}\n\n/**\n * Connect to the WebSocket server\n */\nfunction connect(): void {\n if (!isBrowser()) {\n if (import.meta.env.DEV) {\n console.warn('[DevTools WebSocket] Cannot connect outside browser environment');\n }\n return;\n }\n\n // Don't connect if already connected or connecting\n // Check connectionState first to prevent race condition when connect() is called rapidly\n if (\n connectionState.value === 'connecting' ||\n connectionState.value === 'connected' ||\n (ws && (ws.readyState === WebSocket.CONNECTING || ws.readyState === WebSocket.OPEN))\n ) {\n return;\n }\n\n // Clean up existing connection without resetting reconnect state\n cleanupConnection();\n\n connectionState.value = 'connecting';\n const url = buildWebSocketUrl(currentOptions.path);\n\n try {\n ws = new WebSocket(url);\n ws.onopen = handleOpen;\n ws.onmessage = handleMessage;\n ws.onclose = handleClose;\n ws.onerror = handleError;\n } catch (error) {\n console.error('[DevTools WebSocket] Failed to create WebSocket:', error);\n connectionState.value = 'disconnected';\n }\n}\n\n/**\n * Clean up WebSocket connection without resetting reconnect state.\n * Used internally when reconnecting.\n */\nfunction cleanupConnection(): void {\n if (ws) {\n // Remove event handlers to prevent close handler from triggering reconnect\n ws.onopen = null;\n ws.onmessage = null;\n ws.onclose = null;\n ws.onerror = null;\n\n if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {\n ws.close();\n }\n\n ws = null;\n }\n}\n\n/**\n * Disconnect from the WebSocket server\n */\nfunction disconnect(): void {\n clearReconnectTimer();\n cleanupConnection();\n\n connectionState.value = 'disconnected';\n reconnectAttempts.value = 0;\n}\n\n/**\n * Send a command to the server\n *\n * @param command - The command to send\n * @returns true if the command was sent, false otherwise\n */\nfunction send<T = unknown>(command: ClientCommand<T>): boolean {\n if (!ws || ws.readyState !== WebSocket.OPEN) {\n if (import.meta.env.DEV) {\n console.warn('[DevTools WebSocket] Cannot send command - not connected');\n }\n return false;\n }\n\n try {\n ws.send(JSON.stringify(command));\n return true;\n } catch (error) {\n console.error('[DevTools WebSocket] Failed to send command:', error);\n return false;\n }\n}\n\n/**\n * Subscribe to a server event\n *\n * @param event - The event type to subscribe to (or '*' for all events)\n * @param handler - The handler function to call when the event is received\n * @returns An unsubscribe function\n */\nfunction on<T = unknown>(event: ServerEventType | '*', handler: EventHandler<T>): () => void {\n if (!eventHandlers.has(event)) {\n eventHandlers.set(event, new Set());\n }\n\n const handlers = eventHandlers.get(event);\n if (handlers) {\n handlers.add(handler as EventHandler);\n }\n\n // Return unsubscribe function\n return () => {\n const currentHandlers = eventHandlers.get(event);\n if (currentHandlers) {\n currentHandlers.delete(handler as EventHandler);\n if (currentHandlers.size === 0) {\n eventHandlers.delete(event);\n }\n }\n };\n}\n\n/**\n * Unsubscribe from a server event\n *\n * @param event - The event type to unsubscribe from\n * @param handler - The handler function to remove\n */\nfunction off<T = unknown>(event: ServerEventType | '*', handler: EventHandler<T>): void {\n const handlers = eventHandlers.get(event);\n if (handlers) {\n handlers.delete(handler as EventHandler);\n if (handlers.size === 0) {\n eventHandlers.delete(event);\n }\n }\n}\n\n/**\n * Subscribe to an event and automatically unsubscribe after the first invocation.\n * This is a standard one-shot subscription - the handler is called exactly once.\n *\n * @param event - The event type to subscribe to\n * @param handler - The handler function to call once\n * @returns An unsubscribe function (can be used to cancel before the event fires)\n *\n * @example\n * ```typescript\n * // Wait for the first 'connected' event\n * once('connected', (data) => {\n * console.log('Connected with version:', data.serverVersion);\n * });\n * ```\n */\nfunction once<T = unknown>(event: ServerEventType | '*', handler: EventHandler<T>): () => void {\n const wrappedHandler: EventHandler<T> = (data) => {\n off(event, wrappedHandler);\n handler(data);\n };\n\n return on(event, wrappedHandler);\n}\n\n/**\n * Subscribe to an event and unsubscribe when the handler returns true.\n * Useful for conditional one-time events where you need to wait for specific data.\n *\n * @param event - The event type to subscribe to\n * @param handler - The handler function that returns true to unsubscribe\n * @returns An unsubscribe function\n *\n * @example\n * ```typescript\n * // Wait until we receive a response with status 200\n * onUntil('response', (data) => {\n * if (data.status === 200) {\n * console.log('Success response received');\n * return true; // Unsubscribe\n * }\n * return false; // Keep listening\n * });\n * ```\n */\nfunction onUntil<T = unknown>(\n event: ServerEventType | '*',\n handler: (data: T) => boolean | undefined,\n): () => void {\n const wrappedHandler: EventHandler<T> = (data) => {\n const result = handler(data);\n if (result === true) {\n off(event, wrappedHandler);\n }\n };\n\n return on(event, wrappedHandler);\n}\n\n/**\n * Reset the composable state (useful for testing)\n */\nfunction resetState(): void {\n disconnect();\n serverVersion.value = null;\n eventHandlers.clear();\n currentOptions = { ...DEFAULT_OPTIONS };\n optionsInitialized = false;\n}\n\n/**\n * useWebSocket composable\n *\n * Provides WebSocket connection management functionality including:\n * - Reactive connection state\n * - Auto-reconnect with configurable delay\n * - Event subscription system\n * - Command sending\n *\n * @param options - Configuration options\n * @returns WebSocket management utilities\n */\nexport function useWebSocket(options: UseWebSocketOptions = {}): UseWebSocketReturn {\n // Only merge options when not connected and not initialized, or when disconnected\n // This prevents race conditions when multiple components pass different options\n if (!optionsInitialized || connectionState.value === 'disconnected') {\n currentOptions = { ...DEFAULT_OPTIONS, ...options };\n optionsInitialized = true;\n }\n\n /**\n * Computed property indicating if the WebSocket is connected\n */\n const connected = computed(() => connectionState.value === 'connected');\n\n /**\n * Computed property indicating if the WebSocket is attempting to reconnect\n */\n const isReconnecting = computed(() => connectionState.value === 'reconnecting');\n\n // Note: We don't disconnect on component unmount because this is singleton state\n // and other components may still be using the connection.\n // The connection will be cleaned up when the page unloads.\n\n // Only register lifecycle hooks when inside a Vue component context\n if (hasComponentContext()) {\n onMounted(() => {\n if (currentOptions.autoConnect) {\n connect();\n }\n });\n }\n\n return {\n /**\n * Current connection state\n */\n connectionState: computed(() => connectionState.value),\n\n /**\n * Whether the WebSocket is connected\n */\n connected,\n\n /**\n * Whether the WebSocket is attempting to reconnect\n */\n isReconnecting,\n\n /**\n * Server version received on connection\n */\n serverVersion: computed(() => serverVersion.value),\n\n /**\n * Number of reconnection attempts made\n */\n reconnectAttempts: computed(() => reconnectAttempts.value),\n\n /**\n * Connect to the WebSocket server\n */\n connect,\n\n /**\n * Disconnect from the WebSocket server\n */\n disconnect,\n\n /**\n * Send a command to the server\n */\n send,\n\n /**\n * Subscribe to a server event\n */\n on,\n\n /**\n * Unsubscribe from a server event\n */\n off,\n\n /**\n * Subscribe to an event once (one-shot, auto-unsubscribes after first call)\n */\n once,\n\n /**\n * Subscribe to an event until handler returns true\n */\n onUntil,\n\n /**\n * Reset the composable state (useful for testing)\n */\n resetState,\n };\n}\n","/**\n * Vue Router Configuration\n *\n * What: Defines routing configuration for the DevTools SPA\n * How: Creates routes for each main page/tab in the application\n * Why: Enables navigation between different DevTools features\n */\n\nimport { createRouter, createWebHashHistory, type RouteRecordRaw } from 'vue-router';\n\n/**\n * Route definitions for the DevTools SPA\n *\n * Each route corresponds to a tab in the DevTools interface:\n * - Routes: Endpoint listing and details\n * - Timeline: Request/response log with real-time updates\n * - Models: Store data editor for viewing/modifying mock data\n * - Simulator: Error simulation controls\n */\nconst routes: RouteRecordRaw[] = [\n {\n path: '/',\n redirect: '/routes',\n },\n {\n path: '/routes',\n name: 'routes',\n component: () => import('@/pages/RoutesPage.vue'),\n meta: {\n title: 'Routes',\n icon: 'route',\n },\n },\n {\n path: '/timeline',\n name: 'timeline',\n component: () => import('@/pages/TimelinePage.vue'),\n meta: {\n title: 'Timeline',\n icon: 'clock',\n },\n },\n {\n path: '/models',\n name: 'models',\n component: () => import('@/pages/ModelsPage.vue'),\n meta: {\n title: 'Models',\n icon: 'database',\n },\n },\n {\n path: '/simulator',\n name: 'simulator',\n component: () => import('@/pages/SimulatorPage.vue'),\n meta: {\n title: 'Simulator',\n icon: 'zap',\n },\n },\n // Catch-all route for undefined paths - redirects to routes page\n {\n path: '/:pathMatch(.*)*',\n name: 'not-found',\n redirect: '/routes',\n },\n];\n\n/**\n * Create the router instance\n *\n * Uses hash history mode for compatibility when embedded in iframes\n * or served from arbitrary paths in the dev server\n */\nconst router = createRouter({\n history: createWebHashHistory(),\n routes,\n});\n\nexport { routes };\nexport default router;\n","<!--\n App.vue - Main Application Component\n\n What: Root component for the DevTools SPA\n How: Provides the main layout with header, tab navigation, and router view\n Why: Acts as the entry point for the Vue application and defines the overall structure\n-->\n\n<script setup lang=\"ts\">\nimport { Clock, Database, Route, Wifi, WifiOff, Zap } from 'lucide-vue-next';\nimport { computed } from 'vue';\nimport { useRoute, useRouter } from 'vue-router';\nimport { useWebSocket } from '@/composables/useWebSocket';\nimport { routes } from '@/router';\n\nconst route = useRoute();\nconst router = useRouter();\n\n// Navigation tabs derived from routes\nconst tabs = computed(() =>\n routes\n .filter((r) => r.name && r.meta?.title)\n .map((r) => ({\n name: r.name as string,\n path: r.path,\n title: r.meta?.title as string,\n icon: r.meta?.icon as string,\n })),\n);\n\n// Current active tab\nconst activeTab = computed(() => route.name as string);\n\n// Navigate to a tab\nfunction navigateTo(path: string): void {\n router.push(path);\n}\n\n// Icon component map\nconst iconMap: Record<string, typeof Route> = {\n route: Route,\n clock: Clock,\n database: Database,\n zap: Zap,\n};\n\n// Get icon with fallback for unknown icon names\nfunction getIcon(iconName: string): typeof Route {\n const icon = iconMap[iconName];\n if (!icon && import.meta.env.DEV) {\n console.warn(`[DevTools] Unknown icon name: \"${iconName}\". Using fallback.`);\n }\n return icon ?? Route;\n}\n\n// Connection status from WebSocket composable\nconst { connected: isConnected } = useWebSocket();\n</script>\n\n<template>\n <div class=\"app\">\n <!-- Header with branding and connection status -->\n <header class=\"app-header\">\n <div class=\"app-header__brand\">\n <Zap class=\"app-header__logo\" :size=\"20\" />\n <span class=\"app-header__title\">OpenAPI DevTools</span>\n </div>\n\n <!-- Tab Navigation -->\n <nav class=\"app-nav\" role=\"tablist\" aria-label=\"DevTools navigation\">\n <button\n v-for=\"tab in tabs\"\n :key=\"tab.name\"\n role=\"tab\"\n :aria-selected=\"activeTab === tab.name\"\n :aria-current=\"activeTab === tab.name ? 'true' : undefined\"\n :aria-controls=\"`panel-${tab.name}`\"\n :tabindex=\"0\"\n :class=\"[\n 'app-nav__tab',\n { 'app-nav__tab--active': activeTab === tab.name },\n ]\"\n @click=\"navigateTo(tab.path)\"\n >\n <component\n :is=\"getIcon(tab.icon)\"\n :size=\"16\"\n class=\"app-nav__icon\"\n />\n <span class=\"app-nav__label\">{{ tab.title }}</span>\n </button>\n </nav>\n\n <!-- Connection Status -->\n <div class=\"app-header__status\">\n <div class=\"connection-status\">\n <span\n :class=\"[\n 'connection-status__dot',\n isConnected\n ? 'connection-status__dot--connected'\n : 'connection-status__dot--disconnected',\n ]\"\n />\n <span class=\"connection-status__text\">\n {{ isConnected ? 'Connected' : 'Disconnected' }}\n </span>\n <component\n :is=\"isConnected ? Wifi : WifiOff\"\n :size=\"14\"\n class=\"connection-status__icon\"\n />\n </div>\n </div>\n </header>\n\n <!-- Main Content Area -->\n <main class=\"app-main\">\n <router-view v-slot=\"{ Component }\">\n <transition name=\"fade\" mode=\"out-in\">\n <component :is=\"Component\" />\n </transition>\n </router-view>\n </main>\n </div>\n</template>\n\n<style scoped>\n.app {\n display: flex;\n flex-direction: column;\n min-height: 100vh;\n background-color: var(--devtools-bg);\n}\n\n/* Header styles */\n.app-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n height: var(--devtools-header-height);\n padding: 0 var(--devtools-space-md);\n background-color: var(--devtools-surface);\n border-bottom: 1px solid var(--devtools-border);\n position: sticky;\n top: 0;\n z-index: 100;\n}\n\n.app-header__brand {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n}\n\n.app-header__logo {\n color: var(--devtools-primary);\n}\n\n.app-header__title {\n font-weight: var(--font-weight-6);\n font-size: var(--font-size-1);\n color: var(--devtools-text);\n}\n\n.app-header__status {\n display: flex;\n align-items: center;\n}\n\n/* Navigation styles */\n.app-nav {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n height: 100%;\n}\n\n.app-nav__tab {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n height: 100%;\n padding: 0 var(--devtools-space-md);\n background: none;\n border: none;\n border-bottom: 2px solid transparent;\n color: var(--devtools-text-muted);\n font-family: var(--devtools-font-sans);\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.app-nav__tab:hover {\n color: var(--devtools-text);\n background-color: var(--devtools-surface-elevated);\n}\n\n.app-nav__tab:focus {\n outline: none;\n}\n\n.app-nav__tab:focus-visible {\n outline: 2px solid var(--devtools-primary);\n outline-offset: -2px;\n background-color: var(--devtools-surface-elevated);\n}\n\n/* High contrast mode support */\n@media (forced-colors: active) {\n .app-nav__tab:focus-visible {\n outline: 3px solid CanvasText;\n outline-offset: 2px;\n }\n}\n\n.app-nav__tab--active {\n color: var(--devtools-primary);\n border-bottom-color: var(--devtools-primary);\n}\n\n.app-nav__tab--active:focus-visible {\n outline-color: var(--devtools-primary-hover);\n}\n\n.app-nav__icon {\n flex-shrink: 0;\n}\n\n.app-nav__label {\n white-space: nowrap;\n}\n\n/* Connection status styles */\n.connection-status {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n}\n\n.connection-status__icon {\n opacity: 0.7;\n}\n\n/* Main content styles */\n.app-main {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n</style>\n\n<style>\n/* Page transition - must be unscoped to apply to router-view children */\n.fade-enter-active,\n.fade-leave-active {\n transition: opacity var(--devtools-transition-normal);\n}\n\n.fade-enter-from,\n.fade-leave-to {\n opacity: 0;\n}\n</style>\n","/**\n * Models Store - Store Data Management\n *\n * What: Manages in-memory store data for viewing and editing mock data\n * How: Fetches data from /_api/store endpoints and sends WebSocket commands\n * Why: Provides centralized state management for the Models page\n *\n * API Endpoints Used:\n * - GET /_api/store - List all schemas\n * - GET /_api/store/:schema - Get items for a schema\n * - POST /_api/store/:schema - Bulk replace items\n * - DELETE /_api/store/:schema - Clear schema data\n *\n * WebSocket Commands:\n * - reseed - Trigger reseed of all schemas\n */\n\nimport { defineStore } from 'pinia';\nimport type { ComputedRef, Ref } from 'vue';\nimport { computed, ref, toRaw } from 'vue';\n\n/**\n * Safe clone helper that handles Vue reactive/proxy values\n * Attempts structuredClone with toRaw, falls back to JSON serialization\n */\nfunction safeClone<T>(value: T): T {\n try {\n return structuredClone(toRaw(value));\n } catch {\n return JSON.parse(JSON.stringify(value)) as T;\n }\n}\n\n/**\n * Schema metadata from the server\n */\nexport interface SchemaInfo {\n /** Schema name from OpenAPI components */\n name: string;\n /** Number of items in the store for this schema */\n count: number;\n /** ID field name for this schema */\n idField: string;\n}\n\n/**\n * Schema data response from the server\n */\nexport interface SchemaData {\n /** Schema name */\n schema: string;\n /** Number of items */\n count: number;\n /** ID field name */\n idField: string;\n /** Array of data items */\n items: unknown[];\n}\n\n/**\n * Store state data\n */\nexport interface ModelsData {\n /** List of available schemas */\n schemas: SchemaInfo[];\n /** Currently selected schema name */\n selectedSchema: string | null;\n /** Items for the currently selected schema */\n currentItems: unknown[];\n /** Loading state */\n loading: boolean;\n /** Error message if any */\n error: string | null;\n /** Editing state - whether data has been modified */\n isDirty: boolean;\n}\n\n/**\n * Models store for managing store data\n */\nexport const useModelsStore = defineStore('models', () => {\n // ==========================================================================\n // State\n // ==========================================================================\n\n /** List of available schemas with metadata */\n const schemas: Ref<SchemaInfo[]> = ref([]);\n\n /** Currently selected schema name */\n const selectedSchema: Ref<string | null> = ref(null);\n\n /** Items for the currently selected schema */\n const currentItems: Ref<unknown[]> = ref([]);\n\n /** Original items (before editing) for dirty detection */\n const originalItems: Ref<unknown[]> = ref([]);\n\n /** Loading state */\n const loading: Ref<boolean> = ref(false);\n\n /** Error message */\n const error: Ref<string | null> = ref(null);\n\n // ==========================================================================\n // Computed\n // ==========================================================================\n\n /**\n * Currently selected schema metadata\n */\n const currentSchema: ComputedRef<SchemaInfo | null> = computed(() => {\n if (!selectedSchema.value) return null;\n return schemas.value.find((s) => s.name === selectedSchema.value) ?? null;\n });\n\n /**\n * Dirty state flag - updated by functions that mutate state\n */\n const isDirtyFlag: Ref<boolean> = ref(false);\n\n /**\n * Whether the current data has been modified\n */\n const isDirty: ComputedRef<boolean> = computed(() => isDirtyFlag.value);\n\n /**\n * Total number of schemas\n */\n const schemaCount: ComputedRef<number> = computed(() => schemas.value.length);\n\n /**\n * Total number of items across all schemas\n */\n const totalItems: ComputedRef<number> = computed(() => {\n return schemas.value.reduce((sum, schema) => sum + schema.count, 0);\n });\n\n // ==========================================================================\n // Actions\n // ==========================================================================\n\n /**\n * Fetch the list of schemas from the server\n */\n async function fetchSchemas(): Promise<void> {\n loading.value = true;\n error.value = null;\n\n try {\n const response = await fetch('/_api/store');\n if (!response.ok) {\n throw new Error(`Failed to fetch schemas: ${response.statusText}`);\n }\n\n const data = await response.json();\n schemas.value = data.schemas ?? [];\n } catch (err) {\n error.value = err instanceof Error ? err.message : 'Failed to fetch schemas';\n console.error('[ModelsStore] Error fetching schemas:', err);\n } finally {\n loading.value = false;\n }\n }\n\n /**\n * Select a schema and fetch its data\n */\n async function selectSchemaByName(schemaName: string): Promise<void> {\n if (selectedSchema.value === schemaName) return;\n\n selectedSchema.value = schemaName;\n await fetchSchemaData(schemaName);\n }\n\n /**\n * Fetch data for a specific schema\n */\n async function fetchSchemaData(schemaName: string): Promise<void> {\n loading.value = true;\n error.value = null;\n\n try {\n const response = await fetch(`/_api/store/${encodeURIComponent(schemaName)}`);\n if (!response.ok) {\n throw new Error(`Failed to fetch schema data: ${response.statusText}`);\n }\n\n const data: SchemaData = await response.json();\n const items = data.items ?? [];\n // Clone items to avoid shared references between current and original\n currentItems.value = safeClone(items);\n originalItems.value = safeClone(items);\n isDirtyFlag.value = false;\n\n // Update schema count in the list\n const schemaIndex = schemas.value.findIndex((s) => s.name === schemaName);\n if (schemaIndex !== -1) {\n schemas.value[schemaIndex].count = data.count;\n }\n } catch (err) {\n error.value = err instanceof Error ? err.message : 'Failed to fetch schema data';\n console.error('[ModelsStore] Error fetching schema data:', err);\n } finally {\n loading.value = false;\n }\n }\n\n /**\n * Update the current items (for editing)\n */\n function updateItems(items: unknown): void {\n // Validate that items is an array\n if (!Array.isArray(items)) {\n error.value = 'Invalid data: Expected an array of items';\n console.error('[ModelsStore] updateItems received non-array value:', typeof items);\n return;\n }\n\n currentItems.value = items;\n // Clear any previous validation errors\n error.value = null;\n // Mark as dirty since items were updated\n isDirtyFlag.value = true;\n }\n\n /**\n * Save the current items to the server\n */\n async function saveItems(): Promise<boolean> {\n if (!selectedSchema.value) {\n error.value = 'No schema selected';\n return false;\n }\n\n loading.value = true;\n error.value = null;\n\n try {\n const response = await fetch(`/_api/store/${encodeURIComponent(selectedSchema.value)}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(currentItems.value),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new Error(errorData.error || `Failed to save items: ${response.statusText}`);\n }\n\n const result = await response.json();\n\n // Update original items to match saved items\n originalItems.value = safeClone(currentItems.value);\n isDirtyFlag.value = false;\n\n // Update schema count\n const schemaIndex = schemas.value.findIndex((s) => s.name === selectedSchema.value);\n if (schemaIndex !== -1) {\n schemas.value[schemaIndex].count = result.created ?? currentItems.value.length;\n }\n\n return true;\n } catch (err) {\n error.value = err instanceof Error ? err.message : 'Failed to save items';\n console.error('[ModelsStore] Error saving items:', err);\n return false;\n } finally {\n loading.value = false;\n }\n }\n\n /**\n * Clear all items for the current schema\n */\n async function clearSchema(): Promise<boolean> {\n if (!selectedSchema.value) {\n error.value = 'No schema selected';\n return false;\n }\n\n loading.value = true;\n error.value = null;\n\n try {\n const response = await fetch(`/_api/store/${encodeURIComponent(selectedSchema.value)}`, {\n method: 'DELETE',\n });\n\n if (!response.ok) {\n throw new Error(`Failed to clear schema: ${response.statusText}`);\n }\n\n // Update local state\n currentItems.value = [];\n originalItems.value = [];\n isDirtyFlag.value = false;\n\n // Update schema count\n const schemaIndex = schemas.value.findIndex((s) => s.name === selectedSchema.value);\n if (schemaIndex !== -1) {\n schemas.value[schemaIndex].count = 0;\n }\n\n return true;\n } catch (err) {\n error.value = err instanceof Error ? err.message : 'Failed to clear schema';\n console.error('[ModelsStore] Error clearing schema:', err);\n return false;\n } finally {\n loading.value = false;\n }\n }\n\n /**\n * Discard changes and revert to original items\n */\n function discardChanges(): void {\n currentItems.value = safeClone(originalItems.value);\n isDirtyFlag.value = false;\n }\n\n /**\n * Refresh the current schema data from the server\n */\n async function refresh(): Promise<void> {\n if (selectedSchema.value) {\n await fetchSchemaData(selectedSchema.value);\n } else {\n await fetchSchemas();\n }\n }\n\n /**\n * Reset the store state\n */\n function reset(): void {\n schemas.value = [];\n selectedSchema.value = null;\n currentItems.value = [];\n originalItems.value = [];\n loading.value = false;\n error.value = null;\n isDirtyFlag.value = false;\n }\n\n /**\n * Handle store update from WebSocket event\n */\n function handleStoreUpdate(data: { schema: string; action: string; count: number }): void {\n const schemaIndex = schemas.value.findIndex((s) => s.name === data.schema);\n if (schemaIndex !== -1) {\n schemas.value[schemaIndex].count = data.count;\n }\n\n // If the updated schema is currently selected, refresh it only if no unsaved changes\n if (selectedSchema.value === data.schema) {\n if (!isDirty.value) {\n fetchSchemaData(data.schema);\n } else {\n // Don't auto-refresh when there are unsaved changes\n console.warn(\n `[ModelsStore] Skipping auto-refresh for schema \"${data.schema}\" - unsaved changes exist`,\n );\n }\n }\n }\n\n /**\n * Handle reseed completion from WebSocket event\n */\n function handleReseedComplete(data: { success: boolean; schemas: string[] }): void {\n if (data.success) {\n // Refresh schema list\n fetchSchemas();\n\n // Refresh current schema data only if no unsaved changes\n if (selectedSchema.value) {\n if (!isDirty.value) {\n fetchSchemaData(selectedSchema.value);\n } else {\n console.warn(\n `[ModelsStore] Skipping auto-refresh after reseed for schema \"${selectedSchema.value}\" - unsaved changes exist`,\n );\n }\n }\n }\n }\n\n // ==========================================================================\n // Return store interface\n // ==========================================================================\n\n return {\n // State\n schemas,\n selectedSchema,\n currentItems,\n loading,\n error,\n\n // Computed\n currentSchema,\n isDirty,\n schemaCount,\n totalItems,\n\n // Actions\n fetchSchemas,\n selectSchemaByName,\n fetchSchemaData,\n updateItems,\n saveItems,\n clearSchema,\n discardChanges,\n refresh,\n reset,\n handleStoreUpdate,\n handleReseedComplete,\n };\n});\n\nexport type ModelsStore = ReturnType<typeof useModelsStore>;\n","/**\n * Registry Store\n *\n * What: Pinia store for managing endpoint registry data\n * How: Fetches and caches endpoint data from the server via WebSocket\n * Why: Provides reactive access to endpoint data for the Routes Page\n *\n * @module stores/registry\n */\n\nimport { defineStore } from 'pinia';\nimport { computed, ref } from 'vue';\n\n/**\n * HTTP method type\n */\nexport type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete' | 'options' | 'head' | 'trace';\n\n/**\n * Security requirement from OpenAPI spec\n */\nexport interface SecurityRequirement {\n name: string;\n scopes: string[];\n}\n\n/**\n * Endpoint entry from the server\n */\nexport interface EndpointEntry {\n key: string;\n operationId: string;\n method: HttpMethod;\n path: string;\n summary?: string;\n description?: string;\n tags: string[];\n responseSchema?: string;\n hasHandler: boolean;\n hasSeed: boolean;\n security: SecurityRequirement[];\n}\n\n/**\n * Registry statistics\n */\nexport interface RegistryStats {\n totalEndpoints: number;\n withCustomHandler: number;\n totalSchemas: number;\n withCustomSeed: number;\n autoGenerated: number;\n}\n\n/**\n * Registry data from server\n */\nexport interface RegistryData {\n endpoints: EndpointEntry[];\n stats: RegistryStats;\n}\n\n/**\n * Grouped endpoints by tag\n */\nexport interface EndpointGroup {\n tag: string;\n endpoints: EndpointEntry[];\n isExpanded: boolean;\n}\n\n/**\n * Filter options for endpoints\n */\nexport interface EndpointFilter {\n methods: HttpMethod[];\n hasHandler: boolean | null;\n hasSeed: boolean | null;\n tags: string[];\n}\n\n/**\n * Registry store for endpoint data management\n *\n * Provides:\n * - Endpoint data storage and retrieval\n * - Grouping by tags\n * - Search and filter functionality\n * - Selected endpoint tracking\n */\nexport const useRegistryStore = defineStore('registry', () => {\n // ==========================================================================\n // State\n // ==========================================================================\n\n /** All endpoints from the server */\n const endpoints = ref<EndpointEntry[]>([]);\n\n /** Registry statistics */\n const stats = ref<RegistryStats>({\n totalEndpoints: 0,\n withCustomHandler: 0,\n totalSchemas: 0,\n withCustomSeed: 0,\n autoGenerated: 0,\n });\n\n /** Loading state */\n const isLoading = ref(false);\n\n /** Error state */\n const error = ref<string | null>(null);\n\n /** Search query */\n const searchQuery = ref('');\n\n /** Active filters */\n const filter = ref<EndpointFilter>({\n methods: [],\n hasHandler: null,\n hasSeed: null,\n tags: [],\n });\n\n /** Currently selected endpoint key */\n const selectedEndpointKey = ref<string | null>(null);\n\n /** Expanded tag groups */\n const expandedTags = ref<Set<string>>(new Set());\n\n // ==========================================================================\n // Getters / Computed\n // ==========================================================================\n\n /**\n * All unique tags from endpoints\n */\n const allTags = computed(() => {\n const tagSet = new Set<string>();\n for (const endpoint of endpoints.value) {\n for (const tag of endpoint.tags) {\n tagSet.add(tag);\n }\n }\n return Array.from(tagSet).sort();\n });\n\n /**\n * All unique response schemas\n */\n const allSchemas = computed(() => {\n const schemaSet = new Set<string>();\n for (const endpoint of endpoints.value) {\n if (endpoint.responseSchema) {\n schemaSet.add(endpoint.responseSchema);\n }\n }\n return Array.from(schemaSet).sort();\n });\n\n /**\n * Filtered endpoints based on search and filters\n */\n const filteredEndpoints = computed(() => {\n let result = endpoints.value;\n\n // Apply search query\n if (searchQuery.value.trim()) {\n const query = searchQuery.value.toLowerCase().trim();\n result = result.filter((endpoint) => {\n return (\n endpoint.path.toLowerCase().includes(query) ||\n endpoint.operationId.toLowerCase().includes(query) ||\n endpoint.summary?.toLowerCase().includes(query) ||\n endpoint.tags.some((tag) => tag.toLowerCase().includes(query))\n );\n });\n }\n\n // Apply method filter\n if (filter.value.methods.length > 0) {\n result = result.filter((endpoint) => filter.value.methods.includes(endpoint.method));\n }\n\n // Apply handler filter\n if (filter.value.hasHandler !== null) {\n result = result.filter((endpoint) => endpoint.hasHandler === filter.value.hasHandler);\n }\n\n // Apply seed filter\n if (filter.value.hasSeed !== null) {\n result = result.filter((endpoint) => endpoint.hasSeed === filter.value.hasSeed);\n }\n\n // Apply tag filter\n if (filter.value.tags.length > 0) {\n result = result.filter((endpoint) =>\n endpoint.tags.some((tag) => filter.value.tags.includes(tag)),\n );\n }\n\n return result;\n });\n\n /**\n * Endpoints grouped by tag\n *\n * Grouping logic (from PRD):\n * 1. By tags (if they exist in spec)\n * 2. Fallback: By response schema\n * 3. Final fallback: By first path segment\n */\n const groupedEndpoints = computed((): EndpointGroup[] => {\n const groups = new Map<string, EndpointEntry[]>();\n\n for (const endpoint of filteredEndpoints.value) {\n // Determine group key\n let groupKey: string;\n\n if (endpoint.tags.length > 0) {\n // Use first tag as group\n groupKey = endpoint.tags[0];\n } else if (endpoint.responseSchema) {\n // Fallback to response schema\n groupKey = endpoint.responseSchema;\n } else {\n // Final fallback: first path segment\n const segments = endpoint.path.split('/').filter(Boolean);\n groupKey = segments[0] || 'Other';\n }\n\n if (!groups.has(groupKey)) {\n groups.set(groupKey, []);\n }\n groups.get(groupKey)?.push(endpoint);\n }\n\n // Convert to array and sort\n return Array.from(groups.entries())\n .map(([tag, eps]) => ({\n tag,\n endpoints: eps.sort((a, b) => a.path.localeCompare(b.path)),\n isExpanded: expandedTags.value.has(tag),\n }))\n .sort((a, b) => a.tag.localeCompare(b.tag));\n });\n\n /**\n * Currently selected endpoint\n */\n const selectedEndpoint = computed(() => {\n if (!selectedEndpointKey.value) return null;\n return endpoints.value.find((e) => e.key === selectedEndpointKey.value) ?? null;\n });\n\n /**\n * Count of endpoints with custom handlers\n */\n const handlerCount = computed(() => endpoints.value.filter((e) => e.hasHandler).length);\n\n /**\n * Count of endpoints with seed data\n */\n const seedCount = computed(() => endpoints.value.filter((e) => e.hasSeed).length);\n\n // ==========================================================================\n // Actions\n // ==========================================================================\n\n /**\n * Set registry data from server response\n */\n function setRegistryData(data: RegistryData): void {\n endpoints.value = data.endpoints;\n stats.value = data.stats;\n error.value = null;\n\n // Auto-expand all groups initially\n for (const endpoint of data.endpoints) {\n if (endpoint.tags.length > 0) {\n expandedTags.value.add(endpoint.tags[0]);\n }\n }\n }\n\n /**\n * Set loading state\n */\n function setLoading(loading: boolean): void {\n isLoading.value = loading;\n }\n\n /**\n * Set error state\n */\n function setError(errorMessage: string): void {\n error.value = errorMessage;\n isLoading.value = false;\n }\n\n /**\n * Clear error state\n */\n function clearError(): void {\n error.value = null;\n }\n\n /**\n * Set search query\n */\n function setSearchQuery(query: string): void {\n searchQuery.value = query;\n }\n\n /**\n * Toggle method filter\n */\n function toggleMethodFilter(method: HttpMethod): void {\n const index = filter.value.methods.indexOf(method);\n if (index === -1) {\n filter.value.methods.push(method);\n } else {\n filter.value.methods.splice(index, 1);\n }\n }\n\n /**\n * Set handler filter\n */\n function setHandlerFilter(hasHandler: boolean | null): void {\n filter.value.hasHandler = hasHandler;\n }\n\n /**\n * Set seed filter\n */\n function setSeedFilter(hasSeed: boolean | null): void {\n filter.value.hasSeed = hasSeed;\n }\n\n /**\n * Toggle tag filter\n */\n function toggleTagFilter(tag: string): void {\n const index = filter.value.tags.indexOf(tag);\n if (index === -1) {\n filter.value.tags.push(tag);\n } else {\n filter.value.tags.splice(index, 1);\n }\n }\n\n /**\n * Clear all filters\n */\n function clearFilters(): void {\n filter.value = {\n methods: [],\n hasHandler: null,\n hasSeed: null,\n tags: [],\n };\n searchQuery.value = '';\n }\n\n /**\n * Check if any filter is active\n */\n function hasActiveFilters(): boolean {\n return (\n searchQuery.value.trim() !== '' ||\n filter.value.methods.length > 0 ||\n filter.value.hasHandler !== null ||\n filter.value.hasSeed !== null ||\n filter.value.tags.length > 0\n );\n }\n\n /**\n * Select an endpoint by key\n */\n function selectEndpoint(key: string | null): void {\n selectedEndpointKey.value = key;\n }\n\n /**\n * Toggle group expansion\n */\n function toggleGroup(tag: string): void {\n if (expandedTags.value.has(tag)) {\n expandedTags.value.delete(tag);\n } else {\n expandedTags.value.add(tag);\n }\n }\n\n /**\n * Expand all groups\n */\n function expandAllGroups(): void {\n for (const group of groupedEndpoints.value) {\n expandedTags.value.add(group.tag);\n }\n }\n\n /**\n * Collapse all groups\n */\n function collapseAllGroups(): void {\n expandedTags.value.clear();\n }\n\n /**\n * Update handler status for endpoints\n * Called when handlers are reloaded\n */\n function updateHandlerStatus(handlerOperationIds: string[]): void {\n const handlerSet = new Set(handlerOperationIds);\n for (const endpoint of endpoints.value) {\n endpoint.hasHandler = handlerSet.has(endpoint.operationId);\n }\n }\n\n /**\n * Update seed status for endpoints\n * Called when seeds are reloaded\n */\n function updateSeedStatus(seedSchemas: string[]): void {\n const seedSet = new Set(seedSchemas);\n for (const endpoint of endpoints.value) {\n endpoint.hasSeed = endpoint.responseSchema ? seedSet.has(endpoint.responseSchema) : false;\n }\n }\n\n // ==========================================================================\n // Return\n // ==========================================================================\n\n return {\n // State\n endpoints,\n stats,\n isLoading,\n error,\n searchQuery,\n filter,\n selectedEndpointKey,\n expandedTags,\n\n // Getters\n allTags,\n allSchemas,\n filteredEndpoints,\n groupedEndpoints,\n selectedEndpoint,\n handlerCount,\n seedCount,\n\n // Actions\n setRegistryData,\n setLoading,\n setError,\n clearError,\n setSearchQuery,\n toggleMethodFilter,\n setHandlerFilter,\n setSeedFilter,\n toggleTagFilter,\n clearFilters,\n hasActiveFilters,\n selectEndpoint,\n toggleGroup,\n expandAllGroups,\n collapseAllGroups,\n updateHandlerStatus,\n updateSeedStatus,\n };\n});\n","/**\n * Simulation Store\n *\n * What: Pinia store for managing error and delay simulations\n * How: Manages simulation state and communicates with server via WebSocket\n * Why: Enables developers to test error handling and loading states\n *\n * @module stores/simulation\n */\n\nimport { defineStore } from 'pinia';\nimport { computed, ref } from 'vue';\n\n/**\n * Simulation preset type\n */\nexport type SimulationPresetType = 'delay' | 'error' | 'empty';\n\n/**\n * Simulation preset definition\n */\nexport interface SimulationPreset {\n id: string;\n label: string;\n description: string;\n type: SimulationPresetType;\n status: number;\n delay?: number;\n body?: unknown;\n}\n\n/**\n * Active simulation state\n */\nexport interface ActiveSimulation {\n path: string;\n operationId?: string;\n status: number;\n delay?: number;\n body?: unknown;\n presetId?: string;\n}\n\n/**\n * Preset definitions matching PRD FR-104 requirements\n */\nexport const SIMULATION_PRESETS: SimulationPreset[] = [\n {\n id: 'slow-network',\n label: 'Slow Network',\n description: '3000ms delay (3G simulation)',\n type: 'delay',\n status: 200,\n delay: 3000,\n },\n {\n id: 'server-error',\n label: 'Server Error',\n description: 'Returns HTTP 500',\n type: 'error',\n status: 500,\n body: { error: 'Internal Server Error', message: 'Simulated server error' },\n },\n {\n id: 'rate-limit',\n label: 'Rate Limited',\n description: 'Returns HTTP 429',\n type: 'error',\n status: 429,\n body: { error: 'Too Many Requests', message: 'Rate limit exceeded' },\n },\n {\n id: 'not-found',\n label: 'Not Found',\n description: 'Returns HTTP 404',\n type: 'error',\n status: 404,\n body: { error: 'Not Found', message: 'Resource not found' },\n },\n {\n id: 'request-timeout',\n label: 'Request Timeout',\n description: '30000ms delay (simulates timeout)',\n type: 'delay',\n status: 200,\n delay: 30000,\n },\n {\n id: 'empty-response',\n label: 'Empty Response',\n description: 'Returns HTTP 200 with empty body',\n type: 'empty',\n status: 200,\n body: null,\n },\n {\n id: 'unauthorized',\n label: 'Unauthorized',\n description: 'Returns HTTP 401',\n type: 'error',\n status: 401,\n body: { error: 'Unauthorized', message: 'Authentication required' },\n },\n];\n\n/**\n * Simulation store for managing endpoint simulations\n *\n * Provides:\n * - Active simulations storage and retrieval\n * - Preset definitions and lookup\n * - WebSocket command integration\n * - Simulation count and status tracking\n */\nexport const useSimulationStore = defineStore('simulation', () => {\n // ==========================================================================\n // State\n // ==========================================================================\n\n /**\n * Active simulations keyed by path\n * One simulation per path (enforced by Map)\n */\n const simulations = ref<Map<string, ActiveSimulation>>(new Map());\n\n /**\n * Previous simulation state for rollback on failure\n * Keyed by path, stores the simulation before optimistic update\n */\n const previousSimulations = ref<Map<string, ActiveSimulation | null>>(new Map());\n\n /**\n * Loading state for async operations\n */\n const isLoading = ref(false);\n\n /**\n * Error state\n */\n const error = ref<string | null>(null);\n\n // ==========================================================================\n // Getters / Computed\n // ==========================================================================\n\n /**\n * All active simulations as an array\n */\n const activeSimulations = computed(() => {\n return Array.from(simulations.value.values());\n });\n\n /**\n * Count of active simulations\n */\n const count = computed(() => simulations.value.size);\n\n /**\n * Available presets\n */\n const presets = computed(() => SIMULATION_PRESETS);\n\n /**\n * Check if any simulations are active\n */\n const hasActiveSimulations = computed(() => simulations.value.size > 0);\n\n /**\n * Get simulations grouped by type\n */\n const simulationsByType = computed(() => {\n const grouped = {\n delay: [] as ActiveSimulation[],\n error: [] as ActiveSimulation[],\n empty: [] as ActiveSimulation[],\n };\n\n for (const simulation of simulations.value.values()) {\n const type = getSimulationType(simulation);\n grouped[type].push(simulation);\n }\n\n return grouped;\n });\n\n /**\n * Determine simulation type from simulation config\n */\n function getSimulationType(simulation: ActiveSimulation): SimulationPresetType {\n const preset = simulation.presetId\n ? SIMULATION_PRESETS.find((p) => p.id === simulation.presetId)\n : null;\n\n if (preset) {\n return preset.type;\n }\n\n if (simulation.delay && simulation.delay > 0) {\n return 'delay';\n }\n\n if (simulation.body === null) {\n return 'empty';\n }\n\n return 'error';\n }\n\n // ==========================================================================\n // Actions\n // ==========================================================================\n\n /**\n * Set active simulations from server (e.g., on 'simulation:active' event)\n */\n function setSimulations(newSimulations: ActiveSimulation[]): void {\n simulations.value.clear();\n for (const simulation of newSimulations) {\n simulations.value.set(simulation.path, simulation);\n }\n error.value = null;\n }\n\n /**\n * Add a new simulation locally\n * Note: This updates local state only. Use addSimulation() to sync with server.\n * @param storeForRollback - If true, stores previous state for rollback\n */\n function addSimulationLocal(simulation: ActiveSimulation, storeForRollback = false): void {\n if (storeForRollback) {\n // Store previous state (null if didn't exist)\n const previous = simulations.value.get(simulation.path) || null;\n previousSimulations.value.set(simulation.path, previous);\n }\n simulations.value.set(simulation.path, simulation);\n }\n\n /**\n * Remove a simulation locally by path\n * Note: This updates local state only. Use removeSimulation() to sync with server.\n * @param storeForRollback - If true, stores previous state for rollback\n */\n function removeSimulationLocal(path: string, storeForRollback = false): boolean {\n if (storeForRollback) {\n // Store previous state before removing\n const previous = simulations.value.get(path) || null;\n previousSimulations.value.set(path, previous);\n }\n return simulations.value.delete(path);\n }\n\n /**\n * Clear all simulations locally\n * Note: This updates local state only. Use clearSimulations() to sync with server.\n */\n function clearSimulationsLocal(): void {\n simulations.value.clear();\n }\n\n /**\n * Get a simulation by path\n */\n function getSimulation(path: string): ActiveSimulation | undefined {\n return simulations.value.get(path);\n }\n\n /**\n * Check if a simulation exists for a path\n */\n function hasSimulation(path: string): boolean {\n return simulations.value.has(path);\n }\n\n /**\n * Get a preset by ID\n */\n function getPreset(id: string): SimulationPreset | undefined {\n return SIMULATION_PRESETS.find((p) => p.id === id);\n }\n\n /**\n * Create a simulation from a preset\n */\n function createSimulationFromPreset(\n path: string,\n presetId: string,\n operationId?: string,\n ): ActiveSimulation | null {\n const preset = getPreset(presetId);\n if (!preset) {\n error.value = `Preset not found: ${presetId}`;\n return null;\n }\n\n return {\n path,\n operationId,\n status: preset.status,\n delay: preset.delay,\n body: preset.body,\n presetId: preset.id,\n };\n }\n\n /**\n * Set loading state\n */\n function setLoading(loading: boolean): void {\n isLoading.value = loading;\n }\n\n /**\n * Set error state\n */\n function setError(errorMessage: string): void {\n error.value = errorMessage;\n isLoading.value = false;\n }\n\n /**\n * Clear error state\n */\n function clearError(): void {\n error.value = null;\n }\n\n /**\n * Rollback a simulation to its previous state\n * @param path - The path of the simulation to rollback\n */\n function rollbackSimulation(path: string): void {\n if (!previousSimulations.value.has(path)) {\n return;\n }\n\n const previous = previousSimulations.value.get(path);\n if (previous === null || previous === undefined) {\n // Was added optimistically, remove it\n simulations.value.delete(path);\n } else {\n // Restore previous state\n simulations.value.set(path, previous);\n }\n\n // Clear rollback data\n previousSimulations.value.delete(path);\n }\n\n /**\n * Handle simulation:added event from server\n */\n function handleSimulationAdded(data: { path: string }): void {\n // Server will send 'simulation:active' event with full state\n // This event is just a notification\n console.log('[Simulation] Added:', data.path);\n }\n\n /**\n * Handle simulation:removed event from server\n */\n function handleSimulationRemoved(data: { path: string }): void {\n removeSimulationLocal(data.path);\n console.log('[Simulation] Removed:', data.path);\n }\n\n /**\n * Handle simulations:cleared event from server\n */\n function handleSimulationsCleared(data: { count: number }): void {\n clearSimulationsLocal();\n console.log('[Simulation] Cleared all:', data.count);\n }\n\n /**\n * Handle simulation:set response from server\n */\n function handleSimulationSet(data: { path: string; success: boolean }): void {\n if (data.success) {\n // Clear rollback data on success\n previousSimulations.value.delete(data.path);\n console.log('[Simulation] Set successfully:', data.path);\n } else {\n // Rollback optimistic update on failure\n rollbackSimulation(data.path);\n setError(`Failed to set simulation for ${data.path}`);\n }\n setLoading(false);\n }\n\n /**\n * Handle simulation:cleared response from server\n */\n function handleSimulationCleared(data: { path: string; success: boolean }): void {\n if (data.success) {\n // Clear rollback data on success\n previousSimulations.value.delete(data.path);\n console.log('[Simulation] Cleared successfully:', data.path);\n } else {\n // Rollback optimistic removal on failure\n rollbackSimulation(data.path);\n setError(`Failed to clear simulation for ${data.path}`);\n }\n setLoading(false);\n }\n\n // ==========================================================================\n // Return\n // ==========================================================================\n\n return {\n // State\n simulations,\n isLoading,\n error,\n\n // Getters\n activeSimulations,\n count,\n presets,\n hasActiveSimulations,\n simulationsByType,\n\n // Actions\n setSimulations,\n addSimulationLocal,\n removeSimulationLocal,\n clearSimulationsLocal,\n getSimulation,\n hasSimulation,\n getPreset,\n createSimulationFromPreset,\n setLoading,\n setError,\n clearError,\n rollbackSimulation,\n\n // Event handlers\n handleSimulationAdded,\n handleSimulationRemoved,\n handleSimulationsCleared,\n handleSimulationSet,\n handleSimulationCleared,\n };\n});\n","/**\n * Timeline Store\n *\n * What: Pinia store for managing request/response timeline data\n * How: Receives and stores timeline events from the server via WebSocket\n * Why: Provides reactive access to timeline data for the Timeline Page\n *\n * @module stores/timeline\n */\n\nimport { defineStore } from 'pinia';\nimport { computed, ref } from 'vue';\n\n/**\n * HTTP method type for timeline entries\n */\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'TRACE';\n\n/**\n * Request log entry from the server\n */\nexport interface RequestLogEntry {\n id: string;\n method: string;\n path: string;\n operationId: string;\n timestamp: number;\n headers: Record<string, string>;\n query: Record<string, string | string[]>;\n body?: unknown;\n}\n\n/**\n * Response log entry from the server\n */\nexport interface ResponseLogEntry {\n id: string;\n requestId: string;\n status: number;\n duration: number;\n headers: Record<string, string>;\n body: unknown;\n simulated: boolean;\n}\n\n/**\n * Combined timeline entry with request and optional response\n */\nexport interface TimelineEntry {\n id: string;\n request: RequestLogEntry;\n response: ResponseLogEntry | null;\n status: number | null;\n duration: number | null;\n simulated: boolean;\n}\n\n/**\n * Timeline data from server\n */\nexport interface TimelineData {\n entries: Array<{ type: 'request' | 'response'; data: RequestLogEntry | ResponseLogEntry }>;\n count: number;\n total: number;\n}\n\n/**\n * Filter options for timeline entries\n */\nexport interface TimelineFilter {\n methods: HttpMethod[];\n statusCodes: ('1xx' | '2xx' | '3xx' | '4xx' | '5xx')[];\n searchQuery: string;\n simulatedOnly: boolean | null;\n}\n\n/**\n * Timeline store for request/response tracking\n *\n * Provides:\n * - Timeline entry storage and retrieval\n * - Real-time updates via WebSocket events\n * - Search and filter functionality\n * - Selected entry tracking for detail view\n * - Timeline limit management\n */\nexport const useTimelineStore = defineStore('timeline', () => {\n // ==========================================================================\n // State\n // ==========================================================================\n\n /** All timeline entries (request + response pairs) */\n const entries = ref<TimelineEntry[]>([]);\n\n /** Loading state */\n const isLoading = ref(false);\n\n /** Error state */\n const error = ref<string | null>(null);\n\n /** Active filters */\n const filter = ref<TimelineFilter>({\n methods: [],\n statusCodes: [],\n searchQuery: '',\n simulatedOnly: null,\n });\n\n /** Currently selected entry ID */\n const selectedEntryId = ref<string | null>(null);\n\n /** Maximum number of entries to keep */\n const maxEntries = ref(500);\n\n /** Buffer for responses that arrived before their requests */\n const responseBuffer = new Map<string, ResponseLogEntry>();\n\n // ==========================================================================\n // Getters / Computed\n // ==========================================================================\n\n /**\n * Get status category from status code\n */\n function getStatusCategory(status: number): '1xx' | '2xx' | '3xx' | '4xx' | '5xx' {\n if (status < 200) return '1xx';\n if (status < 300) return '2xx';\n if (status < 400) return '3xx';\n if (status < 500) return '4xx';\n return '5xx';\n }\n\n /**\n * Filtered entries based on search and filters\n */\n const filteredEntries = computed(() => {\n let result = entries.value;\n\n // Apply search query (matches path or operationId)\n if (filter.value.searchQuery.trim()) {\n const query = filter.value.searchQuery.toLowerCase().trim();\n result = result.filter((entry) => {\n return (\n entry.request.path.toLowerCase().includes(query) ||\n entry.request.operationId.toLowerCase().includes(query)\n );\n });\n }\n\n // Apply method filter\n if (filter.value.methods.length > 0) {\n result = result.filter((entry) =>\n filter.value.methods.includes(entry.request.method.toUpperCase() as HttpMethod),\n );\n }\n\n // Apply status code filter\n if (filter.value.statusCodes.length > 0) {\n result = result.filter((entry) => {\n if (entry.status === null) return false;\n const category = getStatusCategory(entry.status);\n return filter.value.statusCodes.includes(category);\n });\n }\n\n // Apply simulated filter\n if (filter.value.simulatedOnly !== null) {\n result = result.filter((entry) => entry.simulated === filter.value.simulatedOnly);\n }\n\n return result;\n });\n\n /**\n * Currently selected entry\n */\n const selectedEntry = computed(() => {\n if (!selectedEntryId.value) return null;\n return entries.value.find((e) => e.id === selectedEntryId.value) ?? null;\n });\n\n /**\n * Total number of entries (including pending responses)\n */\n const totalCount = computed(() => entries.value.length);\n\n /**\n * Count of entries with responses\n */\n const completedCount = computed(() => entries.value.filter((e) => e.response !== null).length);\n\n /**\n * Count of pending requests (no response yet)\n */\n const pendingCount = computed(() => entries.value.filter((e) => e.response === null).length);\n\n /**\n * Count of entries by status category\n */\n const statusCounts = computed(() => {\n const counts = {\n '1xx': 0,\n '2xx': 0,\n '3xx': 0,\n '4xx': 0,\n '5xx': 0,\n };\n\n for (const entry of entries.value) {\n if (entry.status !== null) {\n const category = getStatusCategory(entry.status);\n counts[category]++;\n }\n }\n\n return counts;\n });\n\n /**\n * Average response duration in milliseconds\n */\n const averageDuration = computed(() => {\n const completedEntries = entries.value.filter((e) => e.duration !== null);\n if (completedEntries.length === 0) return 0;\n\n const totalDuration = completedEntries.reduce((sum, e) => sum + (e.duration ?? 0), 0);\n return Math.round(totalDuration / completedEntries.length);\n });\n\n // ==========================================================================\n // Actions\n // ==========================================================================\n\n /**\n * Add a request to the timeline\n */\n function addRequest(request: RequestLogEntry): void {\n const entry: TimelineEntry = {\n id: request.id,\n request,\n response: null,\n status: null,\n duration: null,\n simulated: false,\n };\n\n // Check if there's a buffered response for this request\n const bufferedResponse = responseBuffer.get(request.id);\n if (bufferedResponse) {\n mergeResponse(entry, bufferedResponse);\n // Clear consumed buffered response\n responseBuffer.delete(request.id);\n }\n\n // Add to beginning of array (newest first)\n entries.value.unshift(entry);\n\n // Trim to max entries\n if (entries.value.length > maxEntries.value) {\n entries.value = entries.value.slice(0, maxEntries.value);\n }\n }\n\n /**\n * Add a response to an existing request\n */\n function addResponse(response: ResponseLogEntry): void {\n const entry = entries.value.find((e) => e.id === response.requestId);\n if (entry) {\n // Entry exists, merge immediately\n mergeResponse(entry, response);\n // Clear from buffer if it was buffered\n responseBuffer.delete(response.requestId);\n } else {\n // Entry doesn't exist yet, buffer the response\n responseBuffer.set(response.requestId, response);\n\n // Prevent unbounded buffer growth: create stub entry if buffer exceeds threshold\n // This ensures orphaned responses don't cause memory leaks in real-time scenarios\n if (responseBuffer.size > 100) {\n const stubEntry = createStubEntry(response);\n entries.value.unshift(stubEntry);\n responseBuffer.delete(response.requestId);\n\n // Trim to max entries\n if (entries.value.length > maxEntries.value) {\n entries.value = entries.value.slice(0, maxEntries.value);\n }\n }\n }\n }\n\n /**\n * Merge a response into an entry\n */\n function mergeResponse(entry: TimelineEntry, response: ResponseLogEntry): void {\n entry.response = response;\n entry.status = response.status;\n entry.duration = response.duration;\n entry.simulated = response.simulated;\n }\n\n /**\n * Create a stub entry for an orphaned response\n */\n function createStubEntry(response: ResponseLogEntry): TimelineEntry {\n // Create a minimal request stub for the orphaned response\n const stubRequest: RequestLogEntry = {\n id: response.requestId,\n method: 'UNKNOWN',\n path: '/unknown',\n operationId: 'unknown',\n timestamp: Date.now(), // Use current time as fallback\n headers: {},\n query: {},\n body: undefined,\n };\n\n return {\n id: response.requestId,\n request: stubRequest,\n response,\n status: response.status,\n duration: response.duration,\n simulated: response.simulated,\n };\n }\n\n /**\n * Process buffered responses and merge with existing entries or create stubs\n */\n function processBufferedResponses(requestMap: Map<string, TimelineEntry>): void {\n for (const [requestId, response] of responseBuffer) {\n const entry = requestMap.get(requestId);\n if (entry) {\n mergeResponse(entry, response);\n responseBuffer.delete(requestId);\n } else {\n // No matching request found, create stub entry\n requestMap.set(requestId, createStubEntry(response));\n responseBuffer.delete(requestId);\n }\n }\n }\n\n /**\n * Process incoming responses and merge, buffer, or create stub entries\n */\n function processIncomingResponses(\n requestMap: Map<string, TimelineEntry>,\n incomingResponses: Map<string, ResponseLogEntry>,\n ): void {\n for (const [requestId, response] of incomingResponses) {\n const entry = requestMap.get(requestId);\n if (entry) {\n mergeResponse(entry, response);\n } else {\n // Buffer the response for potential future request\n // Note: During initial load, we'll create stubs later\n responseBuffer.set(requestId, response);\n }\n }\n }\n\n /**\n * Create stub entries for any remaining buffered responses\n * This ensures no response is lost even if its request never arrives\n */\n function createStubsForOrphanedResponses(requestMap: Map<string, TimelineEntry>): void {\n for (const [requestId, response] of responseBuffer) {\n if (!requestMap.has(requestId)) {\n requestMap.set(requestId, createStubEntry(response));\n responseBuffer.delete(requestId);\n }\n }\n }\n\n /**\n * Set timeline data from server response\n * Used when fetching initial timeline data\n */\n function setTimelineData(data: TimelineData): void {\n const requestMap = new Map<string, TimelineEntry>();\n const incomingResponses = new Map<string, ResponseLogEntry>();\n\n // First pass: collect all requests and responses\n for (const item of data.entries) {\n if (item.type === 'request') {\n const request = item.data as RequestLogEntry;\n requestMap.set(request.id, {\n id: request.id,\n request,\n response: null,\n status: null,\n duration: null,\n simulated: false,\n });\n } else if (item.type === 'response') {\n const response = item.data as ResponseLogEntry;\n incomingResponses.set(response.requestId, response);\n }\n }\n\n // Second pass: merge responses with requests\n processBufferedResponses(requestMap);\n processIncomingResponses(requestMap, incomingResponses);\n\n // Third pass: create stub entries for any remaining orphaned responses\n // This ensures no response is lost even if its request never arrives\n createStubsForOrphanedResponses(requestMap);\n\n // Convert map to array and sort by timestamp (newest first)\n const sorted = Array.from(requestMap.values()).sort(\n (a, b) => b.request.timestamp - a.request.timestamp,\n );\n\n // Apply maxEntries limit\n entries.value = sorted.slice(0, maxEntries.value);\n\n error.value = null;\n }\n\n /**\n * Clear all timeline entries\n */\n function clearTimeline(): void {\n entries.value = [];\n selectedEntryId.value = null;\n responseBuffer.clear();\n }\n\n /**\n * Set loading state\n */\n function setLoading(loading: boolean): void {\n isLoading.value = loading;\n }\n\n /**\n * Set error state\n */\n function setError(errorMessage: string): void {\n error.value = errorMessage;\n isLoading.value = false;\n }\n\n /**\n * Clear error state\n */\n function clearError(): void {\n error.value = null;\n }\n\n /**\n * Set search query\n */\n function setSearchQuery(query: string): void {\n filter.value.searchQuery = query;\n }\n\n /**\n * Toggle method filter\n */\n function toggleMethodFilter(method: HttpMethod): void {\n const index = filter.value.methods.indexOf(method);\n if (index === -1) {\n filter.value.methods.push(method);\n } else {\n filter.value.methods.splice(index, 1);\n }\n }\n\n /**\n * Toggle status code filter\n */\n function toggleStatusFilter(status: '1xx' | '2xx' | '3xx' | '4xx' | '5xx'): void {\n const index = filter.value.statusCodes.indexOf(status);\n if (index === -1) {\n filter.value.statusCodes.push(status);\n } else {\n filter.value.statusCodes.splice(index, 1);\n }\n }\n\n /**\n * Set simulated filter\n */\n function setSimulatedFilter(simulated: boolean | null): void {\n filter.value.simulatedOnly = simulated;\n }\n\n /**\n * Clear all filters\n */\n function clearFilters(): void {\n filter.value = {\n methods: [],\n statusCodes: [],\n searchQuery: '',\n simulatedOnly: null,\n };\n }\n\n /**\n * Check if any filter is active\n */\n function hasActiveFilters(): boolean {\n return (\n filter.value.searchQuery.trim() !== '' ||\n filter.value.methods.length > 0 ||\n filter.value.statusCodes.length > 0 ||\n filter.value.simulatedOnly !== null\n );\n }\n\n /**\n * Select an entry by ID\n */\n function selectEntry(id: string | null): void {\n selectedEntryId.value = id;\n }\n\n /**\n * Set maximum entries limit\n */\n function setMaxEntries(limit: number): void {\n // Clamp limit to a safe minimum\n const clamped = Math.max(1, limit);\n maxEntries.value = clamped;\n\n // Trim if necessary\n if (entries.value.length > clamped) {\n entries.value = entries.value.slice(0, clamped);\n }\n }\n\n // ==========================================================================\n // Return\n // ==========================================================================\n\n return {\n // State\n entries,\n isLoading,\n error,\n filter,\n selectedEntryId,\n maxEntries,\n\n // Getters\n filteredEntries,\n selectedEntry,\n totalCount,\n completedCount,\n pendingCount,\n statusCounts,\n averageDuration,\n\n // Actions\n addRequest,\n addResponse,\n setTimelineData,\n clearTimeline,\n setLoading,\n setError,\n clearError,\n setSearchQuery,\n toggleMethodFilter,\n toggleStatusFilter,\n setSimulatedFilter,\n clearFilters,\n hasActiveFilters,\n selectEntry,\n setMaxEntries,\n };\n});\n","/**\n * useTheme Composable\n *\n * What: Provides reactive theme management for the DevTools SPA\n * How: Uses CSS class on document root and localStorage for persistence\n * Why: Allows users to switch between dark and light mode, respecting system preference\n */\n\nimport { computed, getCurrentInstance, onMounted, onUnmounted, ref, watch } from 'vue';\n\n/**\n * Theme mode type\n */\nexport type ThemeMode = 'light' | 'dark' | 'system';\n\n/**\n * Valid theme modes for type guard validation\n */\nconst VALID_THEME_MODES: readonly ThemeMode[] = ['light', 'dark', 'system'];\n\n/**\n * Type guard to check if a value is a valid ThemeMode\n */\nfunction isThemeMode(value: unknown): value is ThemeMode {\n return typeof value === 'string' && VALID_THEME_MODES.includes(value as ThemeMode);\n}\n\n/**\n * Storage key for persisting theme preference\n */\nconst STORAGE_KEY = 'openapi-devtools-theme';\n\n/**\n * Singleton state for theme - shared across all component instances\n */\nconst themeMode = ref<ThemeMode>('system');\nconst systemPrefersDark = ref(false);\n\n/**\n * Track the current mediaQuery and handler for cleanup\n */\nlet currentMediaQuery: MediaQueryList | null = null;\nlet currentMediaHandler: ((e: MediaQueryListEvent) => void) | null = null;\n\n/**\n * Check if we're running in a browser environment\n */\nfunction isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Check if we're inside a Vue component context\n * This allows the composable to work both inside and outside components\n */\nfunction hasComponentContext(): boolean {\n return getCurrentInstance() !== null;\n}\n\n/**\n * useTheme composable\n *\n * Provides theme management functionality including:\n * - Reactive theme state\n * - System preference detection\n * - Theme toggling\n * - LocalStorage persistence\n *\n * @returns Theme management utilities\n */\nexport function useTheme() {\n /**\n * Computed property for the effective theme (resolved from system if needed)\n */\n const effectiveTheme = computed<'light' | 'dark'>(() => {\n if (themeMode.value === 'system') {\n return systemPrefersDark.value ? 'dark' : 'light';\n }\n return themeMode.value;\n });\n\n /**\n * Computed property indicating if dark mode is active\n */\n const isDark = computed(() => effectiveTheme.value === 'dark');\n\n /**\n * Apply the current theme to the document\n */\n function applyTheme(): void {\n if (!isBrowser()) return;\n\n const root = document.documentElement;\n\n if (effectiveTheme.value === 'dark') {\n root.classList.add('dark');\n root.classList.remove('light');\n } else {\n root.classList.add('light');\n root.classList.remove('dark');\n }\n }\n\n /**\n * Set the theme mode\n */\n function setTheme(mode: ThemeMode): void {\n if (!isThemeMode(mode)) {\n console.warn(`[DevTools] Invalid theme mode: ${mode}`);\n return;\n }\n\n themeMode.value = mode;\n\n if (isBrowser()) {\n try {\n localStorage.setItem(STORAGE_KEY, mode);\n } catch {\n // Storage unavailable (private browsing, quota exceeded, etc.)\n console.warn('[DevTools] Unable to persist theme preference');\n }\n }\n }\n\n /**\n * Toggle between light and dark mode\n * If currently in system mode, switch to the opposite of system preference\n */\n function toggleTheme(): void {\n if (themeMode.value === 'system') {\n // Switch to explicit mode opposite of system preference\n setTheme(systemPrefersDark.value ? 'light' : 'dark');\n } else {\n // Toggle between light and dark\n setTheme(themeMode.value === 'dark' ? 'light' : 'dark');\n }\n }\n\n /**\n * Reset to system preference\n */\n function resetToSystem(): void {\n setTheme('system');\n }\n\n /**\n * Clean up the media query listener\n */\n function cleanupMediaQuery(): void {\n if (currentMediaQuery && currentMediaHandler) {\n currentMediaQuery.removeEventListener('change', currentMediaHandler);\n currentMediaQuery = null;\n currentMediaHandler = null;\n }\n }\n\n /**\n * Initialize theme from storage and system preference\n */\n function initialize(): void {\n if (!isBrowser()) return;\n\n // Clean up any existing media query listener before adding a new one\n cleanupMediaQuery();\n\n // Check system preference\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\n systemPrefersDark.value = mediaQuery.matches;\n\n // Create and store the handler for cleanup\n const handler = (e: MediaQueryListEvent): void => {\n systemPrefersDark.value = e.matches;\n };\n\n // Listen for system preference changes\n mediaQuery.addEventListener('change', handler);\n\n // Store references for cleanup\n currentMediaQuery = mediaQuery;\n currentMediaHandler = handler;\n\n // Load saved preference from localStorage\n try {\n const saved = localStorage.getItem(STORAGE_KEY);\n if (isThemeMode(saved)) {\n themeMode.value = saved;\n }\n } catch {\n // Storage unavailable (private browsing, etc.)\n }\n\n // Apply initial theme\n applyTheme();\n }\n\n /**\n * Reset theme state to defaults (useful for testing)\n * This resets the singleton state and cleans up listeners\n */\n function resetState(): void {\n cleanupMediaQuery();\n themeMode.value = 'system';\n systemPrefersDark.value = false;\n\n if (isBrowser()) {\n const root = document.documentElement;\n root.classList.remove('dark', 'light');\n\n try {\n localStorage.removeItem(STORAGE_KEY);\n } catch {\n // Storage unavailable\n }\n }\n }\n\n // Watch for theme changes and apply them\n watch([themeMode, systemPrefersDark], () => {\n applyTheme();\n });\n\n // Only register lifecycle hooks when inside a Vue component context\n // This allows the composable to be used in tests without Vue warnings\n if (hasComponentContext()) {\n // Initialize on mount\n onMounted(() => {\n initialize();\n });\n\n // Clean up on unmount\n onUnmounted(() => {\n cleanupMediaQuery();\n });\n }\n\n return {\n /**\n * Current theme mode setting ('light', 'dark', or 'system')\n */\n themeMode: computed(() => themeMode.value),\n\n /**\n * The effective theme after resolving 'system' mode\n */\n effectiveTheme,\n\n /**\n * Whether dark mode is currently active\n */\n isDark,\n\n /**\n * Whether the system prefers dark mode\n */\n systemPrefersDark: computed(() => systemPrefersDark.value),\n\n /**\n * Set the theme mode\n */\n setTheme,\n\n /**\n * Toggle between light and dark mode\n */\n toggleTheme,\n\n /**\n * Reset to system preference\n */\n resetToSystem,\n\n /**\n * Manually initialize theme (useful for SSR hydration)\n */\n initialize,\n\n /**\n * Reset theme state to defaults (useful for testing)\n */\n resetState,\n };\n}\n","/**\n * Main Entry Point for DevTools SPA\n *\n * What: Initializes and mounts the Vue application\n * How: Creates Vue app instance with Pinia and Vue Router\n * Why: Required entry point for the DevTools SPA\n */\n\nimport { createPinia } from 'pinia';\nimport type { App } from 'vue';\nimport { createApp } from 'vue';\n\nimport AppComponent from '@/App.vue';\nimport router from '@/router';\nimport { initializeStores } from '@/stores';\n\n// Import global styles\nimport '@/assets/main.css';\n\n/**\n * Module-scoped guard to ensure bootstrap only runs once\n */\nlet isBootstrapped = false;\nlet appInstance: App | null = null;\n\n/**\n * Create and configure the Vue application\n * This function is idempotent - calling it multiple times has no effect\n * after the first successful call.\n *\n * @returns The Vue app instance, or null if already bootstrapped\n */\nfunction bootstrap(): App | null {\n // Guard against multiple bootstrap calls\n if (isBootstrapped) {\n if (import.meta.env.DEV) {\n console.warn('[OpenAPI DevTools] Application already initialized, skipping bootstrap');\n }\n return appInstance;\n }\n\n // Create Vue app instance\n const app = createApp(AppComponent);\n\n // Create Pinia store instance\n const pinia = createPinia();\n\n // Install plugins\n app.use(pinia);\n app.use(router);\n\n // Initialize stores after Pinia is installed\n initializeStores();\n\n // Mount the app to the DOM\n app.mount('#app');\n\n // Mark as bootstrapped and store the instance\n isBootstrapped = true;\n appInstance = app;\n\n // Log startup info in development\n if (import.meta.env.DEV) {\n console.log('[OpenAPI DevTools] Application initialized');\n }\n\n return app;\n}\n\n// Only auto-bootstrap when running as standalone app (index.html entry)\n// When imported as a library, consumers should call bootstrap() manually\nif (typeof window !== 'undefined' && document.getElementById('app')) {\n bootstrap();\n}\n\n/**\n * Export the bootstrap function for library consumers\n * who may want to manually initialize the DevTools\n */\nexport { bootstrap };\n\nexport type {\n ClientCommand,\n ClientCommandType,\n ConnectedEventData,\n ConnectionState,\n EventHandler,\n ServerEvent,\n ServerEventType,\n ThemeMode,\n UseWebSocketOptions,\n UseWebSocketReturn,\n} from '@/composables';\n// Re-export composables for library consumers\nexport { useTheme, useWebSocket } from '@/composables';\n","/**\n * Format Utilities\n *\n * What: Shared formatting functions for display purposes\n * How: Provides consistent formatting across components\n * Why: Centralizes common formatting logic to avoid duplication (DRY)\n *\n * @module utils/format\n */\n\n/**\n * Get display label for HTTP method\n *\n * Converts an HTTP method to its uppercase display format.\n *\n * @param method - The HTTP method string (e.g., 'get', 'post')\n * @returns The uppercase method label (e.g., 'GET', 'POST')\n *\n * @example\n * getMethodLabel('get') // Returns 'GET'\n * getMethodLabel('post') // Returns 'POST'\n */\nexport function getMethodLabel(method: string): string {\n return method.toUpperCase();\n}\n","<!--\n EndpointDetail.vue - Endpoint Detail Panel Component\n\n What: Displays detailed information about a selected API endpoint\n How: Shows method, path, operation ID, tags, summary, description, and status indicators\n Why: Provides comprehensive endpoint information for developers using the DevTools\n-->\n\n<script setup lang=\"ts\">\nimport { Code, FileJson, Lock, Shield, Sprout, Tag } from 'lucide-vue-next';\nimport { computed } from 'vue';\n\nimport type { EndpointEntry } from '@/stores/registry';\nimport { getMethodLabel } from '@/utils/format';\n\n/**\n * Component props\n */\ninterface Props {\n /** Endpoint to display details for */\n endpoint: EndpointEntry | null;\n}\n\nconst props = defineProps<Props>();\n\n/**\n * Check if endpoint has security requirements\n */\nconst hasSecurity = computed(() => {\n return props.endpoint?.security && props.endpoint.security.length > 0;\n});\n\n/**\n * Format security requirements for display\n */\nconst securityDisplay = computed(() => {\n if (!props.endpoint?.security) return [];\n return props.endpoint.security.map((sec) => ({\n name: sec.name,\n scopes: sec.scopes.length > 0 ? sec.scopes.join(', ') : 'No scopes',\n }));\n});\n</script>\n\n<template>\n <div class=\"endpoint-detail\">\n <!-- Empty state when no endpoint selected -->\n <div v-if=\"!endpoint\" class=\"endpoint-detail__empty\">\n <FileJson :size=\"48\" class=\"endpoint-detail__empty-icon\" />\n <h3 class=\"endpoint-detail__empty-title\">No endpoint selected</h3>\n <p class=\"endpoint-detail__empty-text text-muted\">\n Select an endpoint from the list to view its details\n </p>\n </div>\n\n <!-- Endpoint details -->\n <div v-else class=\"endpoint-detail__content\">\n <!-- Header with method and path -->\n <header class=\"endpoint-detail__header\">\n <span\n :class=\"[\n 'method-badge',\n 'method-badge--large',\n `method-badge--${endpoint.method}`\n ]\"\n >\n {{ getMethodLabel(endpoint.method) }}\n </span>\n <h2 class=\"endpoint-detail__path font-mono\">\n {{ endpoint.path }}\n </h2>\n </header>\n\n <!-- Status indicators -->\n <div class=\"endpoint-detail__status\">\n <div\n v-if=\"endpoint.hasHandler\"\n class=\"endpoint-detail__status-item endpoint-detail__status-item--handler\"\n >\n <Code :size=\"14\" />\n <span>Has custom handler</span>\n </div>\n <div\n v-if=\"endpoint.hasSeed\"\n class=\"endpoint-detail__status-item endpoint-detail__status-item--seed\"\n >\n <Sprout :size=\"14\" />\n <span>Has seed data</span>\n </div>\n <div\n v-if=\"hasSecurity\"\n class=\"endpoint-detail__status-item endpoint-detail__status-item--security\"\n >\n <Lock :size=\"14\" />\n <span>Requires authentication</span>\n </div>\n <div\n v-if=\"!endpoint.hasHandler && !endpoint.hasSeed\"\n class=\"endpoint-detail__status-item endpoint-detail__status-item--auto\"\n >\n <FileJson :size=\"14\" />\n <span>Auto-generated response</span>\n </div>\n </div>\n\n <!-- Info sections -->\n <div class=\"endpoint-detail__sections\">\n <!-- Operation ID -->\n <section class=\"endpoint-detail__section\">\n <h3 class=\"endpoint-detail__section-title\">Operation</h3>\n <p class=\"endpoint-detail__section-content font-mono\">\n {{ endpoint.operationId }}\n </p>\n </section>\n\n <!-- Tags -->\n <section v-if=\"endpoint.tags.length > 0\" class=\"endpoint-detail__section\">\n <h3 class=\"endpoint-detail__section-title\">\n <Tag :size=\"14\" />\n Tags\n </h3>\n <div class=\"endpoint-detail__tags\">\n <span\n v-for=\"tag in endpoint.tags\"\n :key=\"tag\"\n class=\"endpoint-detail__tag\"\n >\n {{ tag }}\n </span>\n </div>\n </section>\n\n <!-- Summary -->\n <section v-if=\"endpoint.summary\" class=\"endpoint-detail__section\">\n <h3 class=\"endpoint-detail__section-title\">Summary</h3>\n <p class=\"endpoint-detail__section-content\">\n {{ endpoint.summary }}\n </p>\n </section>\n\n <!-- Description -->\n <section v-if=\"endpoint.description\" class=\"endpoint-detail__section\">\n <h3 class=\"endpoint-detail__section-title\">Description</h3>\n <p class=\"endpoint-detail__section-content endpoint-detail__description\">\n {{ endpoint.description }}\n </p>\n </section>\n\n <!-- Response Schema -->\n <section v-if=\"endpoint.responseSchema\" class=\"endpoint-detail__section\">\n <h3 class=\"endpoint-detail__section-title\">\n <FileJson :size=\"14\" />\n Response Schema\n </h3>\n <p class=\"endpoint-detail__section-content font-mono\">\n {{ endpoint.responseSchema }}\n </p>\n </section>\n\n <!-- Security -->\n <section v-if=\"hasSecurity\" class=\"endpoint-detail__section\">\n <h3 class=\"endpoint-detail__section-title\">\n <Shield :size=\"14\" />\n Security\n </h3>\n <div class=\"endpoint-detail__security\">\n <div\n v-for=\"sec in securityDisplay\"\n :key=\"sec.name\"\n class=\"endpoint-detail__security-item\"\n >\n <span class=\"endpoint-detail__security-name font-mono\">\n {{ sec.name }}\n </span>\n <span class=\"endpoint-detail__security-scopes text-muted\">\n {{ sec.scopes }}\n </span>\n </div>\n </div>\n </section>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.endpoint-detail {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n\n/* Empty state */\n.endpoint-detail__empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: var(--devtools-space-xl);\n text-align: center;\n}\n\n.endpoint-detail__empty-icon {\n color: var(--devtools-text-muted);\n opacity: 0.5;\n margin-bottom: var(--devtools-space-md);\n}\n\n.endpoint-detail__empty-title {\n font-size: var(--font-size-2);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text);\n margin: 0 0 var(--devtools-space-sm);\n}\n\n.endpoint-detail__empty-text {\n font-size: var(--font-size-1);\n margin: 0;\n}\n\n/* Content */\n.endpoint-detail__content {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow-y: auto;\n padding: var(--devtools-space-md);\n}\n\n/* Header */\n.endpoint-detail__header {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-md);\n margin-bottom: var(--devtools-space-md);\n padding-bottom: var(--devtools-space-md);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.endpoint-detail__path {\n font-size: var(--font-size-2);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text);\n margin: 0;\n word-break: break-all;\n}\n\n/* Large method badge */\n.method-badge--large {\n font-size: var(--font-size-0);\n padding: var(--devtools-space-sm) var(--devtools-space-md);\n min-width: 70px;\n}\n\n/* Status indicators */\n.endpoint-detail__status {\n display: flex;\n flex-wrap: wrap;\n gap: var(--devtools-space-sm);\n margin-bottom: var(--devtools-space-md);\n}\n\n.endpoint-detail__status-item {\n display: inline-flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n border-radius: var(--devtools-radius-sm);\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n}\n\n.endpoint-detail__status-item--handler {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n color: var(--devtools-info);\n}\n\n.endpoint-detail__status-item--seed {\n background-color: color-mix(in srgb, var(--devtools-success) 15%, transparent);\n color: var(--devtools-success);\n}\n\n.endpoint-detail__status-item--security {\n background-color: color-mix(in srgb, var(--devtools-warning) 15%, transparent);\n color: var(--devtools-warning);\n}\n\n.endpoint-detail__status-item--auto {\n background-color: color-mix(in srgb, var(--devtools-text-muted) 15%, transparent);\n color: var(--devtools-text-muted);\n}\n\n/* Sections */\n.endpoint-detail__sections {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-md);\n}\n\n.endpoint-detail__section {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-xs);\n}\n\n.endpoint-detail__section-title {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-6);\n color: var(--devtools-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin: 0;\n}\n\n.endpoint-detail__section-content {\n font-size: var(--font-size-1);\n color: var(--devtools-text);\n margin: 0;\n line-height: var(--font-lineheight-3);\n}\n\n.endpoint-detail__description {\n white-space: pre-wrap;\n}\n\n/* Tags */\n.endpoint-detail__tags {\n display: flex;\n flex-wrap: wrap;\n gap: var(--devtools-space-xs);\n}\n\n.endpoint-detail__tag {\n display: inline-flex;\n align-items: center;\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n background-color: var(--devtools-surface-elevated);\n border-radius: var(--devtools-radius-sm);\n font-size: var(--font-size-0);\n color: var(--devtools-text);\n}\n\n/* Security */\n.endpoint-detail__security {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-xs);\n}\n\n.endpoint-detail__security-item {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: var(--devtools-space-sm);\n background-color: var(--devtools-surface-elevated);\n border-radius: var(--devtools-radius-sm);\n}\n\n.endpoint-detail__security-name {\n font-size: var(--font-size-1);\n font-weight: var(--font-weight-5);\n}\n\n.endpoint-detail__security-scopes {\n font-size: var(--font-size-0);\n}\n</style>\n","<!--\n EndpointList.vue - Grouped Endpoint Listing Component\n\n What: Displays a list of API endpoints grouped by tags with collapsible sections\n How: Renders endpoint groups from registry store with method badges and selection support\n Why: Provides organized navigation through available mock endpoints\n-->\n\n<script setup lang=\"ts\">\nimport { ChevronDown, ChevronRight, Code, Sprout } from 'lucide-vue-next';\n\nimport type { EndpointEntry, EndpointGroup } from '@/stores/registry';\nimport { getMethodLabel } from '@/utils/format';\n\n/**\n * Component props\n */\ninterface Props {\n /** Grouped endpoints to display */\n groups: EndpointGroup[];\n /** Currently selected endpoint key */\n selectedKey: string | null;\n}\n\nconst props = defineProps<Props>();\n\n/**\n * Component events\n */\nconst emit = defineEmits<{\n /** Emitted when an endpoint is selected */\n (e: 'select', key: string): void;\n /** Emitted when a group is toggled */\n (e: 'toggle-group', tag: string): void;\n}>();\n\n/**\n * Handle endpoint click\n */\nfunction handleEndpointClick(endpoint: EndpointEntry): void {\n emit('select', endpoint.key);\n}\n\n/**\n * Handle group toggle\n */\nfunction handleGroupToggle(tag: string): void {\n emit('toggle-group', tag);\n}\n\n/**\n * Check if endpoint is selected\n */\nfunction isSelected(endpoint: EndpointEntry): boolean {\n return props.selectedKey === endpoint.key;\n}\n</script>\n\n<template>\n <div class=\"endpoint-list\">\n <!-- Empty state -->\n <div v-if=\"groups.length === 0\" class=\"endpoint-list__empty\">\n <p class=\"text-muted\">No endpoints found</p>\n </div>\n\n <!-- Endpoint groups -->\n <div v-else class=\"endpoint-list__groups\">\n <div\n v-for=\"group in groups\"\n :key=\"group.tag\"\n class=\"endpoint-group\"\n >\n <!-- Group header -->\n <button\n type=\"button\"\n class=\"endpoint-group__header\"\n :aria-expanded=\"group.isExpanded\"\n :aria-controls=\"`group-${group.tag}`\"\n @click=\"handleGroupToggle(group.tag)\"\n >\n <component\n :is=\"group.isExpanded ? ChevronDown : ChevronRight\"\n :size=\"16\"\n class=\"endpoint-group__chevron\"\n />\n <span class=\"endpoint-group__tag\">{{ group.tag }}</span>\n <span class=\"endpoint-group__count text-muted\">\n ({{ group.endpoints.length }})\n </span>\n </button>\n\n <!-- Group endpoints -->\n <div\n v-show=\"group.isExpanded\"\n :id=\"`group-${group.tag}`\"\n class=\"endpoint-group__items\"\n role=\"group\"\n :aria-label=\"`${group.tag} endpoints`\"\n >\n <button\n v-for=\"endpoint in group.endpoints\"\n :key=\"endpoint.key\"\n type=\"button\"\n :class=\"[\n 'endpoint-item',\n { 'endpoint-item--selected': isSelected(endpoint) }\n ]\"\n :aria-selected=\"isSelected(endpoint)\"\n @click=\"handleEndpointClick(endpoint)\"\n >\n <!-- Method badge -->\n <span\n :class=\"[\n 'method-badge',\n `method-badge--${endpoint.method}`\n ]\"\n >\n {{ getMethodLabel(endpoint.method) }}\n </span>\n\n <!-- Path -->\n <span class=\"endpoint-item__path font-mono\">\n {{ endpoint.path }}\n </span>\n\n <!-- Status indicators -->\n <div class=\"endpoint-item__indicators\">\n <span\n v-if=\"endpoint.hasHandler\"\n class=\"endpoint-item__indicator endpoint-item__indicator--handler\"\n title=\"Has custom handler\"\n >\n <Code :size=\"12\" />\n </span>\n <span\n v-if=\"endpoint.hasSeed\"\n class=\"endpoint-item__indicator endpoint-item__indicator--seed\"\n title=\"Has seed data\"\n >\n <Sprout :size=\"12\" />\n </span>\n </div>\n </button>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.endpoint-list {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n\n.endpoint-list__empty {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--devtools-space-lg);\n}\n\n.endpoint-list__groups {\n flex: 1;\n overflow-y: auto;\n padding: var(--devtools-space-xs);\n}\n\n/* Group styles */\n.endpoint-group {\n margin-bottom: var(--devtools-space-xs);\n}\n\n.endpoint-group__header {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n width: 100%;\n padding: var(--devtools-space-sm) var(--devtools-space-sm);\n background: none;\n border: none;\n border-radius: var(--devtools-radius-sm);\n font-family: var(--devtools-font-sans);\n font-size: var(--font-size-1);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text);\n text-align: left;\n cursor: pointer;\n transition: background-color var(--devtools-transition-fast);\n}\n\n.endpoint-group__header:hover {\n background-color: var(--devtools-surface-elevated);\n}\n\n.endpoint-group__header:focus {\n outline: none;\n}\n\n.endpoint-group__header:focus-visible {\n outline: 2px solid var(--devtools-primary);\n outline-offset: -2px;\n}\n\n.endpoint-group__chevron {\n flex-shrink: 0;\n color: var(--devtools-text-muted);\n}\n\n.endpoint-group__tag {\n flex: 1;\n text-transform: capitalize;\n}\n\n.endpoint-group__count {\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-4);\n}\n\n.endpoint-group__items {\n padding-left: var(--devtools-space-md);\n}\n\n/* Endpoint item styles */\n.endpoint-item {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n width: 100%;\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n background: none;\n border: none;\n border-radius: var(--devtools-radius-sm);\n font-family: var(--devtools-font-sans);\n text-align: left;\n cursor: pointer;\n transition: background-color var(--devtools-transition-fast);\n}\n\n.endpoint-item:hover {\n background-color: var(--devtools-surface-elevated);\n}\n\n.endpoint-item:focus {\n outline: none;\n}\n\n.endpoint-item:focus-visible {\n outline: 2px solid var(--devtools-primary);\n outline-offset: -2px;\n}\n\n.endpoint-item--selected {\n background-color: color-mix(in srgb, var(--devtools-primary) 15%, transparent);\n}\n\n.endpoint-item--selected:hover {\n background-color: color-mix(in srgb, var(--devtools-primary) 20%, transparent);\n}\n\n.endpoint-item__path {\n flex: 1;\n font-size: var(--font-size-0);\n color: var(--devtools-text);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.endpoint-item__indicators {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n}\n\n.endpoint-item__indicator {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n border-radius: var(--devtools-radius-sm);\n}\n\n.endpoint-item__indicator--handler {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n color: var(--devtools-info);\n}\n\n.endpoint-item__indicator--seed {\n background-color: color-mix(in srgb, var(--devtools-success) 15%, transparent);\n color: var(--devtools-success);\n}\n</style>\n","<!--\n RoutesPage.vue - Endpoint Listing Page\n\n What: Displays a list of all available API endpoints from the OpenAPI spec\n How: Fetches endpoint data via WebSocket and displays in a searchable/filterable list\n Why: Allows developers to quickly browse and inspect available mock endpoints\n-->\n\n<script setup lang=\"ts\">\nimport { ChevronDown, ChevronUp, Code, Filter, Route, Search, Sprout, X } from 'lucide-vue-next';\nimport { computed, onMounted, onUnmounted, ref, watch } from 'vue';\n\nimport EndpointDetail from '@/components/EndpointDetail.vue';\nimport EndpointList from '@/components/EndpointList.vue';\nimport { useWebSocket } from '@/composables/useWebSocket';\nimport { type HttpMethod, type RegistryData, useRegistryStore } from '@/stores/registry';\n\n// Store and WebSocket\nconst registryStore = useRegistryStore();\nconst { send, on, connected } = useWebSocket();\n\n// Local UI state\nconst showFilters = ref(false);\nconst searchInputRef = ref<HTMLInputElement | null>(null);\n\n// HTTP methods for filter (matches HttpMethod type from registry store)\nconst httpMethods: HttpMethod[] = [\n 'get',\n 'post',\n 'put',\n 'patch',\n 'delete',\n 'options',\n 'head',\n 'trace',\n];\n\n/**\n * Fetch registry data when connected\n */\nfunction fetchRegistry(): void {\n if (connected.value) {\n registryStore.setLoading(true);\n send({ type: 'get:registry' });\n }\n}\n\n/**\n * Handle registry data from server\n */\nfunction handleRegistryData(data: RegistryData): void {\n registryStore.setRegistryData(data);\n registryStore.setLoading(false);\n}\n\n/**\n * Handle endpoint selection\n */\nfunction handleSelectEndpoint(key: string): void {\n registryStore.selectEndpoint(key);\n}\n\n/**\n * Handle group toggle\n */\nfunction handleToggleGroup(tag: string): void {\n registryStore.toggleGroup(tag);\n}\n\n/**\n * Handle search input\n */\nfunction handleSearchInput(event: Event): void {\n const target = event.target as HTMLInputElement;\n registryStore.setSearchQuery(target.value);\n}\n\n/**\n * Clear search\n */\nfunction clearSearch(): void {\n registryStore.setSearchQuery('');\n searchInputRef.value?.focus();\n}\n\n/**\n * Toggle method filter\n */\nfunction toggleMethod(method: HttpMethod): void {\n registryStore.toggleMethodFilter(method);\n}\n\n/**\n * Check if method is active in filter\n */\nfunction isMethodActive(method: HttpMethod): boolean {\n return registryStore.filter.methods.includes(method);\n}\n\n/**\n * Toggle handler filter\n */\nfunction toggleHandlerFilter(): void {\n const current = registryStore.filter.hasHandler;\n registryStore.setHandlerFilter(current === true ? null : true);\n}\n\n/**\n * Toggle seed filter\n */\nfunction toggleSeedFilter(): void {\n const current = registryStore.filter.hasSeed;\n registryStore.setSeedFilter(current === true ? null : true);\n}\n\n/**\n * Clear all filters\n */\nfunction clearAllFilters(): void {\n registryStore.clearFilters();\n}\n\n/**\n * Toggle filter panel visibility\n */\nfunction toggleFilters(): void {\n showFilters.value = !showFilters.value;\n}\n\n/**\n * Computed: Has active filters\n */\nconst hasActiveFilters = computed(() => registryStore.hasActiveFilters());\n\n// Event cleanup functions for WebSocket subscriptions\nlet unsubRegistry: (() => void) | null = null;\nlet unsubHandlers: (() => void) | null = null;\nlet unsubSeeds: (() => void) | null = null;\n\n// Subscribe to registry events and setup cleanup\nonMounted(() => {\n // Subscribe to WebSocket events (on() returns unsubscribe function)\n unsubRegistry = on<RegistryData>('registry', handleRegistryData);\n unsubHandlers = on('handlers:updated', () => fetchRegistry());\n unsubSeeds = on('seeds:updated', () => fetchRegistry());\n\n // Fetch registry when already connected\n if (connected.value) {\n fetchRegistry();\n }\n});\n\n// Cleanup event subscriptions on unmount to prevent memory leaks\nonUnmounted(() => {\n unsubRegistry?.();\n unsubHandlers?.();\n unsubSeeds?.();\n});\n\n// Re-fetch when connection is established\nwatch(connected, (isConnected) => {\n if (isConnected) {\n fetchRegistry();\n }\n});\n</script>\n\n<template>\n <div class=\"routes-page\">\n <!-- Toolbar -->\n <div class=\"routes-toolbar\">\n <!-- Search -->\n <div class=\"routes-search\">\n <Search :size=\"16\" class=\"routes-search__icon\" />\n <input\n ref=\"searchInputRef\"\n type=\"text\"\n class=\"routes-search__input input\"\n placeholder=\"Search endpoints...\"\n :value=\"registryStore.searchQuery\"\n @input=\"handleSearchInput\"\n />\n <button\n v-if=\"registryStore.searchQuery\"\n type=\"button\"\n class=\"routes-search__clear btn btn--ghost btn--icon\"\n title=\"Clear search\"\n @click=\"clearSearch\"\n >\n <X :size=\"14\" />\n </button>\n </div>\n\n <!-- Filter toggle -->\n <button\n type=\"button\"\n :class=\"[\n 'routes-filter-toggle btn btn--secondary',\n { 'routes-filter-toggle--active': hasActiveFilters }\n ]\"\n :aria-expanded=\"showFilters\"\n @click=\"toggleFilters\"\n >\n <Filter :size=\"16\" />\n <span>Filters</span>\n <span v-if=\"hasActiveFilters\" class=\"routes-filter-toggle__badge\">\n {{ registryStore.filter.methods.length +\n (registryStore.filter.hasHandler ? 1 : 0) +\n (registryStore.filter.hasSeed ? 1 : 0) }}\n </span>\n <component :is=\"showFilters ? ChevronUp : ChevronDown\" :size=\"14\" />\n </button>\n\n <!-- Stats -->\n <div class=\"routes-stats\">\n <span class=\"routes-stats__item\">\n {{ registryStore.filteredEndpoints.length }} endpoints\n </span>\n <span class=\"routes-stats__separator\">|</span>\n <span class=\"routes-stats__item\">\n {{ registryStore.allTags.length }} tags\n </span>\n </div>\n </div>\n\n <!-- Filter panel -->\n <div v-if=\"showFilters\" class=\"routes-filters\">\n <!-- Method filters -->\n <div class=\"routes-filters__section\">\n <h4 class=\"routes-filters__title\">Methods</h4>\n <div class=\"routes-filters__methods\">\n <button\n v-for=\"method in httpMethods\"\n :key=\"method\"\n type=\"button\"\n :class=\"[\n 'method-badge',\n `method-badge--${method}`,\n { 'method-badge--inactive': !isMethodActive(method) && registryStore.filter.methods.length > 0 }\n ]\"\n @click=\"toggleMethod(method)\"\n >\n {{ method.toUpperCase() }}\n </button>\n </div>\n </div>\n\n <!-- Status filters -->\n <div class=\"routes-filters__section\">\n <h4 class=\"routes-filters__title\">Status</h4>\n <div class=\"routes-filters__status\">\n <button\n type=\"button\"\n :class=\"[\n 'routes-filters__status-btn',\n { 'routes-filters__status-btn--active': registryStore.filter.hasHandler }\n ]\"\n @click=\"toggleHandlerFilter\"\n >\n <Code :size=\"14\" />\n <span>Has Handler</span>\n </button>\n <button\n type=\"button\"\n :class=\"[\n 'routes-filters__status-btn',\n { 'routes-filters__status-btn--active': registryStore.filter.hasSeed }\n ]\"\n @click=\"toggleSeedFilter\"\n >\n <Sprout :size=\"14\" />\n <span>Has Seed</span>\n </button>\n </div>\n </div>\n\n <!-- Clear filters -->\n <div v-if=\"hasActiveFilters\" class=\"routes-filters__actions\">\n <button\n type=\"button\"\n class=\"btn btn--ghost\"\n @click=\"clearAllFilters\"\n >\n <X :size=\"14\" />\n Clear all filters\n </button>\n </div>\n </div>\n\n <!-- Main content: split panel -->\n <div class=\"routes-content\">\n <!-- Loading state -->\n <div v-if=\"registryStore.isLoading\" class=\"routes-loading\">\n <div class=\"routes-loading__spinner\" />\n <span class=\"text-muted\">Loading endpoints...</span>\n </div>\n\n <!-- Error state -->\n <div v-else-if=\"registryStore.error\" class=\"routes-error\">\n <p class=\"routes-error__message\">{{ registryStore.error }}</p>\n <button type=\"button\" class=\"btn btn--primary\" @click=\"fetchRegistry\">\n Retry\n </button>\n </div>\n\n <!-- Empty state -->\n <div v-else-if=\"registryStore.endpoints.length === 0\" class=\"routes-empty empty-state\">\n <Route :size=\"48\" class=\"empty-state__icon\" />\n <h3 class=\"empty-state__title\">No endpoints found</h3>\n <p class=\"empty-state__description\">\n No API endpoints are available. Make sure your OpenAPI spec is loaded.\n </p>\n </div>\n\n <!-- No results state -->\n <div v-else-if=\"registryStore.filteredEndpoints.length === 0\" class=\"routes-empty empty-state\">\n <Search :size=\"48\" class=\"empty-state__icon\" />\n <h3 class=\"empty-state__title\">No matching endpoints</h3>\n <p class=\"empty-state__description\">\n Try adjusting your search or filters.\n </p>\n <button\n v-if=\"hasActiveFilters\"\n type=\"button\"\n class=\"btn btn--secondary\"\n @click=\"clearAllFilters\"\n >\n Clear filters\n </button>\n </div>\n\n <!-- Split panel layout -->\n <template v-else>\n <!-- Endpoint list panel -->\n <div class=\"routes-list-panel\">\n <EndpointList\n :groups=\"registryStore.groupedEndpoints\"\n :selected-key=\"registryStore.selectedEndpointKey\"\n @select=\"handleSelectEndpoint\"\n @toggle-group=\"handleToggleGroup\"\n />\n </div>\n\n <!-- Endpoint detail panel -->\n <div class=\"routes-detail-panel\">\n <EndpointDetail :endpoint=\"registryStore.selectedEndpoint\" />\n </div>\n </template>\n </div>\n </div>\n</template>\n\n<style scoped>\n.routes-page {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n\n/* Toolbar */\n.routes-toolbar {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-md);\n background-color: var(--devtools-surface);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.routes-search {\n position: relative;\n flex: 1;\n max-width: 400px;\n}\n\n.routes-search__icon {\n position: absolute;\n left: var(--devtools-space-sm);\n top: 50%;\n transform: translateY(-50%);\n color: var(--devtools-text-muted);\n pointer-events: none;\n}\n\n.routes-search__input {\n padding-left: calc(var(--devtools-space-sm) + 24px);\n padding-right: calc(var(--devtools-space-sm) + 24px);\n}\n\n.routes-search__clear {\n position: absolute;\n right: var(--devtools-space-xs);\n top: 50%;\n transform: translateY(-50%);\n padding: var(--devtools-space-xs);\n}\n\n.routes-filter-toggle {\n flex-shrink: 0;\n}\n\n.routes-filter-toggle--active {\n background-color: color-mix(in srgb, var(--devtools-primary) 15%, transparent);\n border-color: var(--devtools-primary);\n color: var(--devtools-primary);\n}\n\n.routes-filter-toggle__badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 var(--devtools-space-xs);\n background-color: var(--devtools-primary);\n color: var(--devtools-text-inverted);\n border-radius: 9px;\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-6);\n}\n\n.routes-stats {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n margin-left: auto;\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n}\n\n.routes-stats__separator {\n opacity: 0.5;\n}\n\n/* Filter panel */\n.routes-filters {\n display: flex;\n flex-wrap: wrap;\n align-items: flex-start;\n gap: var(--devtools-space-lg);\n padding: var(--devtools-space-md);\n background-color: var(--devtools-surface-elevated);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.routes-filters__section {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-sm);\n}\n\n.routes-filters__title {\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-6);\n color: var(--devtools-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin: 0;\n}\n\n.routes-filters__methods {\n display: flex;\n flex-wrap: wrap;\n gap: var(--devtools-space-xs);\n}\n\n.routes-filters__methods .method-badge {\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.routes-filters__methods .method-badge--inactive {\n opacity: 0.4;\n}\n\n.routes-filters__status {\n display: flex;\n gap: var(--devtools-space-sm);\n}\n\n.routes-filters__status-btn {\n display: inline-flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n background-color: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-sm);\n font-family: var(--devtools-font-sans);\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.routes-filters__status-btn:hover {\n background-color: var(--devtools-surface-elevated);\n color: var(--devtools-text);\n}\n\n.routes-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-primary) 15%, transparent);\n border-color: var(--devtools-primary);\n color: var(--devtools-primary);\n}\n\n.routes-filters__actions {\n display: flex;\n align-items: flex-end;\n margin-left: auto;\n}\n\n/* Main content */\n.routes-content {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n/* Loading state */\n.routes-loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 100%;\n gap: var(--devtools-space-md);\n}\n\n.routes-loading__spinner {\n width: 32px;\n height: 32px;\n border: 3px solid var(--devtools-border);\n border-top-color: var(--devtools-primary);\n border-radius: 50%;\n animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n/* Error state */\n.routes-error {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 100%;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-xl);\n}\n\n.routes-error__message {\n color: var(--devtools-error);\n margin: 0;\n}\n\n/* Empty state */\n.routes-empty {\n width: 100%;\n}\n\n/* Split panels */\n.routes-list-panel {\n width: var(--devtools-sidebar-width);\n min-width: 200px;\n max-width: 400px;\n border-right: 1px solid var(--devtools-border);\n background-color: var(--devtools-surface);\n overflow: hidden;\n}\n\n.routes-detail-panel {\n flex: 1;\n overflow: hidden;\n background-color: var(--devtools-bg);\n}\n</style>\n","<!--\n TimelineDetail.vue - Timeline Entry Detail Panel\n\n What: Displays full request and response details for a selected timeline entry\n How: Shows headers, query params, body content in organized collapsible sections\n Why: Allows developers to inspect API traffic in detail for debugging\n-->\n\n<script setup lang=\"ts\">\nimport { Check, ChevronDown, ChevronRight, Clock, Copy, Zap } from 'lucide-vue-next';\n\nimport { computed, ref } from 'vue';\n\nimport type { TimelineEntry } from '@/stores/timeline';\n\nimport { getMethodLabel } from '@/utils/format';\n\n/**\n * Component props\n */\ninterface Props {\n /** The timeline entry to display */\n entry: TimelineEntry | null;\n}\n\nconst props = defineProps<Props>();\n\n/**\n * Section expansion state\n */\nconst expandedSections = ref({\n requestHeaders: true,\n requestQuery: true,\n requestBody: true,\n responseHeaders: true,\n responseBody: true,\n});\n\n/**\n * Copy feedback state\n */\nconst copiedField = ref<string | null>(null);\n\n/**\n * Format timestamp for display\n */\nconst formattedTimestamp = computed(() => {\n if (!props.entry) return '';\n const date = new Date(props.entry.request.timestamp);\n return date.toLocaleString('en-US', {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n fractionalSecondDigits: 3,\n hour12: false,\n });\n});\n\n/**\n * Format duration for display\n */\nconst formattedDuration = computed(() => {\n if (props.entry?.duration == null) return 'pending...';\n if (props.entry.duration < 1000) {\n return `${props.entry.duration}ms`;\n }\n return `${(props.entry.duration / 1000).toFixed(2)}s`;\n});\n\n/**\n * Get status badge class based on status code\n */\nconst statusClass = computed(() => {\n if (!props.entry?.status) return 'status-badge--pending';\n if (props.entry.status < 200) return 'status-badge--1xx';\n if (props.entry.status < 300) return 'status-badge--2xx';\n if (props.entry.status < 400) return 'status-badge--3xx';\n if (props.entry.status < 500) return 'status-badge--4xx';\n return 'status-badge--5xx';\n});\n\n/**\n * Check if request has query parameters\n */\nconst hasQueryParams = computed(() => {\n if (!props.entry?.request.query) return false;\n return Object.keys(props.entry.request.query).length > 0;\n});\n\n/**\n * Check if request has headers\n */\nconst hasRequestHeaders = computed(() => {\n if (!props.entry?.request.headers) return false;\n return Object.keys(props.entry.request.headers).length > 0;\n});\n\n/**\n * Check if request has body\n */\nconst hasRequestBody = computed(() => {\n return props.entry?.request.body !== undefined && props.entry?.request.body !== null;\n});\n\n/**\n * Check if response has headers\n */\nconst hasResponseHeaders = computed(() => {\n if (!props.entry?.response?.headers) return false;\n return Object.keys(props.entry.response.headers).length > 0;\n});\n\n/**\n * Check if response has body\n */\nconst hasResponseBody = computed(() => {\n return props.entry?.response?.body !== undefined && props.entry?.response?.body !== null;\n});\n\n/**\n * Format JSON for display\n */\nfunction formatJson(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Toggle section expansion\n */\nfunction toggleSection(section: keyof typeof expandedSections.value): void {\n expandedSections.value[section] = !expandedSections.value[section];\n}\n\n/**\n * Copy text to clipboard\n */\nasync function copyToClipboard(text: string, fieldId: string): Promise<void> {\n try {\n await navigator.clipboard.writeText(text);\n copiedField.value = fieldId;\n setTimeout(() => {\n copiedField.value = null;\n }, 2000);\n } catch (err) {\n console.error('Failed to copy:', err);\n }\n}\n\n/**\n * Copy full entry as JSON\n */\nasync function copyFullEntry(): Promise<void> {\n if (!props.entry) return;\n const data = {\n request: props.entry.request,\n response: props.entry.response,\n };\n await copyToClipboard(JSON.stringify(data, null, 2), 'full');\n}\n</script>\n\n<template>\n <div class=\"timeline-detail\">\n <!-- Empty state -->\n <div v-if=\"!entry\" class=\"timeline-detail__empty\">\n <Clock :size=\"48\" class=\"timeline-detail__empty-icon\" />\n <h3 class=\"timeline-detail__empty-title\">Select an entry</h3>\n <p class=\"timeline-detail__empty-description\">\n Click on a timeline entry to view its details.\n </p>\n </div>\n\n <!-- Entry details -->\n <div v-else class=\"timeline-detail__content\">\n <!-- Header with summary -->\n <div class=\"timeline-detail__header\">\n <div class=\"timeline-detail__summary\">\n <span :class=\"['method-badge', `method-badge--${entry.request.method.toLowerCase()}`]\">\n {{ getMethodLabel(entry.request.method) }}\n </span>\n <span class=\"timeline-detail__path font-mono\">{{ entry.request.path }}</span>\n </div>\n\n <div class=\"timeline-detail__meta\">\n <span v-if=\"entry.status !== null\" :class=\"['status-badge', statusClass]\">\n {{ entry.status }}\n </span>\n <span v-else class=\"status-badge status-badge--pending\">pending</span>\n\n <span class=\"timeline-detail__duration\">\n <Clock :size=\"14\" />\n {{ formattedDuration }}\n </span>\n\n <span v-if=\"entry.simulated\" class=\"timeline-detail__simulated\" title=\"Simulated response\">\n <Zap :size=\"14\" />\n Simulated\n </span>\n </div>\n\n <div class=\"timeline-detail__actions\">\n <button\n type=\"button\"\n class=\"btn btn--ghost btn--sm\"\n title=\"Copy as JSON\"\n @click=\"copyFullEntry\"\n >\n <component :is=\"copiedField === 'full' ? Check : Copy\" :size=\"14\" />\n {{ copiedField === 'full' ? 'Copied!' : 'Copy JSON' }}\n </button>\n </div>\n </div>\n\n <!-- Info section -->\n <div class=\"timeline-detail__info\">\n <div class=\"timeline-detail__info-item\">\n <span class=\"timeline-detail__info-label\">Timestamp</span>\n <span class=\"timeline-detail__info-value font-mono\">{{ formattedTimestamp }}</span>\n </div>\n <div class=\"timeline-detail__info-item\">\n <span class=\"timeline-detail__info-label\">Operation ID</span>\n <span class=\"timeline-detail__info-value font-mono\">{{ entry.request.operationId }}</span>\n </div>\n <div class=\"timeline-detail__info-item\">\n <span class=\"timeline-detail__info-label\">Request ID</span>\n <span class=\"timeline-detail__info-value font-mono\">{{ entry.id }}</span>\n </div>\n </div>\n\n <!-- Request section -->\n <div class=\"timeline-detail__section\">\n <h3 class=\"timeline-detail__section-title\">Request</h3>\n\n <!-- Query Parameters -->\n <div v-if=\"hasQueryParams\" class=\"timeline-detail__subsection\">\n <button\n type=\"button\"\n class=\"timeline-detail__subsection-header\"\n :aria-expanded=\"expandedSections.requestQuery\"\n aria-controls=\"requestQuery-panel\"\n @click=\"toggleSection('requestQuery')\"\n >\n <component\n :is=\"expandedSections.requestQuery ? ChevronDown : ChevronRight\"\n :size=\"16\"\n />\n <span>Query Parameters</span>\n <span class=\"text-muted\">({{ Object.keys(entry.request.query).length }})</span>\n </button>\n <div\n id=\"requestQuery-panel\"\n v-show=\"expandedSections.requestQuery\"\n class=\"timeline-detail__subsection-content\"\n >\n <div\n v-for=\"(value, key) in entry.request.query\"\n :key=\"key\"\n class=\"timeline-detail__kv-row\"\n >\n <span class=\"timeline-detail__kv-key font-mono\">{{ key }}</span>\n <span class=\"timeline-detail__kv-value font-mono\">\n {{ Array.isArray(value) ? value.join(', ') : value }}\n </span>\n </div>\n </div>\n </div>\n\n <!-- Request Headers -->\n <div v-if=\"hasRequestHeaders\" class=\"timeline-detail__subsection\">\n <button\n type=\"button\"\n class=\"timeline-detail__subsection-header\"\n :aria-expanded=\"expandedSections.requestHeaders\"\n aria-controls=\"requestHeaders-panel\"\n @click=\"toggleSection('requestHeaders')\"\n >\n <component\n :is=\"expandedSections.requestHeaders ? ChevronDown : ChevronRight\"\n :size=\"16\"\n />\n <span>Headers</span>\n <span class=\"text-muted\">({{ Object.keys(entry.request.headers).length }})</span>\n </button>\n <div\n id=\"requestHeaders-panel\"\n v-show=\"expandedSections.requestHeaders\"\n class=\"timeline-detail__subsection-content\"\n >\n <div\n v-for=\"(value, key) in entry.request.headers\"\n :key=\"key\"\n class=\"timeline-detail__kv-row\"\n >\n <span class=\"timeline-detail__kv-key font-mono\">{{ key }}</span>\n <span class=\"timeline-detail__kv-value font-mono\">{{ value }}</span>\n </div>\n </div>\n </div>\n\n <!-- Request Body -->\n <div v-if=\"hasRequestBody\" class=\"timeline-detail__subsection\">\n <div class=\"timeline-detail__subsection-header\" role=\"group\">\n <button\n type=\"button\"\n class=\"timeline-detail__subsection-toggle\"\n :aria-expanded=\"expandedSections.requestBody\"\n aria-controls=\"requestBody-panel\"\n @click=\"toggleSection('requestBody')\"\n >\n <component\n :is=\"expandedSections.requestBody ? ChevronDown : ChevronRight\"\n :size=\"16\"\n />\n <span>Body</span>\n </button>\n <button\n type=\"button\"\n class=\"btn btn--ghost btn--icon btn--sm\"\n title=\"Copy body\"\n @click.stop=\"copyToClipboard(formatJson(entry.request.body), 'reqBody')\"\n >\n <component :is=\"copiedField === 'reqBody' ? Check : Copy\" :size=\"12\" />\n </button>\n </div>\n <div\n id=\"requestBody-panel\"\n v-show=\"expandedSections.requestBody\"\n class=\"timeline-detail__subsection-content\"\n >\n <pre class=\"timeline-detail__json\">{{ formatJson(entry.request.body) }}</pre>\n </div>\n </div>\n </div>\n\n <!-- Response section -->\n <div v-if=\"entry.response\" class=\"timeline-detail__section\">\n <h3 class=\"timeline-detail__section-title\">Response</h3>\n\n <!-- Response Headers -->\n <div v-if=\"hasResponseHeaders\" class=\"timeline-detail__subsection\">\n <button\n type=\"button\"\n class=\"timeline-detail__subsection-header\"\n :aria-expanded=\"expandedSections.responseHeaders\"\n aria-controls=\"responseHeaders-panel\"\n @click=\"toggleSection('responseHeaders')\"\n >\n <component\n :is=\"expandedSections.responseHeaders ? ChevronDown : ChevronRight\"\n :size=\"16\"\n />\n <span>Headers</span>\n <span class=\"text-muted\">({{ Object.keys(entry.response.headers).length }})</span>\n </button>\n <div\n id=\"responseHeaders-panel\"\n v-show=\"expandedSections.responseHeaders\"\n class=\"timeline-detail__subsection-content\"\n >\n <div\n v-for=\"(value, key) in entry.response.headers\"\n :key=\"key\"\n class=\"timeline-detail__kv-row\"\n >\n <span class=\"timeline-detail__kv-key font-mono\">{{ key }}</span>\n <span class=\"timeline-detail__kv-value font-mono\">{{ value }}</span>\n </div>\n </div>\n </div>\n\n <!-- Response Body -->\n <div v-if=\"hasResponseBody\" class=\"timeline-detail__subsection\">\n <div class=\"timeline-detail__subsection-header\" role=\"group\">\n <button\n type=\"button\"\n class=\"timeline-detail__subsection-toggle\"\n :aria-expanded=\"expandedSections.responseBody\"\n aria-controls=\"responseBody-panel\"\n @click=\"toggleSection('responseBody')\"\n >\n <component\n :is=\"expandedSections.responseBody ? ChevronDown : ChevronRight\"\n :size=\"16\"\n />\n <span>Body</span>\n </button>\n <button\n type=\"button\"\n class=\"btn btn--ghost btn--icon btn--sm\"\n title=\"Copy body\"\n @click.stop=\"copyToClipboard(formatJson(entry.response.body), 'resBody')\"\n >\n <component :is=\"copiedField === 'resBody' ? Check : Copy\" :size=\"12\" />\n </button>\n </div>\n <div\n id=\"responseBody-panel\"\n v-show=\"expandedSections.responseBody\"\n class=\"timeline-detail__subsection-content\"\n >\n <pre class=\"timeline-detail__json\">{{ formatJson(entry.response.body) }}</pre>\n </div>\n </div>\n </div>\n\n <!-- Pending response state -->\n <div v-else class=\"timeline-detail__section timeline-detail__section--pending\">\n <h3 class=\"timeline-detail__section-title\">Response</h3>\n <div class=\"timeline-detail__pending\">\n <Clock :size=\"24\" class=\"timeline-detail__pending-icon\" />\n <span class=\"text-muted\">Waiting for response...</span>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.timeline-detail {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n\n/* Empty state */\n.timeline-detail__empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: var(--devtools-space-xl);\n text-align: center;\n}\n\n.timeline-detail__empty-icon {\n color: var(--devtools-text-muted);\n opacity: 0.5;\n margin-bottom: var(--devtools-space-md);\n}\n\n.timeline-detail__empty-title {\n font-size: var(--font-size-3);\n font-weight: var(--font-weight-6);\n color: var(--devtools-text);\n margin: 0 0 var(--devtools-space-sm) 0;\n}\n\n.timeline-detail__empty-description {\n font-size: var(--font-size-1);\n color: var(--devtools-text-muted);\n margin: 0;\n}\n\n/* Content */\n.timeline-detail__content {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow-y: auto;\n}\n\n/* Header */\n.timeline-detail__header {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-sm);\n padding: var(--devtools-space-md);\n background-color: var(--devtools-surface);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-detail__summary {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n}\n\n.timeline-detail__path {\n font-size: var(--font-size-2);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text);\n word-break: break-all;\n}\n\n.timeline-detail__meta {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-md);\n}\n\n.timeline-detail__duration {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n}\n\n.timeline-detail__simulated {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n font-size: var(--font-size-0);\n color: var(--devtools-warning);\n}\n\n.timeline-detail__actions {\n display: flex;\n gap: var(--devtools-space-sm);\n}\n\n/* Info section */\n.timeline-detail__info {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-md);\n background-color: var(--devtools-surface-elevated);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-detail__info-item {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-xs);\n}\n\n.timeline-detail__info-label {\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.timeline-detail__info-value {\n font-size: var(--font-size-1);\n color: var(--devtools-text);\n}\n\n/* Section */\n.timeline-detail__section {\n padding: var(--devtools-space-md);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-detail__section:last-child {\n border-bottom: none;\n}\n\n.timeline-detail__section-title {\n font-size: var(--font-size-1);\n font-weight: var(--font-weight-6);\n color: var(--devtools-text);\n margin: 0 0 var(--devtools-space-md) 0;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n/* Subsection */\n.timeline-detail__subsection {\n margin-bottom: var(--devtools-space-sm);\n}\n\n.timeline-detail__subsection:last-child {\n margin-bottom: 0;\n}\n\n.timeline-detail__subsection-header {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n width: 100%;\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n background-color: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-sm);\n}\n\n.timeline-detail__subsection-toggle {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n flex: 1;\n padding: 0;\n background: none;\n border: none;\n font-family: var(--devtools-font-sans);\n font-size: var(--font-size-1);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text);\n text-align: left;\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.timeline-detail__subsection-toggle:hover {\n color: var(--devtools-text-hover);\n}\n\n.timeline-detail__subsection-content {\n margin-top: var(--devtools-space-xs);\n padding: var(--devtools-space-sm);\n background-color: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-sm);\n}\n\n/* Key-value rows */\n.timeline-detail__kv-row {\n display: grid;\n grid-template-columns: minmax(120px, auto) 1fr;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-xs) 0;\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-detail__kv-row:last-child {\n border-bottom: none;\n}\n\n.timeline-detail__kv-key {\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text-muted);\n word-break: break-all;\n}\n\n.timeline-detail__kv-value {\n font-size: var(--font-size-0);\n color: var(--devtools-text);\n word-break: break-all;\n}\n\n/* JSON display */\n.timeline-detail__json {\n margin: 0;\n padding: var(--devtools-space-sm);\n background-color: var(--devtools-bg);\n border-radius: var(--devtools-radius-sm);\n font-family: var(--devtools-font-mono);\n font-size: var(--font-size-0);\n color: var(--devtools-text);\n white-space: pre-wrap;\n word-break: break-all;\n overflow-x: auto;\n}\n\n/* Status badges */\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n padding: 2px var(--devtools-space-sm);\n border-radius: var(--devtools-radius-sm);\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n font-family: var(--devtools-font-mono);\n}\n\n.status-badge--pending {\n background-color: color-mix(in srgb, var(--devtools-text-muted) 15%, transparent);\n color: var(--devtools-text-muted);\n}\n\n.status-badge--1xx {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n color: var(--devtools-info);\n}\n\n.status-badge--2xx {\n background-color: color-mix(in srgb, var(--devtools-success) 15%, transparent);\n color: var(--devtools-success);\n}\n\n.status-badge--3xx {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n color: var(--devtools-info);\n}\n\n.status-badge--4xx {\n background-color: color-mix(in srgb, var(--devtools-warning) 15%, transparent);\n color: var(--devtools-warning);\n}\n\n.status-badge--5xx {\n background-color: color-mix(in srgb, var(--devtools-error) 15%, transparent);\n color: var(--devtools-error);\n}\n\n/* Pending response */\n.timeline-detail__pending {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--devtools-space-sm);\n padding: var(--devtools-space-lg);\n}\n\n.timeline-detail__pending-icon {\n color: var(--devtools-text-muted);\n animation: pulse 2s ease-in-out infinite;\n}\n\n@keyframes pulse {\n 0%, 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.5;\n }\n}\n</style>\n","<!--\n TimelineEntry.vue - Timeline Entry Component\n\n What: Displays a single request/response entry in the timeline\n How: Shows method, path, status, duration with color-coded badges\n Why: Provides consistent visualization of API traffic in the timeline list\n-->\n\n<script setup lang=\"ts\">\nimport { AlertTriangle, CheckCircle, Clock, Zap } from 'lucide-vue-next';\nimport { computed } from 'vue';\n\nimport type { TimelineEntry } from '@/stores/timeline';\n\nimport { getMethodLabel } from '@/utils/format';\n\n/**\n * Component props\n */\ninterface Props {\n /** The timeline entry to display */\n entry: TimelineEntry;\n /** Whether this entry is currently selected */\n isSelected?: boolean;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n isSelected: false,\n});\n\n/**\n * Component events\n */\nconst emit = defineEmits<{\n /** Emitted when the entry is clicked */\n (e: 'select', id: string): void;\n}>();\n\n/**\n * Format timestamp for display\n */\nconst formattedTime = computed(() => {\n const date = new Date(props.entry.request.timestamp);\n return date.toLocaleTimeString('en-US', {\n hour12: false,\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n fractionalSecondDigits: 3,\n });\n});\n\n/**\n * Format duration for display\n */\nconst formattedDuration = computed(() => {\n if (props.entry.duration === null) {\n return 'pending...';\n }\n if (props.entry.duration < 1000) {\n return `${props.entry.duration}ms`;\n }\n return `${(props.entry.duration / 1000).toFixed(2)}s`;\n});\n\n/**\n * Get status badge class based on status code\n */\nconst statusClass = computed(() => {\n if (props.entry.status === null) return 'status-badge--pending';\n if (props.entry.status < 200) return 'status-badge--1xx';\n if (props.entry.status < 300) return 'status-badge--2xx';\n if (props.entry.status < 400) return 'status-badge--3xx';\n if (props.entry.status < 500) return 'status-badge--4xx';\n return 'status-badge--5xx';\n});\n\n/**\n * Status icon component based on status code\n */\nconst statusIcon = computed(() => {\n if (props.entry.status === null) return Clock;\n if (props.entry.status < 400) return CheckCircle;\n return AlertTriangle;\n});\n\n/**\n * Whether the response is pending\n */\nconst isPending = computed(() => props.entry.response === null);\n\n/**\n * Handle entry click\n */\nfunction handleClick(): void {\n emit('select', props.entry.id);\n}\n</script>\n\n<template>\n <button\n type=\"button\"\n :class=\"[\n 'timeline-entry',\n { 'timeline-entry--selected': isSelected },\n { 'timeline-entry--pending': isPending },\n { 'timeline-entry--simulated': entry.simulated }\n ]\"\n @click=\"handleClick\"\n >\n <!-- Timestamp -->\n <div class=\"timeline-entry__time font-mono text-muted\">\n {{ formattedTime }}\n </div>\n\n <!-- Method badge -->\n <div class=\"timeline-entry__method\">\n <span :class=\"['method-badge', `method-badge--${entry.request.method.toLowerCase()}`]\">\n {{ getMethodLabel(entry.request.method) }}\n </span>\n </div>\n\n <!-- Path -->\n <div class=\"timeline-entry__path font-mono\">\n {{ entry.request.path }}\n </div>\n\n <!-- Status badge -->\n <div class=\"timeline-entry__status\">\n <span v-if=\"entry.status !== null\" :class=\"['status-badge', statusClass]\">\n <component :is=\"statusIcon\" :size=\"12\" />\n {{ entry.status }}\n </span>\n <span v-else class=\"status-badge status-badge--pending\">\n <Clock :size=\"12\" />\n pending\n </span>\n </div>\n\n <!-- Duration -->\n <div class=\"timeline-entry__duration font-mono text-muted\">\n {{ formattedDuration }}\n </div>\n\n <!-- Simulated indicator -->\n <div v-if=\"entry.simulated\" class=\"timeline-entry__simulated\" title=\"Simulated response\">\n <Zap :size=\"14\" />\n </div>\n </button>\n</template>\n\n<style scoped>\n.timeline-entry {\n display: grid;\n grid-template-columns: 100px 80px 1fr auto 80px auto;\n align-items: center;\n gap: var(--devtools-space-md);\n width: 100%;\n padding: var(--devtools-space-sm) var(--devtools-space-md);\n background: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-sm);\n font-family: var(--devtools-font-sans);\n text-align: left;\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.timeline-entry:hover {\n background-color: var(--devtools-surface-elevated);\n border-color: var(--devtools-border-hover);\n}\n\n.timeline-entry:focus {\n outline: none;\n}\n\n.timeline-entry:focus-visible {\n outline: 2px solid var(--devtools-primary);\n outline-offset: -2px;\n}\n\n.timeline-entry--selected {\n background-color: color-mix(in srgb, var(--devtools-primary) 10%, transparent);\n border-color: var(--devtools-primary);\n}\n\n.timeline-entry--selected:hover {\n background-color: color-mix(in srgb, var(--devtools-primary) 15%, transparent);\n}\n\n.timeline-entry--pending {\n opacity: 0.7;\n}\n\n.timeline-entry--simulated {\n border-left: 3px solid var(--devtools-warning);\n}\n\n/* Time column */\n.timeline-entry__time {\n font-size: var(--font-size-0);\n}\n\n/* Path column */\n.timeline-entry__path {\n font-size: var(--font-size-1);\n color: var(--devtools-text);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Status column */\n.timeline-entry__status {\n display: flex;\n align-items: center;\n}\n\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n padding: 2px var(--devtools-space-sm);\n border-radius: var(--devtools-radius-sm);\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n font-family: var(--devtools-font-mono);\n}\n\n.status-badge--pending {\n background-color: color-mix(in srgb, var(--devtools-text-muted) 15%, transparent);\n color: var(--devtools-text-muted);\n}\n\n.status-badge--1xx {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n color: var(--devtools-info);\n}\n\n.status-badge--2xx {\n background-color: color-mix(in srgb, var(--devtools-success) 15%, transparent);\n color: var(--devtools-success);\n}\n\n.status-badge--3xx {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n color: var(--devtools-info);\n}\n\n.status-badge--4xx {\n background-color: color-mix(in srgb, var(--devtools-warning) 15%, transparent);\n color: var(--devtools-warning);\n}\n\n.status-badge--5xx {\n background-color: color-mix(in srgb, var(--devtools-error) 15%, transparent);\n color: var(--devtools-error);\n}\n\n/* Duration column */\n.timeline-entry__duration {\n font-size: var(--font-size-0);\n text-align: right;\n}\n\n/* Simulated indicator */\n.timeline-entry__simulated {\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--devtools-warning);\n}\n</style>\n","<!--\n TimelinePage.vue - Request/Response Timeline Page\n\n What: Displays a real-time timeline of API requests and responses\n How: Subscribes to WebSocket events and displays request/response logs with filtering\n Why: Allows developers to monitor and debug API traffic in real-time\n-->\n\n<script setup lang=\"ts\">\nimport { ChevronDown, ChevronUp, Clock, Filter, Search, Trash2, X } from 'lucide-vue-next';\nimport { computed, onMounted, onUnmounted, ref, watch } from 'vue';\n\nimport TimelineDetail from '@/components/TimelineDetail.vue';\nimport TimelineEntryComponent from '@/components/TimelineEntry.vue';\nimport { useWebSocket } from '@/composables/useWebSocket';\nimport {\n type HttpMethod,\n type RequestLogEntry,\n type ResponseLogEntry,\n type TimelineData,\n useTimelineStore,\n} from '@/stores/timeline';\n\n// Store and WebSocket\nconst timelineStore = useTimelineStore();\nconst { send, on, connected } = useWebSocket();\n\n// Local UI state\nconst showFilters = ref(false);\nconst searchInputRef = ref<HTMLInputElement | null>(null);\n\n// HTTP methods for filter\nconst httpMethods: HttpMethod[] = [\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'OPTIONS',\n 'HEAD',\n 'TRACE',\n];\n\n// Status categories for filter\nconst statusCategories = ['2xx', '3xx', '4xx', '5xx'] as const;\n\n/**\n * Fetch timeline data when connected\n */\nfunction fetchTimeline(): void {\n if (connected.value) {\n timelineStore.setLoading(true);\n send({ type: 'get:timeline' });\n }\n}\n\n/**\n * Handle timeline data from server\n */\nfunction handleTimelineData(data: TimelineData): void {\n timelineStore.setTimelineData(data);\n timelineStore.setLoading(false);\n}\n\n/**\n * Handle incoming request event\n */\nfunction handleRequest(data: RequestLogEntry): void {\n timelineStore.addRequest(data);\n}\n\n/**\n * Handle incoming response event\n */\nfunction handleResponse(data: ResponseLogEntry): void {\n timelineStore.addResponse(data);\n}\n\n/**\n * Handle timeline cleared event\n */\nfunction handleTimelineCleared(): void {\n timelineStore.clearTimeline();\n}\n\n/**\n * Clear timeline on server and locally\n */\nfunction clearTimeline(): void {\n send({ type: 'clear:timeline' });\n timelineStore.clearTimeline();\n}\n\n/**\n * Handle entry selection\n */\nfunction handleSelectEntry(id: string): void {\n timelineStore.selectEntry(id);\n}\n\n/**\n * Handle search input\n */\nfunction handleSearchInput(event: Event): void {\n const target = event.target as HTMLInputElement;\n timelineStore.setSearchQuery(target.value);\n}\n\n/**\n * Clear search\n */\nfunction clearSearch(): void {\n timelineStore.setSearchQuery('');\n searchInputRef.value?.focus();\n}\n\n/**\n * Toggle method filter\n */\nfunction toggleMethod(method: HttpMethod): void {\n timelineStore.toggleMethodFilter(method);\n}\n\n/**\n * Check if method is active in filter\n */\nfunction isMethodActive(method: HttpMethod): boolean {\n return timelineStore.filter.methods.includes(method);\n}\n\n/**\n * Toggle status filter\n */\nfunction toggleStatus(status: '1xx' | '2xx' | '3xx' | '4xx' | '5xx'): void {\n timelineStore.toggleStatusFilter(status);\n}\n\n/**\n * Check if status is active in filter\n */\nfunction isStatusActive(status: '1xx' | '2xx' | '3xx' | '4xx' | '5xx'): boolean {\n return timelineStore.filter.statusCodes.includes(status);\n}\n\n/**\n * Toggle simulated filter\n */\nfunction toggleSimulatedFilter(): void {\n const current = timelineStore.filter.simulatedOnly;\n timelineStore.setSimulatedFilter(current === true ? null : true);\n}\n\n/**\n * Clear all filters\n */\nfunction clearAllFilters(): void {\n timelineStore.clearFilters();\n}\n\n/**\n * Toggle filter panel visibility\n */\nfunction toggleFilters(): void {\n showFilters.value = !showFilters.value;\n}\n\n/**\n * Computed: Has active filters\n */\nconst hasActiveFilters = computed(() => timelineStore.hasActiveFilters());\n\n/**\n * Computed: Filter badge count\n */\nconst filterBadgeCount = computed(() => {\n return (\n timelineStore.filter.methods.length +\n timelineStore.filter.statusCodes.length +\n (timelineStore.filter.simulatedOnly !== null ? 1 : 0)\n );\n});\n\n// Event cleanup functions for WebSocket subscriptions\nlet unsubTimeline: (() => void) | null = null;\nlet unsubRequest: (() => void) | null = null;\nlet unsubResponse: (() => void) | null = null;\nlet unsubCleared: (() => void) | null = null;\n\n// Subscribe to timeline events and setup cleanup\nonMounted(() => {\n // Subscribe to WebSocket events\n unsubTimeline = on<TimelineData>('timeline', handleTimelineData);\n unsubRequest = on<RequestLogEntry>('request', handleRequest);\n unsubResponse = on<ResponseLogEntry>('response', handleResponse);\n unsubCleared = on('timeline:cleared', handleTimelineCleared);\n\n // Fetch timeline when already connected\n if (connected.value) {\n fetchTimeline();\n }\n});\n\n// Cleanup event subscriptions on unmount\nonUnmounted(() => {\n unsubTimeline?.();\n unsubRequest?.();\n unsubResponse?.();\n unsubCleared?.();\n});\n\n// Re-fetch when connection is established\nwatch(connected, (isConnected) => {\n if (isConnected) {\n fetchTimeline();\n }\n});\n</script>\n\n<template>\n <div class=\"timeline-page\">\n <!-- Toolbar -->\n <div class=\"timeline-toolbar\">\n <!-- Search -->\n <div class=\"timeline-search\">\n <Search :size=\"16\" class=\"timeline-search__icon\" />\n <input\n ref=\"searchInputRef\"\n type=\"text\"\n class=\"timeline-search__input input\"\n placeholder=\"Search by path or operation...\"\n :value=\"timelineStore.filter.searchQuery\"\n @input=\"handleSearchInput\"\n />\n <button\n v-if=\"timelineStore.filter.searchQuery\"\n type=\"button\"\n class=\"timeline-search__clear btn btn--ghost btn--icon\"\n title=\"Clear search\"\n @click=\"clearSearch\"\n >\n <X :size=\"14\" />\n </button>\n </div>\n\n <!-- Filter toggle -->\n <button\n type=\"button\"\n :class=\"[\n 'timeline-filter-toggle btn btn--secondary',\n { 'timeline-filter-toggle--active': hasActiveFilters }\n ]\"\n :aria-expanded=\"showFilters\"\n @click=\"toggleFilters\"\n >\n <Filter :size=\"16\" />\n <span>Filters</span>\n <span v-if=\"filterBadgeCount > 0\" class=\"timeline-filter-toggle__badge\">\n {{ filterBadgeCount }}\n </span>\n <component :is=\"showFilters ? ChevronUp : ChevronDown\" :size=\"14\" />\n </button>\n\n <!-- Stats -->\n <div class=\"timeline-stats\">\n <span class=\"timeline-stats__item\">\n {{ timelineStore.filteredEntries.length }} requests\n </span>\n <span v-if=\"timelineStore.averageDuration > 0\" class=\"timeline-stats__separator\">|</span>\n <span v-if=\"timelineStore.averageDuration > 0\" class=\"timeline-stats__item\">\n avg {{ timelineStore.averageDuration }}ms\n </span>\n </div>\n\n <!-- Clear button -->\n <button\n type=\"button\"\n class=\"btn btn--secondary btn--icon\"\n title=\"Clear timeline\"\n :disabled=\"timelineStore.entries.length === 0\"\n @click=\"clearTimeline\"\n >\n <Trash2 :size=\"16\" />\n </button>\n </div>\n\n <!-- Filter panel -->\n <div v-if=\"showFilters\" class=\"timeline-filters\">\n <!-- Method filters -->\n <div class=\"timeline-filters__section\">\n <h4 class=\"timeline-filters__title\">Methods</h4>\n <div class=\"timeline-filters__methods\">\n <button\n v-for=\"method in httpMethods\"\n :key=\"method\"\n type=\"button\"\n :class=\"[\n 'method-badge',\n `method-badge--${method.toLowerCase()}`,\n { 'method-badge--inactive': !isMethodActive(method) && timelineStore.filter.methods.length > 0 }\n ]\"\n @click=\"toggleMethod(method)\"\n >\n {{ method }}\n </button>\n </div>\n </div>\n\n <!-- Status filters -->\n <div class=\"timeline-filters__section\">\n <h4 class=\"timeline-filters__title\">Status</h4>\n <div class=\"timeline-filters__status\">\n <button\n v-for=\"status in statusCategories\"\n :key=\"status\"\n type=\"button\"\n :class=\"[\n 'timeline-filters__status-btn',\n `timeline-filters__status-btn--${status}`,\n { 'timeline-filters__status-btn--active': isStatusActive(status) }\n ]\"\n @click=\"toggleStatus(status)\"\n >\n {{ status }}\n <span class=\"timeline-filters__status-count\">\n ({{ timelineStore.statusCounts[status] }})\n </span>\n </button>\n </div>\n </div>\n\n <!-- Simulated filter -->\n <div class=\"timeline-filters__section\">\n <h4 class=\"timeline-filters__title\">Type</h4>\n <div class=\"timeline-filters__type\">\n <button\n type=\"button\"\n :class=\"[\n 'timeline-filters__status-btn',\n { 'timeline-filters__status-btn--active': timelineStore.filter.simulatedOnly }\n ]\"\n @click=\"toggleSimulatedFilter\"\n >\n Simulated only\n </button>\n </div>\n </div>\n\n <!-- Clear filters -->\n <div v-if=\"hasActiveFilters\" class=\"timeline-filters__actions\">\n <button\n type=\"button\"\n class=\"btn btn--ghost\"\n @click=\"clearAllFilters\"\n >\n <X :size=\"14\" />\n Clear all filters\n </button>\n </div>\n </div>\n\n <!-- Main content -->\n <div class=\"timeline-content\">\n <!-- Loading state -->\n <div v-if=\"timelineStore.isLoading\" class=\"timeline-loading\">\n <div class=\"timeline-loading__spinner\" />\n <span class=\"text-muted\">Loading timeline...</span>\n </div>\n\n <!-- Error state -->\n <div v-else-if=\"timelineStore.error\" class=\"timeline-error\">\n <p class=\"timeline-error__message\">{{ timelineStore.error }}</p>\n <button type=\"button\" class=\"btn btn--primary\" @click=\"fetchTimeline\">\n Retry\n </button>\n </div>\n\n <!-- Empty state -->\n <div v-else-if=\"timelineStore.entries.length === 0\" class=\"timeline-empty empty-state\">\n <Clock :size=\"48\" class=\"empty-state__icon\" />\n <h3 class=\"empty-state__title\">No requests yet</h3>\n <p class=\"empty-state__description\">\n API requests will appear here in real-time as they are made.\n </p>\n </div>\n\n <!-- No results state -->\n <div v-else-if=\"timelineStore.filteredEntries.length === 0\" class=\"timeline-empty empty-state\">\n <Search :size=\"48\" class=\"empty-state__icon\" />\n <h3 class=\"empty-state__title\">No matching requests</h3>\n <p class=\"empty-state__description\">\n Try adjusting your search or filters.\n </p>\n <button\n v-if=\"hasActiveFilters\"\n type=\"button\"\n class=\"btn btn--secondary\"\n @click=\"clearAllFilters\"\n >\n Clear filters\n </button>\n </div>\n\n <!-- Split panel layout -->\n <template v-else>\n <!-- Timeline list panel -->\n <div class=\"timeline-list-panel\">\n <div class=\"timeline-list\">\n <TimelineEntryComponent\n v-for=\"entry in timelineStore.filteredEntries\"\n :key=\"entry.id\"\n :entry=\"entry\"\n :is-selected=\"timelineStore.selectedEntryId === entry.id\"\n @select=\"handleSelectEntry\"\n />\n </div>\n </div>\n\n <!-- Timeline detail panel -->\n <div class=\"timeline-detail-panel\">\n <TimelineDetail :entry=\"timelineStore.selectedEntry\" />\n </div>\n </template>\n </div>\n </div>\n</template>\n\n<style scoped>\n.timeline-page {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n\n/* Toolbar */\n.timeline-toolbar {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-md);\n background-color: var(--devtools-surface);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-search {\n position: relative;\n flex: 1;\n max-width: 400px;\n}\n\n.timeline-search__icon {\n position: absolute;\n left: var(--devtools-space-sm);\n top: 50%;\n transform: translateY(-50%);\n color: var(--devtools-text-muted);\n pointer-events: none;\n}\n\n.timeline-search__input {\n padding-left: calc(var(--devtools-space-sm) + 24px);\n padding-right: calc(var(--devtools-space-sm) + 24px);\n}\n\n.timeline-search__clear {\n position: absolute;\n right: var(--devtools-space-xs);\n top: 50%;\n transform: translateY(-50%);\n padding: var(--devtools-space-xs);\n}\n\n.timeline-filter-toggle {\n flex-shrink: 0;\n}\n\n.timeline-filter-toggle--active {\n background-color: color-mix(in srgb, var(--devtools-primary) 15%, transparent);\n border-color: var(--devtools-primary);\n color: var(--devtools-primary);\n}\n\n.timeline-filter-toggle__badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 var(--devtools-space-xs);\n background-color: var(--devtools-primary);\n color: var(--devtools-text-inverted);\n border-radius: 9px;\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-6);\n}\n\n.timeline-stats {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n margin-left: auto;\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n}\n\n.timeline-stats__separator {\n opacity: 0.5;\n}\n\n/* Filter panel */\n.timeline-filters {\n display: flex;\n flex-wrap: wrap;\n align-items: flex-start;\n gap: var(--devtools-space-lg);\n padding: var(--devtools-space-md);\n background-color: var(--devtools-surface-elevated);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-filters__section {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-sm);\n}\n\n.timeline-filters__title {\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-6);\n color: var(--devtools-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin: 0;\n}\n\n.timeline-filters__methods {\n display: flex;\n flex-wrap: wrap;\n gap: var(--devtools-space-xs);\n}\n\n.timeline-filters__methods .method-badge {\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.timeline-filters__methods .method-badge--inactive {\n opacity: 0.4;\n}\n\n.timeline-filters__status {\n display: flex;\n gap: var(--devtools-space-sm);\n}\n\n.timeline-filters__type {\n display: flex;\n gap: var(--devtools-space-sm);\n}\n\n.timeline-filters__status-btn {\n display: inline-flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n background-color: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-sm);\n font-family: var(--devtools-font-sans);\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.timeline-filters__status-btn:hover {\n background-color: var(--devtools-surface-elevated);\n color: var(--devtools-text);\n}\n\n.timeline-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-primary) 15%, transparent);\n border-color: var(--devtools-primary);\n color: var(--devtools-primary);\n}\n\n.timeline-filters__status-btn--2xx.timeline-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-success) 15%, transparent);\n border-color: var(--devtools-success);\n color: var(--devtools-success);\n}\n\n.timeline-filters__status-btn--3xx.timeline-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n border-color: var(--devtools-info);\n color: var(--devtools-info);\n}\n\n.timeline-filters__status-btn--4xx.timeline-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-warning) 15%, transparent);\n border-color: var(--devtools-warning);\n color: var(--devtools-warning);\n}\n\n.timeline-filters__status-btn--5xx.timeline-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-error) 15%, transparent);\n border-color: var(--devtools-error);\n color: var(--devtools-error);\n}\n\n.timeline-filters__status-count {\n font-size: var(--font-size-00);\n opacity: 0.7;\n}\n\n.timeline-filters__actions {\n display: flex;\n align-items: flex-end;\n margin-left: auto;\n}\n\n/* Main content */\n.timeline-content {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n/* Loading state */\n.timeline-loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 100%;\n gap: var(--devtools-space-md);\n}\n\n.timeline-loading__spinner {\n width: 32px;\n height: 32px;\n border: 3px solid var(--devtools-border);\n border-top-color: var(--devtools-primary);\n border-radius: 50%;\n animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n/* Error state */\n.timeline-error {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 100%;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-xl);\n}\n\n.timeline-error__message {\n color: var(--devtools-error);\n margin: 0;\n}\n\n/* Empty state */\n.timeline-empty {\n width: 100%;\n}\n\n/* Split panels */\n.timeline-list-panel {\n width: 50%;\n min-width: 300px;\n max-width: 600px;\n border-right: 1px solid var(--devtools-border);\n background-color: var(--devtools-bg);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.timeline-list {\n flex: 1;\n overflow-y: auto;\n padding: var(--devtools-space-sm);\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-xs);\n}\n\n.timeline-detail-panel {\n flex: 1;\n overflow: hidden;\n background-color: var(--devtools-bg);\n}\n</style>\n","<!--\n JsonEditor.vue - JSON Editor Component\n\n What: Editable JSON textarea with syntax highlighting and validation\n How: Uses a textarea with syntax validation and formatting utilities\n Why: Allows developers to edit mock data in a user-friendly interface\n\n Features:\n - Real-time JSON validation\n - Syntax error display\n - Format/prettify button\n - Line numbers\n - Monospace font\n-->\n\n<script setup lang=\"ts\">\nimport { AlertCircle, Check } from 'lucide-vue-next';\nimport { computed, ref, watch } from 'vue';\n\n/**\n * Component props\n */\ninterface Props {\n /** JSON data to edit (will be stringified) */\n modelValue: unknown;\n /** Whether the editor is read-only */\n readonly?: boolean;\n /** Placeholder text when empty */\n placeholder?: string;\n /** Minimum height in pixels */\n minHeight?: number;\n}\n\n/**\n * Component emits\n */\ninterface Emits {\n (e: 'update:modelValue', value: unknown): void;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n readonly: false,\n placeholder: 'Enter JSON data...',\n minHeight: 200,\n});\n\nconst emit = defineEmits<Emits>();\n\n// ==========================================================================\n// State\n// ==========================================================================\n\n/** Current text content */\nconst text = ref<string>('');\n\n/** JSON validation error */\nconst validationError = ref<string | null>(null);\n\n/** Whether JSON is valid */\nconst isValid = computed(() => validationError.value === null);\n\n/** Line count for line numbers */\nconst lineCount = computed(() => {\n return text.value.split('\\n').length;\n});\n\n/** Line numbers array */\nconst lineNumbers = computed(() => {\n return Array.from({ length: lineCount.value }, (_, i) => i + 1);\n});\n\n// ==========================================================================\n// Initialization\n// ==========================================================================\n\n/**\n * Initialize text from modelValue\n */\nfunction initializeText(): void {\n try {\n text.value = JSON.stringify(props.modelValue, null, 2);\n validationError.value = null;\n } catch (err) {\n text.value = '';\n validationError.value = 'Invalid initial value';\n }\n}\n\n// Initialize on mount\ninitializeText();\n\n// Watch for external changes to modelValue\nwatch(\n () => props.modelValue,\n () => {\n // Only update if the parsed value differs (avoid cursor jumps during typing)\n try {\n const currentParsed = JSON.parse(text.value);\n if (JSON.stringify(currentParsed) !== JSON.stringify(props.modelValue)) {\n initializeText();\n }\n } catch {\n // If current text is invalid, always update\n initializeText();\n }\n },\n);\n\n// ==========================================================================\n// Actions\n// ==========================================================================\n\n/**\n * Handle text input\n */\nfunction handleInput(event: Event): void {\n const target = event.target as HTMLTextAreaElement;\n text.value = target.value;\n validateAndEmit();\n}\n\n/**\n * Validate JSON and emit update\n */\nfunction validateAndEmit(): void {\n if (text.value.trim() === '') {\n validationError.value = null;\n emit('update:modelValue', []);\n return;\n }\n\n try {\n const parsed = JSON.parse(text.value);\n validationError.value = null;\n emit('update:modelValue', parsed);\n } catch (err) {\n if (err instanceof Error) {\n // Extract line/column info from error message\n const match = err.message.match(/position (\\d+)/);\n if (match) {\n const position = Number.parseInt(match[1], 10);\n const lines = text.value.substring(0, position).split('\\n');\n const line = lines.length;\n const column = lines[lines.length - 1].length + 1;\n validationError.value = `Line ${line}, Column ${column}: ${err.message}`;\n } else {\n validationError.value = err.message;\n }\n } else {\n validationError.value = 'Invalid JSON';\n }\n }\n}\n\n/**\n * Format/prettify the JSON\n */\nfunction formatJson(): void {\n try {\n const parsed = JSON.parse(text.value);\n text.value = JSON.stringify(parsed, null, 2);\n validationError.value = null;\n emit('update:modelValue', parsed);\n } catch {\n // If invalid, do nothing\n }\n}\n\n/**\n * Handle Tab key for indentation\n */\nfunction handleKeyDown(event: KeyboardEvent): void {\n if (event.key === 'Tab') {\n event.preventDefault();\n const target = event.target as HTMLTextAreaElement;\n const start = target.selectionStart;\n const end = target.selectionEnd;\n\n // Insert 2 spaces\n const newText = `${text.value.substring(0, start)} ${text.value.substring(end)}`;\n text.value = newText;\n\n // Move cursor\n setTimeout(() => {\n target.selectionStart = target.selectionEnd = start + 2;\n }, 0);\n\n validateAndEmit();\n }\n}\n\n// ==========================================================================\n// Expose methods\n// ==========================================================================\n\ndefineExpose({\n formatJson,\n isValid,\n});\n</script>\n\n<template>\n <div class=\"json-editor\">\n <!-- Editor Container -->\n <div class=\"json-editor__container\">\n <!-- Line Numbers -->\n <div class=\"json-editor__lines\" aria-hidden=\"true\">\n <div\n v-for=\"lineNum in lineNumbers\"\n :key=\"lineNum\"\n class=\"json-editor__line-number\"\n >\n {{ lineNum }}\n </div>\n </div>\n\n <!-- Textarea -->\n <textarea\n :value=\"text\"\n :readonly=\"readonly\"\n :placeholder=\"placeholder\"\n :style=\"{ minHeight: `${minHeight}px` }\"\n class=\"json-editor__textarea\"\n spellcheck=\"false\"\n @input=\"handleInput\"\n @keydown=\"handleKeyDown\"\n />\n </div>\n\n <!-- Status Bar -->\n <div class=\"json-editor__status\">\n <div class=\"json-editor__status-left\">\n <!-- Validation Status -->\n <div v-if=\"isValid\" class=\"json-editor__valid\">\n <Check :size=\"14\" />\n <span>Valid JSON</span>\n </div>\n <div v-else-if=\"validationError\" class=\"json-editor__error\">\n <AlertCircle :size=\"14\" />\n <span>{{ validationError }}</span>\n </div>\n </div>\n\n <div class=\"json-editor__status-right\">\n <!-- Line Count -->\n <span class=\"json-editor__info\">{{ lineCount }} lines</span>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.json-editor {\n display: flex;\n flex-direction: column;\n background-color: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-md);\n overflow: hidden;\n}\n\n/* Editor Container */\n.json-editor__container {\n display: flex;\n overflow: auto;\n flex: 1;\n}\n\n/* Line Numbers */\n.json-editor__lines {\n display: flex;\n flex-direction: column;\n padding: var(--devtools-space-sm) var(--devtools-space-xs);\n background-color: var(--devtools-surface-elevated);\n border-right: 1px solid var(--devtools-border);\n user-select: none;\n flex-shrink: 0;\n}\n\n.json-editor__line-number {\n height: 1.5em;\n line-height: 1.5;\n text-align: right;\n font-family: var(--devtools-font-mono);\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n min-width: 2ch;\n padding-right: var(--devtools-space-xs);\n}\n\n/* Textarea */\n.json-editor__textarea {\n flex: 1;\n padding: var(--devtools-space-sm);\n background-color: var(--devtools-surface);\n color: var(--devtools-text);\n border: none;\n outline: none;\n resize: vertical;\n font-family: var(--devtools-font-mono);\n font-size: var(--font-size-0);\n line-height: 1.5;\n tab-size: 2;\n white-space: pre;\n overflow-wrap: normal;\n overflow-x: auto;\n}\n\n.json-editor__textarea::placeholder {\n color: var(--devtools-text-muted);\n opacity: 0.6;\n}\n\n.json-editor__textarea:focus {\n outline: 2px solid var(--devtools-primary);\n outline-offset: -2px;\n}\n\n.json-editor__textarea[readonly] {\n background-color: var(--devtools-surface-elevated);\n cursor: not-allowed;\n opacity: 0.7;\n}\n\n/* Status Bar */\n.json-editor__status {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n background-color: var(--devtools-surface-elevated);\n border-top: 1px solid var(--devtools-border);\n font-size: var(--font-size-0);\n}\n\n.json-editor__status-left,\n.json-editor__status-right {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n}\n\n/* Validation Indicators */\n.json-editor__valid {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n color: var(--devtools-success);\n}\n\n.json-editor__error {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n color: var(--devtools-error);\n}\n\n.json-editor__info {\n color: var(--devtools-text-muted);\n}\n\n/* Dark mode adjustments */\n@media (prefers-color-scheme: dark) {\n .json-editor__textarea {\n color: #e2e8f0;\n }\n\n .json-editor__textarea::placeholder {\n color: #64748b;\n }\n}\n</style>\n","/**\n * Notifications Composable\n *\n * What: Provides consistent user feedback mechanism for the DevTools\n * How: Manages toast notifications and confirmation modals\n * Why: Replaces inconsistent alert()/confirm()/console.log() usage\n *\n * Features:\n * - Toast notifications for success/error/info messages\n * - Confirmation modals with custom messages\n * - Auto-dismiss for toast notifications\n * - Centralized state management\n */\n\nimport { reactive, ref } from 'vue';\n\n/**\n * Toast notification types\n */\nexport type ToastType = 'success' | 'error' | 'info' | 'warning';\n\n/**\n * Toast notification\n */\nexport interface Toast {\n id: string;\n type: ToastType;\n message: string;\n duration: number;\n timestamp: number;\n}\n\n/**\n * Confirmation dialog state\n */\nexport interface ConfirmDialog {\n visible: boolean;\n title: string;\n message: string;\n confirmText: string;\n cancelText: string;\n onConfirm: (() => void) | null;\n onCancel: (() => void) | null;\n}\n\n// ==========================================================================\n// Global State\n// ==========================================================================\n\nconst toasts = ref<Toast[]>([]);\nconst confirmDialog = reactive<ConfirmDialog>({\n visible: false,\n title: '',\n message: '',\n confirmText: 'Confirm',\n cancelText: 'Cancel',\n onConfirm: null,\n onCancel: null,\n});\n\n// Track active timeout IDs to prevent orphaned timers\nconst timeouts = new Map<string, ReturnType<typeof setTimeout>>();\n\n// Track pending confirm dialog promise resolver\nlet pendingResolve: ((value: boolean) => void) | null = null;\n\n// ==========================================================================\n// Helper Functions\n// ==========================================================================\n\nlet toastIdCounter = 0;\n\nfunction generateToastId(): string {\n return `toast-${Date.now()}-${toastIdCounter++}`;\n}\n\nfunction addToast(type: ToastType, message: string, duration = 3000): string {\n const id = generateToastId();\n const toast: Toast = {\n id,\n type,\n message,\n duration,\n timestamp: Date.now(),\n };\n\n toasts.value.push(toast);\n\n // Auto-dismiss\n if (duration > 0) {\n const timeoutId = setTimeout(() => {\n removeToast(id);\n timeouts.delete(id);\n }, duration);\n timeouts.set(id, timeoutId);\n }\n\n return id;\n}\n\nfunction removeToast(id: string): void {\n // Clear the timeout if it exists\n const timeoutId = timeouts.get(id);\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId);\n timeouts.delete(id);\n }\n\n // Remove the toast from the array\n const index = toasts.value.findIndex((t) => t.id === id);\n if (index !== -1) {\n toasts.value.splice(index, 1);\n }\n}\n\n// ==========================================================================\n// Composable\n// ==========================================================================\n\n/**\n * Notifications composable\n *\n * Provides methods for showing toast notifications and confirmation dialogs\n */\nexport function useNotifications() {\n /**\n * Show a success toast notification\n */\n function success(message: string, duration?: number): string {\n return addToast('success', message, duration);\n }\n\n /**\n * Show an error toast notification\n */\n function error(message: string, duration?: number): string {\n return addToast('error', message, duration);\n }\n\n /**\n * Show an info toast notification\n */\n function info(message: string, duration?: number): string {\n return addToast('info', message, duration);\n }\n\n /**\n * Show a warning toast notification\n */\n function warning(message: string, duration?: number): string {\n return addToast('warning', message, duration);\n }\n\n /**\n * Show a confirmation dialog\n *\n * @returns Promise that resolves to true if confirmed, false if cancelled\n */\n function confirm(\n message: string,\n options?: {\n title?: string;\n confirmText?: string;\n cancelText?: string;\n },\n ): Promise<boolean> {\n return new Promise((resolve) => {\n // Resolve any pending dialog with false (cancelled) before opening new one\n if (pendingResolve) {\n pendingResolve(false);\n pendingResolve = null;\n }\n\n // Store the new resolve reference\n pendingResolve = resolve;\n\n confirmDialog.visible = true;\n confirmDialog.title = options?.title || 'Confirm';\n confirmDialog.message = message;\n confirmDialog.confirmText = options?.confirmText || 'Confirm';\n confirmDialog.cancelText = options?.cancelText || 'Cancel';\n\n confirmDialog.onConfirm = () => {\n confirmDialog.visible = false;\n if (pendingResolve) {\n pendingResolve(true);\n pendingResolve = null;\n }\n };\n\n confirmDialog.onCancel = () => {\n confirmDialog.visible = false;\n if (pendingResolve) {\n pendingResolve(false);\n pendingResolve = null;\n }\n };\n });\n }\n\n /**\n * Close the confirmation dialog\n */\n function closeConfirm(): void {\n confirmDialog.visible = false;\n if (pendingResolve) {\n pendingResolve(false);\n pendingResolve = null;\n }\n }\n\n /**\n * Manually dismiss a toast by ID\n */\n function dismiss(id: string): void {\n removeToast(id);\n }\n\n /**\n * Clear all toasts\n */\n function clearAll(): void {\n // Clear all active timeouts\n for (const timeoutId of timeouts.values()) {\n clearTimeout(timeoutId);\n }\n timeouts.clear();\n toasts.value = [];\n }\n\n return {\n // State\n toasts,\n confirmDialog,\n\n // Toast methods\n success,\n error,\n info,\n warning,\n dismiss,\n clearAll,\n\n // Confirm methods\n confirm,\n closeConfirm,\n };\n}\n","<!--\n ModelsPage.vue - Store Data Editor Page\n\n What: Displays and allows editing of in-memory store data organized by schema\n How: Fetches store data from models store and displays in an editable JSON view\n Why: Allows developers to inspect and modify mock data during development\n\n Features:\n - Schema listing sidebar with item counts\n - JSON editor with syntax validation\n - Save, discard, clear, and reseed actions\n - Real-time updates via WebSocket\n - Dirty state tracking\n-->\n<script setup lang=\"ts\">\nimport { Database, RefreshCw, Save, Trash2, X } from 'lucide-vue-next';\nimport { nextTick, onMounted, ref, watch } from 'vue';\n// biome-ignore lint/style/useImportType: Component needs to be available at runtime\nimport JsonEditor from '@/components/JsonEditor.vue';\nimport { useNotifications } from '@/composables/useNotifications';\nimport { useWebSocket } from '@/composables/useWebSocket';\nimport { useModelsStore } from '@/stores';\n\n// ==========================================================================\n// Store & Composables\n// ==========================================================================\n\nconst modelsStore = useModelsStore();\nconst { send, on, connected } = useWebSocket();\nconst { success, error: notifyError, confirm } = useNotifications();\n\n// ==========================================================================\n// State\n// ==========================================================================\n\n/** Reference to the JSON editor component */\nconst jsonEditorRef = ref<InstanceType<typeof JsonEditor> | null>(null);\n\n/** Confirmation dialog state */\nconst showClearConfirm = ref(false);\n\n// ==========================================================================\n// Lifecycle\n// ==========================================================================\n\nonMounted(async () => {\n // Load schemas on mount\n try {\n await modelsStore.fetchSchemas();\n\n // Select first schema if available\n if (modelsStore.schemas.length > 0 && !modelsStore.selectedSchema) {\n await modelsStore.selectSchemaByName(modelsStore.schemas[0].name);\n }\n } catch (err) {\n // Error is already set in the store, but ensure it's visible\n if (!modelsStore.error) {\n modelsStore.error = err instanceof Error ? err.message : 'Failed to load schemas';\n }\n }\n});\n\n// ==========================================================================\n// WebSocket Event Handlers\n// ==========================================================================\n\n// Handle store updates from WebSocket\non('store:updated', (data) => {\n // Validate payload structure\n const payload = data as any;\n if (\n typeof data !== 'object' ||\n data === null ||\n typeof payload.schema !== 'string' ||\n typeof payload.action !== 'string' ||\n typeof payload.count !== 'number'\n ) {\n console.warn('[ModelsPage] Invalid store:updated payload:', data);\n return;\n }\n\n modelsStore.handleStoreUpdate(data as { schema: string; action: string; count: number });\n});\n\n// Handle reseed completion\non('reseeded', (data) => {\n // Validate payload structure\n const payload = data as any;\n if (\n typeof data !== 'object' ||\n data === null ||\n typeof payload.success !== 'boolean' ||\n !Array.isArray(payload.schemas)\n ) {\n console.warn('[ModelsPage] Invalid reseeded payload:', data);\n return;\n }\n\n modelsStore.handleReseedComplete(data as { success: boolean; schemas: string[] });\n});\n\n// ==========================================================================\n// Watchers\n// ==========================================================================\n\n// Format JSON when schema changes\nwatch(\n () => modelsStore.selectedSchema,\n async () => {\n if (jsonEditorRef.value && modelsStore.currentItems.length > 0) {\n // Wait for next tick to ensure editor is updated\n await nextTick();\n jsonEditorRef.value?.formatJson();\n }\n },\n);\n\n// ==========================================================================\n// Actions\n// ==========================================================================\n\n/**\n * Select a schema and fetch its data\n */\nasync function selectSchema(schemaName: string): Promise<void> {\n if (modelsStore.isDirty) {\n const confirmed = await confirm(\n 'You have unsaved changes. Are you sure you want to switch schemas?',\n {\n title: 'Unsaved Changes',\n confirmText: 'Switch Schema',\n cancelText: 'Cancel',\n },\n );\n if (!confirmed) return;\n }\n\n await modelsStore.selectSchemaByName(schemaName);\n}\n\n/**\n * Save the current items to the server\n */\nasync function saveItems(): Promise<void> {\n if (!jsonEditorRef.value?.isValid) {\n notifyError('Cannot save invalid JSON. Please fix the errors first.');\n return;\n }\n\n const saved = await modelsStore.saveItems();\n if (saved) {\n success('Items saved successfully');\n } else {\n // Show error to user if save failed\n const errorMessage = modelsStore.error || 'Failed to save items';\n notifyError(errorMessage);\n }\n}\n\n/**\n * Discard changes and revert to original\n */\nasync function discardChanges(): Promise<void> {\n if (!modelsStore.isDirty) return;\n\n const confirmed = await confirm('Discard all changes and revert to saved data?', {\n title: 'Discard Changes',\n confirmText: 'Discard',\n cancelText: 'Cancel',\n });\n if (confirmed) {\n modelsStore.discardChanges();\n success('Changes discarded');\n }\n}\n\n/**\n * Clear all items for the current schema\n */\nasync function clearSchema(): Promise<void> {\n showClearConfirm.value = false;\n\n try {\n const cleared = await modelsStore.clearSchema();\n if (cleared) {\n success('Schema cleared successfully');\n } else {\n // Show error to user if clear failed\n const errorMessage = modelsStore.error || 'Failed to clear schema';\n notifyError(errorMessage);\n }\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to clear schema';\n notifyError(errorMessage);\n }\n}\n\n/**\n * Trigger reseed via WebSocket\n */\nasync function reseedAll(): Promise<void> {\n if (!connected.value) {\n notifyError('WebSocket not connected. Cannot trigger reseed.');\n return;\n }\n\n const confirmed = await confirm(\n 'This will regenerate all seed data and replace existing items. Continue?',\n {\n title: 'Reseed All Schemas',\n confirmText: 'Reseed',\n cancelText: 'Cancel',\n },\n );\n if (!confirmed) return;\n\n send({ type: 'reseed' });\n success('Reseed command sent');\n}\n\n/**\n * Handle JSON editor value updates\n */\nfunction onJsonEditorUpdate(value: unknown): void {\n modelsStore.updateItems(value);\n}\n</script>\n\n<template>\n <div class=\"models-page\">\n <!-- Schema Sidebar -->\n <aside class=\"models-sidebar\">\n <div class=\"models-sidebar__header\">\n <Database :size=\"18\" />\n <span>Schemas</span>\n <span class=\"models-sidebar__badge\">{{ modelsStore.schemaCount }}</span>\n </div>\n\n <!-- Loading State -->\n <div v-if=\"modelsStore.loading && modelsStore.schemas.length === 0\" class=\"models-sidebar__loading\">\n <div class=\"spinner\" />\n <span>Loading...</span>\n </div>\n\n <!-- Schema List -->\n <div v-else class=\"models-sidebar__list\">\n <button\n v-for=\"schema in modelsStore.schemas\"\n :key=\"schema.name\"\n :class=\"[\n 'models-sidebar__item',\n { 'models-sidebar__item--active': modelsStore.selectedSchema === schema.name },\n ]\"\n @click=\"selectSchema(schema.name)\"\n >\n <span class=\"models-sidebar__name\">{{ schema.name }}</span>\n <span class=\"models-sidebar__count\">{{ schema.count }}</span>\n </button>\n </div>\n\n <!-- Footer Stats -->\n <div class=\"models-sidebar__footer\">\n <div class=\"models-sidebar__stat\">\n <span class=\"text-muted\">Total Items:</span>\n <span class=\"font-mono\">{{ modelsStore.totalItems }}</span>\n </div>\n </div>\n </aside>\n\n <!-- Data Panel -->\n <main class=\"models-content\">\n <template v-if=\"modelsStore.selectedSchema\">\n <!-- Toolbar -->\n <div class=\"models-toolbar\">\n <div class=\"models-toolbar__title\">\n <span class=\"font-mono\">{{ modelsStore.selectedSchema }}</span>\n <span class=\"text-muted\">({{ modelsStore.currentItems.length }} items)</span>\n <span\n v-if=\"modelsStore.isDirty\"\n class=\"models-toolbar__badge models-toolbar__badge--warning\"\n >\n Unsaved\n </span>\n </div>\n\n <div class=\"models-toolbar__actions\">\n <!-- Discard Button -->\n <button\n v-if=\"modelsStore.isDirty\"\n class=\"btn btn--ghost\"\n title=\"Discard changes\"\n @click=\"discardChanges\"\n >\n <X :size=\"16\" />\n <span>Discard</span>\n </button>\n\n <!-- Save Button -->\n <button\n :disabled=\"!modelsStore.isDirty || modelsStore.loading\"\n class=\"btn btn--primary\"\n title=\"Save changes\"\n @click=\"saveItems\"\n >\n <Save :size=\"16\" />\n <span>Save</span>\n </button>\n\n <!-- Clear Button -->\n <button\n class=\"btn btn--danger\"\n title=\"Clear all items\"\n @click=\"showClearConfirm = true\"\n >\n <Trash2 :size=\"16\" />\n <span>Clear</span>\n </button>\n\n <!-- Reseed Button -->\n <button\n :disabled=\"!connected\"\n class=\"btn btn--secondary\"\n title=\"Reseed all schemas with generated data\"\n @click=\"reseedAll\"\n >\n <RefreshCw :size=\"16\" />\n <span>Reseed All</span>\n </button>\n </div>\n </div>\n\n <!-- Error Display -->\n <div v-if=\"modelsStore.error\" class=\"models-error\">\n <span>⚠️ {{ modelsStore.error }}</span>\n </div>\n\n <!-- JSON Editor -->\n <div class=\"models-editor\">\n <JsonEditor\n ref=\"jsonEditorRef\"\n :model-value=\"modelsStore.currentItems\"\n :readonly=\"modelsStore.loading\"\n :min-height=\"400\"\n @update:model-value=\"onJsonEditorUpdate\"\n />\n </div>\n\n <!-- Loading Overlay -->\n <div v-if=\"modelsStore.loading\" class=\"models-loading-overlay\">\n <div class=\"spinner\" />\n <span>Loading...</span>\n </div>\n </template>\n\n <!-- Empty State or Error -->\n <div v-else class=\"empty-state\">\n <!-- Show error if present and no schema selected -->\n <div v-if=\"modelsStore.error\" class=\"models-error\">\n <span>⚠️ {{ modelsStore.error }}</span>\n </div>\n <template v-else>\n <Database :size=\"48\" class=\"empty-state__icon\" />\n <h3 class=\"empty-state__title\">Select a schema</h3>\n <p class=\"empty-state__description\">\n Choose a schema from the sidebar to view and edit its data.\n </p>\n </template>\n </div>\n </main>\n\n <!-- Clear Confirmation Modal -->\n <Teleport to=\"body\">\n <div v-if=\"showClearConfirm\" class=\"modal-overlay\" @click=\"showClearConfirm = false\">\n <div class=\"modal\" @click.stop>\n <div class=\"modal__header\">\n <h3>Clear Schema Data</h3>\n </div>\n <div class=\"modal__body\">\n <p>\n Are you sure you want to clear all items for\n <strong>{{ modelsStore.selectedSchema }}</strong>?\n </p>\n <p class=\"text-muted\">This action cannot be undone.</p>\n </div>\n <div class=\"modal__footer\">\n <button class=\"btn btn--ghost\" @click=\"showClearConfirm = false\">\n Cancel\n </button>\n <button class=\"btn btn--danger\" @click=\"clearSchema\">\n Clear Schema\n </button>\n </div>\n </div>\n </div>\n </Teleport>\n </div>\n</template>\n\n<style scoped>\n.models-page {\n display: grid;\n grid-template-columns: 240px 1fr;\n height: 100%;\n overflow: hidden;\n}\n\n/* Sidebar */\n.models-sidebar {\n display: flex;\n flex-direction: column;\n background-color: var(--devtools-surface);\n border-right: 1px solid var(--devtools-border);\n overflow: hidden;\n}\n\n.models-sidebar__header {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n padding: var(--devtools-space-md);\n font-weight: var(--font-weight-6);\n font-size: var(--font-size-1);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.models-sidebar__badge {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 20px;\n height: 20px;\n padding: 0 var(--devtools-space-xs);\n background-color: var(--devtools-primary);\n color: white;\n border-radius: var(--devtools-radius-sm);\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-6);\n}\n\n.models-sidebar__loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-xl);\n color: var(--devtools-text-muted);\n}\n\n.models-sidebar__list {\n flex: 1;\n overflow-y: auto;\n padding: var(--devtools-space-xs);\n}\n\n.models-sidebar__item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n padding: var(--devtools-space-sm) var(--devtools-space-md);\n background: none;\n border: none;\n border-radius: var(--devtools-radius-sm);\n color: var(--devtools-text);\n font-family: var(--devtools-font-sans);\n font-size: var(--font-size-1);\n cursor: pointer;\n transition: background-color var(--devtools-transition-fast);\n}\n\n.models-sidebar__item:hover {\n background-color: var(--devtools-surface-elevated);\n}\n\n.models-sidebar__item--active {\n background-color: color-mix(in srgb, var(--devtools-primary) 15%, transparent);\n color: var(--devtools-primary);\n}\n\n.models-sidebar__name {\n font-family: var(--devtools-font-mono);\n}\n\n.models-sidebar__count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 24px;\n height: 20px;\n padding: 0 var(--devtools-space-xs);\n background-color: var(--devtools-surface-elevated);\n border-radius: var(--devtools-radius-sm);\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n}\n\n.models-sidebar__footer {\n padding: var(--devtools-space-md);\n border-top: 1px solid var(--devtools-border);\n}\n\n.models-sidebar__stat {\n display: flex;\n justify-content: space-between;\n font-size: var(--font-size-0);\n}\n\n/* Content Area */\n.models-content {\n position: relative;\n display: flex;\n flex-direction: column;\n padding: var(--devtools-space-md);\n overflow: hidden;\n}\n\n/* Toolbar */\n.models-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--devtools-space-md);\n margin-bottom: var(--devtools-space-md);\n}\n\n.models-toolbar__title {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n font-size: var(--font-size-2);\n font-weight: var(--font-weight-6);\n}\n\n.models-toolbar__badge {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n border-radius: var(--devtools-radius-sm);\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n}\n\n.models-toolbar__badge--warning {\n background-color: color-mix(in srgb, #f59e0b 20%, transparent);\n color: #f59e0b;\n}\n\n.models-toolbar__actions {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n}\n\n/* Error Display */\n.models-error {\n padding: var(--devtools-space-sm) var(--devtools-space-md);\n margin-bottom: var(--devtools-space-md);\n background-color: color-mix(in srgb, var(--devtools-error) 10%, transparent);\n border: 1px solid var(--devtools-error);\n border-radius: var(--devtools-radius-sm);\n color: var(--devtools-error);\n font-size: var(--font-size-0);\n}\n\n/* Editor */\n.models-editor {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n/* Loading Overlay */\n.models-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--devtools-space-md);\n background-color: color-mix(in srgb, var(--devtools-bg) 80%, transparent);\n backdrop-filter: blur(2px);\n z-index: 10;\n}\n\n/* Modal */\n.modal-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: rgba(0, 0, 0, 0.5);\n z-index: 1000;\n}\n\n.modal {\n min-width: 400px;\n background-color: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-md);\n box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);\n}\n\n.modal__header {\n padding: var(--devtools-space-md);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.modal__header h3 {\n margin: 0;\n font-size: var(--font-size-2);\n font-weight: var(--font-weight-6);\n}\n\n.modal__body {\n padding: var(--devtools-space-md);\n}\n\n.modal__body p {\n margin: 0 0 var(--devtools-space-sm) 0;\n}\n\n.modal__body p:last-child {\n margin-bottom: 0;\n}\n\n.modal__footer {\n display: flex;\n justify-content: flex-end;\n gap: var(--devtools-space-sm);\n padding: var(--devtools-space-md);\n border-top: 1px solid var(--devtools-border);\n}\n\n/* Spinner */\n.spinner {\n width: 24px;\n height: 24px;\n border: 3px solid var(--devtools-border);\n border-top-color: var(--devtools-primary);\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n</style>\n","<!--\n SimulatorPage.vue - Error Simulation Controls Page\n\n What: Provides controls for simulating various API error conditions\n How: Manages simulation state via simulation store and WebSocket commands\n Why: Allows developers to test error handling without modifying backend code\n-->\n\n<script setup lang=\"ts\">\nimport { AlertTriangle, Clock, Plus, Trash2, Zap } from 'lucide-vue-next';\nimport { computed, onMounted, onUnmounted, ref } from 'vue';\nimport { useWebSocket } from '../composables/useWebSocket';\nimport { useRegistryStore } from '../stores/registry';\nimport type { ActiveSimulation } from '../stores/simulation';\nimport { useSimulationStore } from '../stores/simulation';\n\n// ==========================================================================\n// Types\n// ==========================================================================\n\ninterface SimulationActiveEvent {\n simulations: ActiveSimulation[];\n}\n\ninterface SimulationPathEvent {\n path: string;\n}\n\ninterface SimulationsClearedEvent {\n count: number;\n}\n\ninterface SimulationSetEvent {\n path: string;\n success: boolean;\n}\n\ninterface SimulationClearedEvent {\n path: string;\n success: boolean;\n}\n\n// ==========================================================================\n// Composables\n// ==========================================================================\n\nconst simulationStore = useSimulationStore();\nconst registryStore = useRegistryStore();\nconst { send, on } = useWebSocket();\n\n// ==========================================================================\n// State\n// ==========================================================================\n\n/** Path input for new simulation */\nconst newSimulationPath = ref('');\n\n/** Method input for new simulation */\nconst newSimulationMethod = ref('GET');\n\n/** Selected preset ID */\nconst selectedPresetId = ref<string | null>(null);\n\n/** Selected endpoint key (for dropdown selection) */\nconst selectedEndpointKey = ref<string | null>(null);\n\n/** Available HTTP methods */\nconst httpMethods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'];\n\n/** WebSocket event unsubscribe functions (populated in onMounted) */\nlet unsubscribers: Array<() => void> = [];\n\n/** Simulations pending clear (for rollback on partial failures) */\nconst pendingClears = ref<Set<string>>(new Set());\n\n// ==========================================================================\n// Computed\n// ==========================================================================\n\n/**\n * Available endpoints for selection\n */\nconst availableEndpoints = computed(() => {\n return registryStore.endpoints.map((e) => ({\n key: e.key,\n label: `${e.method.toUpperCase()} ${e.path}`,\n method: e.method.toUpperCase(),\n path: e.path,\n operationId: e.operationId,\n }));\n});\n\n/**\n * Check if we can add a new simulation\n */\nconst canAddSimulation = computed(() => {\n const hasPath = newSimulationPath.value.trim() !== '';\n const hasPreset = selectedPresetId.value !== null;\n return hasPath && hasPreset;\n});\n\n/**\n * Active simulations for display\n */\nconst activeSimulations = computed(() => {\n return simulationStore.activeSimulations.map((sim) => {\n const preset = sim.presetId ? simulationStore.getPreset(sim.presetId) : null;\n return {\n ...sim,\n preset,\n };\n });\n});\n\n/**\n * Simulation count\n */\nconst simulationCount = computed(() => simulationStore.count);\n\n// ==========================================================================\n// Methods\n// ==========================================================================\n\n/**\n * Add a new simulation\n */\nfunction addSimulation(): void {\n if (!canAddSimulation.value || !selectedPresetId.value) return;\n\n const preset = simulationStore.getPreset(selectedPresetId.value);\n if (!preset) return;\n\n // Validate path input\n const trimmedPath = newSimulationPath.value.trim();\n\n // Path must start with /\n if (!trimmedPath.startsWith('/')) {\n simulationStore.setError('Path must start with /');\n return;\n }\n\n // Path must not be too long (reasonable limit)\n if (trimmedPath.length > 500) {\n simulationStore.setError('Path is too long (max 500 characters)');\n return;\n }\n\n // Path should only contain valid URL path characters\n if (!/^\\/[\\w\\-/{}:.]*$/.test(trimmedPath)) {\n simulationStore.setError('Path contains invalid characters');\n return;\n }\n\n // Combine method and path to create endpoint key (e.g., \"get:/pets\")\n const pathWithMethod = `${newSimulationMethod.value.toLowerCase()}:${trimmedPath}`;\n const simulation = simulationStore.createSimulationFromPreset(\n pathWithMethod,\n selectedPresetId.value,\n undefined,\n );\n\n if (!simulation) return;\n\n // Optimistically add to local state (store previous state for rollback)\n simulationStore.addSimulationLocal(simulation, true);\n simulationStore.setLoading(true);\n\n // Send command to server\n send({\n type: 'set:simulation',\n data: {\n path: simulation.path,\n status: simulation.status,\n delay: simulation.delay,\n body: simulation.body,\n },\n });\n\n // Reset form\n newSimulationPath.value = '';\n selectedPresetId.value = null;\n selectedEndpointKey.value = null;\n}\n\n/**\n * Remove an active simulation\n */\nfunction removeSimulation(path: string): void {\n // Optimistically remove from local state (store previous state for rollback)\n simulationStore.removeSimulationLocal(path, true);\n simulationStore.setLoading(true);\n\n // Send command to server\n send({\n type: 'clear:simulation',\n data: { path },\n });\n}\n\n/**\n * Clear all simulations\n */\nfunction clearAllSimulations(): void {\n if (simulationCount.value === 0) return;\n\n // Mark each simulation as pending clear and store for rollback\n for (const simulation of simulationStore.activeSimulations) {\n pendingClears.value.add(simulation.path);\n\n // Store previous state for rollback\n simulationStore.removeSimulationLocal(simulation.path, true);\n\n // Send clear command to server\n send({\n type: 'clear:simulation',\n data: { path: simulation.path },\n });\n }\n\n simulationStore.setLoading(true);\n\n // Note: Individual simulations will be removed from local state\n // only when we receive the corresponding \"simulation:cleared\" event\n // with success: true. Failed clears will be rolled back automatically.\n}\n\n/**\n * Handle endpoint selection from dropdown\n */\nfunction handleEndpointSelect(): void {\n if (!selectedEndpointKey.value) return;\n\n const endpoint = registryStore.endpoints.find((e) => e.key === selectedEndpointKey.value);\n if (!endpoint) return;\n\n newSimulationMethod.value = endpoint.method.toUpperCase();\n newSimulationPath.value = endpoint.path;\n}\n\n/**\n * Handle manual path/method input\n */\nfunction handleManualInput(): void {\n // Clear endpoint selection when user types manually\n selectedEndpointKey.value = null;\n}\n\n// ==========================================================================\n// Lifecycle\n// ==========================================================================\n\nonMounted(() => {\n // Subscribe to simulation events and collect unsubscribe functions\n unsubscribers = [\n on('simulation:active', (data: SimulationActiveEvent) => {\n simulationStore.setSimulations(data.simulations);\n }),\n\n on('simulation:added', (data: SimulationPathEvent) => {\n simulationStore.handleSimulationAdded(data);\n }),\n\n on('simulation:removed', (data: SimulationPathEvent) => {\n simulationStore.handleSimulationRemoved(data);\n }),\n\n on('simulations:cleared', (data: SimulationsClearedEvent) => {\n simulationStore.handleSimulationsCleared(data);\n }),\n\n on('simulation:set', (data: SimulationSetEvent) => {\n simulationStore.handleSimulationSet(data);\n }),\n\n on('simulation:cleared', (data: SimulationClearedEvent) => {\n // Remove from pending clears if it was part of clearAll\n if (pendingClears.value.has(data.path)) {\n pendingClears.value.delete(data.path);\n }\n\n // Delegate to store handler (handles success/failure and rollback)\n simulationStore.handleSimulationCleared(data);\n }),\n ];\n\n // Request current simulations from server\n send({ type: 'get:registry' });\n});\n\n// Cleanup on unmount to prevent memory leaks\nonUnmounted(() => {\n for (const unsub of unsubscribers) {\n unsub();\n }\n});\n</script>\n\n<template>\n <div class=\"simulator-page\">\n <!-- Add Simulation Form -->\n <div class=\"simulator-form card\">\n <div class=\"simulator-form__header\">\n <Zap :size=\"18\" />\n <span>Add Simulation</span>\n </div>\n\n <div class=\"simulator-form__body\">\n <!-- Endpoint Selector (optional) -->\n <div v-if=\"availableEndpoints.length > 0\" class=\"simulator-form__row\">\n <label class=\"simulator-form__label\">Select Endpoint (optional):</label>\n <select\n v-model=\"selectedEndpointKey\"\n class=\"input\"\n @change=\"handleEndpointSelect\"\n >\n <option :value=\"null\">Manual entry...</option>\n <option\n v-for=\"endpoint in availableEndpoints\"\n :key=\"endpoint.key\"\n :value=\"endpoint.key\"\n >\n {{ endpoint.label }}\n </option>\n </select>\n </div>\n\n <!-- Method and Path -->\n <div class=\"simulator-form__row\">\n <select\n v-model=\"newSimulationMethod\"\n class=\"simulator-form__method input\"\n @change=\"handleManualInput\"\n >\n <option v-for=\"method in httpMethods\" :key=\"method\" :value=\"method\">\n {{ method }}\n </option>\n </select>\n <input\n v-model=\"newSimulationPath\"\n type=\"text\"\n class=\"simulator-form__path input\"\n placeholder=\"/api/path\"\n @input=\"handleManualInput\"\n />\n </div>\n\n <!-- Preset Selection -->\n <div class=\"simulator-presets\">\n <button\n v-for=\"preset in simulationStore.presets\"\n :key=\"preset.id\"\n :class=\"[\n 'simulator-preset',\n { 'simulator-preset--selected': selectedPresetId === preset.id },\n `simulator-preset--${preset.type}`,\n ]\"\n :title=\"preset.description\"\n @click=\"selectedPresetId = preset.id\"\n >\n <component\n :is=\"preset.type === 'delay' ? Clock : AlertTriangle\"\n :size=\"14\"\n />\n <span class=\"simulator-preset__label\">{{ preset.label }}</span>\n </button>\n </div>\n\n <!-- Add Button -->\n <button\n class=\"btn btn--primary\"\n :disabled=\"!canAddSimulation || simulationStore.isLoading\"\n @click=\"addSimulation\"\n >\n <Plus :size=\"16\" />\n <span>Add Simulation</span>\n </button>\n </div>\n </div>\n\n <!-- Active Simulations -->\n <div class=\"simulator-active\">\n <div class=\"simulator-active__header\">\n <span class=\"simulator-active__title\">\n Active Simulations ({{ simulationCount }})\n </span>\n <button\n v-if=\"simulationCount > 0\"\n class=\"btn btn--ghost\"\n :disabled=\"simulationStore.isLoading\"\n @click=\"clearAllSimulations\"\n >\n <Trash2 :size=\"14\" />\n <span>Clear All</span>\n </button>\n </div>\n\n <div class=\"simulator-active__list\">\n <div\n v-for=\"simulation in activeSimulations\"\n :key=\"simulation.path\"\n class=\"simulator-simulation card\"\n >\n <div class=\"simulator-simulation__info\">\n <span class=\"simulator-simulation__path font-mono\">\n {{ simulation.path }}\n </span>\n </div>\n <div class=\"simulator-simulation__preset\">\n <component\n :is=\"simulation.preset?.type === 'delay' ? Clock : AlertTriangle\"\n :size=\"14\"\n :class=\"{\n 'text-warning': simulation.preset?.type === 'delay',\n 'text-error': simulation.preset?.type === 'error',\n 'text-muted': simulation.preset?.type === 'empty',\n }\"\n />\n <span>\n {{ simulation.preset?.label || `HTTP ${simulation.status}` }}\n </span>\n <span v-if=\"simulation.delay\" class=\"text-muted\">\n ({{ simulation.delay }}ms)\n </span>\n </div>\n <button\n class=\"btn btn--ghost btn--icon\"\n title=\"Remove simulation\"\n :disabled=\"simulationStore.isLoading\"\n @click=\"removeSimulation(simulation.path)\"\n >\n <Trash2 :size=\"14\" />\n </button>\n </div>\n\n <!-- Empty State -->\n <div v-if=\"simulationCount === 0\" class=\"empty-state\">\n <Zap :size=\"48\" class=\"empty-state__icon\" />\n <h3 class=\"empty-state__title\">No active simulations</h3>\n <p class=\"empty-state__description\">\n Add a simulation above to test error handling and slow responses.\n </p>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.simulator-page {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-lg);\n height: 100%;\n padding: var(--devtools-space-md);\n overflow-y: auto;\n}\n\n/* Form */\n.simulator-form {\n flex-shrink: 0;\n}\n\n.simulator-form__header {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n padding-bottom: var(--devtools-space-md);\n margin-bottom: var(--devtools-space-md);\n border-bottom: 1px solid var(--devtools-border);\n font-weight: var(--font-weight-6);\n font-size: var(--font-size-1);\n}\n\n.simulator-form__body {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-md);\n}\n\n.simulator-form__row {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-xs);\n}\n\n.simulator-form__row:has(.simulator-form__method) {\n flex-direction: row;\n gap: var(--devtools-space-sm);\n}\n\n.simulator-form__label {\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text);\n}\n\n.simulator-form__method {\n width: 100px;\n flex-shrink: 0;\n}\n\n.simulator-form__path {\n flex: 1;\n}\n\n/* Presets */\n.simulator-presets {\n display: flex;\n flex-wrap: wrap;\n gap: var(--devtools-space-xs);\n}\n\n.simulator-preset {\n display: inline-flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n background-color: var(--devtools-surface-elevated);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-sm);\n font-family: var(--devtools-font-sans);\n font-size: var(--font-size-0);\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.simulator-preset:hover {\n background-color: var(--devtools-border);\n}\n\n.simulator-preset--selected {\n border-color: var(--devtools-primary);\n background-color: color-mix(\n in srgb,\n var(--devtools-primary) 15%,\n transparent\n );\n}\n\n.simulator-preset--delay {\n color: var(--devtools-warning);\n}\n\n.simulator-preset--error {\n color: var(--devtools-error);\n}\n\n.simulator-preset--empty {\n color: var(--devtools-text-muted);\n}\n\n.simulator-preset__label {\n color: var(--devtools-text);\n}\n\n/* Active Simulations */\n.simulator-active {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n.simulator-active__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: var(--devtools-space-md);\n}\n\n.simulator-active__title {\n font-weight: var(--font-weight-6);\n font-size: var(--font-size-1);\n}\n\n.simulator-active__list {\n flex: 1;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-xs);\n}\n\n/* Simulation Item */\n.simulator-simulation {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-sm) var(--devtools-space-md);\n}\n\n.simulator-simulation__info {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n flex: 1;\n}\n\n.simulator-simulation__path {\n font-size: var(--font-size-1);\n color: var(--devtools-text);\n}\n\n.simulator-simulation__preset {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n}\n\n/* Color utilities */\n.text-warning {\n color: var(--devtools-warning);\n}\n\n.text-error {\n color: var(--devtools-error);\n}\n\n.text-muted {\n color: var(--devtools-text-muted);\n}\n</style>\n"],"names":["toKebabCase","string","toCamelCase","match","p1","p2","toPascalCase","camelCase","mergeClasses","classes","className","index","array","defaultAttributes","Icon","size","strokeWidth","absoluteStrokeWidth","color","iconNode","name","props","slots","h","child","createLucideIcon","iconName","Check","ChevronDown","ChevronRight","ChevronUp","CircleAlert","CircleCheckBig","Clock","Code","Copy","Database","FileJson","Funnel","Lock","Plus","RefreshCw","Route","Save","Search","Shield","Sprout","Tag","Trash2","TriangleAlert","WifiOff","Wifi","X","Zap","DEFAULT_OPTIONS","connectionState","ref","serverVersion","reconnectAttempts","ws","reconnectTimer","currentOptions","optionsInitialized","eventHandlers","isBrowser","hasComponentContext","getCurrentInstance","buildWebSocketUrl","path","clearReconnectTimer","dispatchEvent","type","data","handlers","handler","error","wildcardHandlers","handleOpen","handleMessage","event","message","connectedData","handleClose","connect","handleError","cleanupConnection","url","disconnect","send","command","on","currentHandlers","off","once","wrappedHandler","onUntil","resetState","useWebSocket","options","connected","computed","isReconnecting","onMounted","routes","RoutesPage$1","TimelinePage$1","ModelsPage$1","SimulatorPage$1","router","createRouter","createWebHashHistory","route","useRoute","useRouter","tabs","r","activeTab","navigateTo","iconMap","getIcon","isConnected","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_createVNode","_unref","_cache","_hoisted_4","_Fragment","_renderList","tab","_normalizeClass","$event","_createBlock","_resolveDynamicComponent","_hoisted_6","_toDisplayString","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_component_router_view","_withCtx","Component","_Transition","safeClone","value","toRaw","useModelsStore","defineStore","schemas","selectedSchema","currentItems","originalItems","loading","currentSchema","s","isDirtyFlag","isDirty","schemaCount","totalItems","sum","schema","fetchSchemas","response","err","selectSchemaByName","schemaName","fetchSchemaData","items","schemaIndex","updateItems","saveItems","errorData","result","clearSchema","discardChanges","refresh","reset","handleStoreUpdate","handleReseedComplete","useRegistryStore","endpoints","stats","isLoading","searchQuery","filter","selectedEndpointKey","expandedTags","allTags","tagSet","endpoint","tag","allSchemas","schemaSet","filteredEndpoints","query","groupedEndpoints","groups","groupKey","eps","a","b","selectedEndpoint","e","handlerCount","seedCount","setRegistryData","setLoading","setError","errorMessage","clearError","setSearchQuery","toggleMethodFilter","method","setHandlerFilter","hasHandler","setSeedFilter","hasSeed","toggleTagFilter","clearFilters","hasActiveFilters","selectEndpoint","key","toggleGroup","expandAllGroups","group","collapseAllGroups","updateHandlerStatus","handlerOperationIds","handlerSet","updateSeedStatus","seedSchemas","seedSet","SIMULATION_PRESETS","useSimulationStore","simulations","previousSimulations","activeSimulations","count","presets","hasActiveSimulations","simulationsByType","grouped","simulation","getSimulationType","preset","p","setSimulations","newSimulations","addSimulationLocal","storeForRollback","previous","removeSimulationLocal","clearSimulationsLocal","getSimulation","hasSimulation","getPreset","id","createSimulationFromPreset","presetId","operationId","rollbackSimulation","handleSimulationAdded","handleSimulationRemoved","handleSimulationsCleared","handleSimulationSet","handleSimulationCleared","useTimelineStore","entries","selectedEntryId","maxEntries","responseBuffer","getStatusCategory","status","filteredEntries","entry","category","selectedEntry","totalCount","completedCount","pendingCount","statusCounts","counts","averageDuration","completedEntries","totalDuration","addRequest","request","bufferedResponse","mergeResponse","addResponse","stubEntry","createStubEntry","stubRequest","processBufferedResponses","requestMap","requestId","processIncomingResponses","incomingResponses","createStubsForOrphanedResponses","setTimelineData","item","sorted","clearTimeline","toggleStatusFilter","setSimulatedFilter","simulated","selectEntry","setMaxEntries","limit","clamped","VALID_THEME_MODES","isThemeMode","STORAGE_KEY","themeMode","systemPrefersDark","currentMediaQuery","currentMediaHandler","useTheme","effectiveTheme","isDark","applyTheme","root","setTheme","mode","toggleTheme","resetToSystem","cleanupMediaQuery","initialize","mediaQuery","saved","watch","onUnmounted","isBootstrapped","appInstance","bootstrap","app","createApp","AppComponent","pinia","createPinia","getMethodLabel","__props","hasSecurity","securityDisplay","sec","_hoisted_5","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","_hoisted_25","_hoisted_26","_hoisted_27","_hoisted_28","emit","__emit","handleEndpointClick","handleGroupToggle","isSelected","_vShow","registryStore","showFilters","searchInputRef","httpMethods","fetchRegistry","handleRegistryData","handleSelectEndpoint","handleToggleGroup","handleSearchInput","target","clearSearch","toggleMethod","isMethodActive","toggleHandlerFilter","current","toggleSeedFilter","clearAllFilters","toggleFilters","unsubRegistry","unsubHandlers","unsubSeeds","Filter","EndpointList","EndpointDetail","expandedSections","copiedField","formattedTimestamp","formattedDuration","statusClass","hasQueryParams","hasRequestHeaders","hasRequestBody","hasResponseHeaders","hasResponseBody","formatJson","toggleSection","section","copyToClipboard","text","fieldId","copyFullEntry","_createTextVNode","_withDirectives","_hoisted_29","_hoisted_30","_hoisted_31","_hoisted_32","_hoisted_33","_withModifiers","_hoisted_35","_hoisted_36","_hoisted_37","_hoisted_38","_hoisted_40","_hoisted_41","_hoisted_42","_hoisted_43","_hoisted_44","_hoisted_45","_hoisted_47","_hoisted_48","_hoisted_49","_hoisted_50","formattedTime","statusIcon","CheckCircle","AlertTriangle","isPending","handleClick","timelineStore","statusCategories","fetchTimeline","handleTimelineData","handleRequest","handleResponse","handleTimelineCleared","handleSelectEntry","toggleStatus","isStatusActive","toggleSimulatedFilter","filterBadgeCount","unsubTimeline","unsubRequest","unsubResponse","unsubCleared","TimelineEntryComponent","TimelineDetail","validationError","isValid","lineCount","lineNumbers","_","i","initializeText","currentParsed","handleInput","validateAndEmit","parsed","position","lines","line","column","handleKeyDown","start","end","newText","__expose","lineNum","AlertCircle","toasts","confirmDialog","reactive","timeouts","pendingResolve","toastIdCounter","generateToastId","addToast","duration","toast","timeoutId","removeToast","t","useNotifications","success","info","warning","confirm","resolve","closeConfirm","dismiss","clearAll","modelsStore","notifyError","jsonEditorRef","showClearConfirm","payload","nextTick","selectSchema","reseedAll","onJsonEditorUpdate","JsonEditor","_Teleport","simulationStore","newSimulationPath","newSimulationMethod","selectedPresetId","unsubscribers","pendingClears","availableEndpoints","canAddSimulation","hasPath","hasPreset","sim","simulationCount","addSimulation","trimmedPath","pathWithMethod","removeSimulation","clearAllSimulations","handleEndpointSelect","handleManualInput","unsub"],"mappings":"8VAOA,MAAMA,GAAeC,GAAWA,EAAO,QAAQ,qBAAsB,OAAO,EAAE,YAAW,EACnFC,GAAeD,GAAWA,EAAO,QACrC,wBACA,CAACE,EAAOC,EAAIC,IAAOA,EAAKA,EAAG,YAAW,EAAKD,EAAG,YAAW,CAC3D,EACME,GAAgBL,GAAW,CAC/B,MAAMM,EAAYL,GAAYD,CAAM,EACpC,OAAOM,EAAU,OAAO,CAAC,EAAE,YAAW,EAAKA,EAAU,MAAM,CAAC,CAC9D,EACMC,GAAe,IAAIC,IAAYA,EAAQ,OAAO,CAACC,EAAWC,EAAOC,IAC9D,EAAQF,GAAcA,EAAU,KAAI,IAAO,IAAME,EAAM,QAAQF,CAAS,IAAMC,CACtF,EAAE,KAAK,GAAG,EAAE,KAAI,ECXjB,IAAIE,GAAoB,CACtB,MAAO,6BACP,MAAO,GACP,OAAQ,GACR,QAAS,YACT,KAAM,OACN,OAAQ,eACR,eAAgB,EAChB,iBAAkB,QAClB,kBAAmB,OACrB,ECNA,MAAMC,GAAO,CAAC,CAAE,KAAAC,EAAM,YAAAC,EAAc,EAAG,oBAAAC,EAAqB,MAAAC,EAAO,SAAAC,EAAU,KAAAC,EAAM,MAAOX,EAAS,GAAGY,CAAK,EAAI,CAAE,MAAAC,KACxGC,EAAAA,EACL,MACA,CACE,GAAGV,GACH,MAAOE,GAAQF,GAAkB,MACjC,OAAQE,GAAQF,GAAkB,OAClC,OAAQK,GAASL,GAAkB,OACnC,eAAgBI,EAAsB,OAAOD,CAAW,EAAI,GAAK,OAAOD,CAAI,EAAIC,EAChF,MAAOR,GACL,SACA,GAAGY,EAAO,CAAC,UAAUpB,GAAYM,GAAac,CAAI,CAAC,CAAC,QAAS,UAAUpB,GAAYoB,CAAI,CAAC,EAAE,EAAI,CAAC,aAAa,CACpH,EACM,GAAGC,CACT,EACI,CAAC,GAAGF,EAAS,IAAKK,GAAUD,EAAAA,EAAE,GAAGC,CAAK,CAAC,EAAG,GAAGF,EAAM,QAAU,CAACA,EAAM,QAAO,CAAE,EAAI,CAAA,CAAE,CACvF,ECjBA,MAAMG,EAAmB,CAACC,EAAUP,IAAa,CAACE,EAAO,CAAE,MAAAC,CAAK,IAAOC,EAAAA,EACrET,GACA,CACE,GAAGO,EACH,SAAAF,EACA,KAAMO,CACV,EACEJ,CACF,ECTA,MAAMK,GAAQF,EAAiB,QAAS,CAAC,CAAC,OAAQ,CAAE,EAAG,kBAAmB,IAAK,QAAQ,CAAE,CAAC,CAAC,ECA3F,MAAMG,EAAcH,EAAiB,eAAgB,CACnD,CAAC,OAAQ,CAAE,EAAG,eAAgB,IAAK,QAAQ,CAAE,CAC/C,CAAC,ECFD,MAAMI,GAAeJ,EAAiB,gBAAiB,CACrD,CAAC,OAAQ,CAAE,EAAG,gBAAiB,IAAK,QAAQ,CAAE,CAChD,CAAC,ECFD,MAAMK,GAAYL,EAAiB,aAAc,CAC/C,CAAC,OAAQ,CAAE,EAAG,iBAAkB,IAAK,QAAQ,CAAE,CACjD,CAAC,ECFD,MAAMM,GAAcN,EAAiB,eAAgB,CACnD,CAAC,SAAU,CAAE,GAAI,KAAM,GAAI,KAAM,EAAG,KAAM,IAAK,SAAU,EACzD,CAAC,OAAQ,CAAE,GAAI,KAAM,GAAI,KAAM,GAAI,IAAK,GAAI,KAAM,IAAK,QAAQ,CAAE,EACjE,CAAC,OAAQ,CAAE,GAAI,KAAM,GAAI,QAAS,GAAI,KAAM,GAAI,KAAM,IAAK,QAAQ,CAAE,CACvE,CAAC,ECJD,MAAMO,GAAiBP,EAAiB,mBAAoB,CAC1D,CAAC,OAAQ,CAAE,EAAG,kCAAmC,IAAK,QAAQ,CAAE,EAChE,CAAC,OAAQ,CAAE,EAAG,iBAAkB,IAAK,QAAQ,CAAE,CACjD,CAAC,ECHD,MAAMQ,EAAQR,EAAiB,QAAS,CACtC,CAAC,SAAU,CAAE,GAAI,KAAM,GAAI,KAAM,EAAG,KAAM,IAAK,SAAU,EACzD,CAAC,WAAY,CAAE,OAAQ,mBAAoB,IAAK,QAAQ,CAAE,CAC5D,CAAC,ECHD,MAAMS,GAAOT,EAAiB,OAAQ,CACpC,CAAC,OAAQ,CAAE,EAAG,iBAAkB,IAAK,OAAO,CAAE,EAC9C,CAAC,OAAQ,CAAE,EAAG,eAAgB,IAAK,QAAQ,CAAE,CAC/C,CAAC,ECHD,MAAMU,GAAOV,EAAiB,OAAQ,CACpC,CAAC,OAAQ,CAAE,MAAO,KAAM,OAAQ,KAAM,EAAG,IAAK,EAAG,IAAK,GAAI,IAAK,GAAI,IAAK,IAAK,SAAU,EACvF,CAAC,OAAQ,CAAE,EAAG,0DAA2D,IAAK,QAAQ,CAAE,CAC1F,CAAC,ECHD,MAAMW,GAAWX,EAAiB,WAAY,CAC5C,CAAC,UAAW,CAAE,GAAI,KAAM,GAAI,IAAK,GAAI,IAAK,GAAI,IAAK,IAAK,QAAQ,CAAE,EAClE,CAAC,OAAQ,CAAE,EAAG,4BAA6B,IAAK,QAAQ,CAAE,EAC1D,CAAC,OAAQ,CAAE,EAAG,wBAAyB,IAAK,QAAQ,CAAE,CACxD,CAAC,ECJD,MAAMY,GAAWZ,EAAiB,YAAa,CAC7C,CAAC,OAAQ,CAAE,EAAG,6DAA8D,IAAK,QAAQ,CAAE,EAC3F,CAAC,OAAQ,CAAE,EAAG,0BAA2B,IAAK,QAAQ,CAAE,EACxD,CACE,OACA,CAAE,EAAG,qEAAsE,IAAK,QAAQ,CAC5F,EACE,CACE,OACA,CAAE,EAAG,uEAAwE,IAAK,QAAQ,CAC9F,CACA,CAAC,ECXD,MAAMa,GAASb,EAAiB,SAAU,CACxC,CACE,OACA,CACE,EAAG,qJACH,IAAK,QACX,CACA,CACA,CAAC,ECRD,MAAMc,GAAOd,EAAiB,OAAQ,CACpC,CAAC,OAAQ,CAAE,MAAO,KAAM,OAAQ,KAAM,EAAG,IAAK,EAAG,KAAM,GAAI,IAAK,GAAI,IAAK,IAAK,SAAU,EACxF,CAAC,OAAQ,CAAE,EAAG,2BAA4B,IAAK,QAAQ,CAAE,CAC3D,CAAC,ECHD,MAAMe,GAAOf,EAAiB,OAAQ,CACpC,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAQ,CAAE,EACzC,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAQ,CAAE,CAC3C,CAAC,ECHD,MAAMgB,GAAYhB,EAAiB,aAAc,CAC/C,CAAC,OAAQ,CAAE,EAAG,qDAAsD,IAAK,QAAQ,CAAE,EACnF,CAAC,OAAQ,CAAE,EAAG,aAAc,IAAK,QAAQ,CAAE,EAC3C,CAAC,OAAQ,CAAE,EAAG,sDAAuD,IAAK,QAAQ,CAAE,EACpF,CAAC,OAAQ,CAAE,EAAG,YAAa,IAAK,QAAQ,CAAE,CAC5C,CAAC,ECLD,MAAMiB,GAAQjB,EAAiB,QAAS,CACtC,CAAC,SAAU,CAAE,GAAI,IAAK,GAAI,KAAM,EAAG,IAAK,IAAK,SAAU,EACvD,CAAC,OAAQ,CAAE,EAAG,uDAAwD,IAAK,OAAO,CAAE,EACpF,CAAC,SAAU,CAAE,GAAI,KAAM,GAAI,IAAK,EAAG,IAAK,IAAK,QAAQ,CAAE,CACzD,CAAC,ECJD,MAAMkB,GAAOlB,EAAiB,OAAQ,CACpC,CACE,OACA,CACE,EAAG,qGACH,IAAK,QACX,CACA,EACE,CAAC,OAAQ,CAAE,EAAG,4CAA6C,IAAK,QAAQ,CAAE,EAC1E,CAAC,OAAQ,CAAE,EAAG,yBAA0B,IAAK,QAAQ,CAAE,CACzD,CAAC,ECVD,MAAMmB,GAASnB,EAAiB,SAAU,CACxC,CAAC,OAAQ,CAAE,EAAG,mBAAoB,IAAK,QAAQ,CAAE,EACjD,CAAC,SAAU,CAAE,GAAI,KAAM,GAAI,KAAM,EAAG,IAAK,IAAK,QAAQ,CAAE,CAC1D,CAAC,ECHD,MAAMoB,GAASpB,EAAiB,SAAU,CACxC,CACE,OACA,CACE,EAAG,qKACH,IAAK,QACX,CACA,CACA,CAAC,ECRD,MAAMqB,GAASrB,EAAiB,SAAU,CACxC,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAQ,CAAE,EACzC,CAAC,OAAQ,CAAE,EAAG,4BAA6B,IAAK,QAAQ,CAAE,EAC1D,CACE,OACA,CACE,EAAG,4FACH,IAAK,QACX,CACA,EACE,CACE,OACA,CACE,EAAG,qFACH,IAAK,QACX,CACA,CACA,CAAC,ECjBD,MAAMsB,GAAMtB,EAAiB,MAAO,CAClC,CACE,OACA,CACE,EAAG,uJACH,IAAK,QACX,CACA,EACE,CAAC,SAAU,CAAE,GAAI,MAAO,GAAI,MAAO,EAAG,KAAM,KAAM,eAAgB,IAAK,QAAQ,CAAE,CACnF,CAAC,ECTD,MAAMuB,GAASvB,EAAiB,UAAW,CACzC,CAAC,OAAQ,CAAE,EAAG,UAAW,IAAK,QAAQ,CAAE,EACxC,CAAC,OAAQ,CAAE,EAAG,wCAAyC,IAAK,QAAQ,CAAE,EACtE,CAAC,OAAQ,CAAE,EAAG,qCAAsC,IAAK,QAAQ,CAAE,EACnE,CAAC,OAAQ,CAAE,GAAI,KAAM,GAAI,KAAM,GAAI,KAAM,GAAI,KAAM,IAAK,QAAQ,CAAE,EAClE,CAAC,OAAQ,CAAE,GAAI,KAAM,GAAI,KAAM,GAAI,KAAM,GAAI,KAAM,IAAK,OAAO,CAAE,CACnE,CAAC,ECND,MAAMwB,GAAgBxB,EAAiB,iBAAkB,CACvD,CACE,OACA,CACE,EAAG,2EACH,IAAK,QACX,CACA,EACE,CAAC,OAAQ,CAAE,EAAG,UAAW,IAAK,QAAQ,CAAE,EACxC,CAAC,OAAQ,CAAE,EAAG,aAAc,IAAK,QAAQ,CAAE,CAC7C,CAAC,ECVD,MAAMyB,GAAUzB,EAAiB,WAAY,CAC3C,CAAC,OAAQ,CAAE,EAAG,aAAc,IAAK,QAAQ,CAAE,EAC3C,CAAC,OAAQ,CAAE,EAAG,4BAA6B,IAAK,QAAQ,CAAE,EAC1D,CAAC,OAAQ,CAAE,EAAG,kCAAmC,IAAK,QAAQ,CAAE,EAChE,CAAC,OAAQ,CAAE,EAAG,qCAAsC,IAAK,QAAQ,CAAE,EACnE,CAAC,OAAQ,CAAE,EAAG,kCAAmC,IAAK,QAAQ,CAAE,EAChE,CAAC,OAAQ,CAAE,EAAG,oCAAqC,IAAK,QAAQ,CAAE,EAClE,CAAC,OAAQ,CAAE,EAAG,aAAc,IAAK,QAAQ,CAAE,CAC7C,CAAC,ECRD,MAAM0B,GAAO1B,EAAiB,OAAQ,CACpC,CAAC,OAAQ,CAAE,EAAG,aAAc,IAAK,QAAQ,CAAE,EAC3C,CAAC,OAAQ,CAAE,EAAG,2BAA4B,IAAK,QAAQ,CAAE,EACzD,CAAC,OAAQ,CAAE,EAAG,6BAA8B,IAAK,QAAQ,CAAE,EAC3D,CAAC,OAAQ,CAAE,EAAG,4BAA6B,IAAK,QAAQ,CAAE,CAC5D,CAAC,ECLD,MAAM2B,GAAI3B,EAAiB,IAAK,CAC9B,CAAC,OAAQ,CAAE,EAAG,aAAc,IAAK,QAAQ,CAAE,EAC3C,CAAC,OAAQ,CAAE,EAAG,aAAc,IAAK,QAAQ,CAAE,CAC7C,CAAC,ECHD,MAAM4B,GAAM5B,EAAiB,MAAO,CAClC,CACE,OACA,CACE,EAAG,8JACH,IAAK,QACX,CACA,CACA,CAAC,EC8IK6B,GAAiD,CACrD,KAAM,OACN,eAAgB,IAChB,qBAAsB,OAAO,kBAC7B,YAAa,EACf,EAKMC,EAAkBC,EAAAA,IAAqB,cAAc,EACrDC,GAAgBD,EAAAA,IAAmB,IAAI,EACvCE,GAAoBF,EAAAA,IAAI,CAAC,EAK/B,IAAIG,EAAuB,KACvBC,GAAuD,KACvDC,GAAgD,CAAE,GAAGP,EAAA,EAMrDQ,GAAqB,GAKzB,MAAMC,MAAoB,IAK1B,SAASC,IAAqB,CAC5B,OAAO,OAAO,OAAW,KAAe,OAAO,UAAc,GAC/D,CAKA,SAASC,IAA+B,CACtC,OAAOC,EAAAA,uBAAyB,IAClC,CAKA,SAASC,GAAkBC,EAAsB,CAC/C,OAAKJ,KAKE,GADU,OAAO,SAAS,WAAa,SAAW,OAAS,KAChD,KAAK,OAAO,SAAS,IAAI,GAAGI,CAAI,GAJzC,iBAAiBA,CAAI,EAKhC,CAKA,SAASC,IAA4B,CAC/BT,KAAmB,OACrB,aAAaA,EAAc,EAC3BA,GAAiB,KAErB,CAKA,SAASU,GAAcC,EAAcC,EAAqB,CACxD,MAAMC,EAAWV,EAAc,IAAIQ,CAAI,EACvC,GAAIE,EACF,UAAWC,KAAWD,EACpB,GAAI,CACFC,EAAQF,CAAI,CACd,OAASG,EAAO,CACd,QAAQ,MAAM,oDAAoDJ,CAAI,KAAMI,CAAK,CACnF,CAKJ,MAAMC,EAAmBb,EAAc,IAAI,GAAG,EAC9C,GAAIa,EACF,UAAWF,KAAWE,EACpB,GAAI,CACFF,EAAQ,CAAE,KAAAH,EAAM,KAAAC,EAAM,CACxB,OAASG,EAAO,CACd,QAAQ,MAAM,wDAAyDA,CAAK,CAC9E,CAGN,CAKA,SAASE,IAAmB,CAC1BtB,EAAgB,MAAQ,YACxBG,GAAkB,MAAQ,EAC1BW,GAAA,CAKF,CAKA,SAASS,GAAcC,EAA2B,CAChD,GAAI,CACF,MAAMC,EAAU,KAAK,MAAMD,EAAM,IAAI,EAGrC,GAAIC,EAAQ,OAAS,YAAa,CAChC,MAAMC,EAAgBD,EAAQ,KAC9BvB,GAAc,MAAQwB,EAAc,aAKtC,CAGAX,GAAcU,EAAQ,KAAMA,EAAQ,IAAI,CAC1C,OAASL,EAAO,CACd,QAAQ,MAAM,gDAAiDA,CAAK,CACtE,CACF,CAKA,SAASO,IAAoB,CACN3B,EAAgB,MACrCA,EAAgB,MAAQ,eACxBI,EAAK,KAODD,GAAkB,MAAQG,GAAe,uBAC3CN,EAAgB,MAAQ,eACxBG,GAAkB,QAQlBE,GAAiB,WAAW,IAAM,CAChCuB,GAAA,CACF,EAAGtB,GAAe,cAAc,EAIpC,CAKA,SAASuB,GAAYL,EAAoB,CACvC,QAAQ,MAAM,8BAA+BA,CAAK,CACpD,CAKA,SAASI,IAAgB,CAUvB,GATI,CAACnB,MAUHT,EAAgB,QAAU,cAC1BA,EAAgB,QAAU,aACzBI,IAAOA,EAAG,aAAe,UAAU,YAAcA,EAAG,aAAe,UAAU,MAE9E,OAIF0B,GAAA,EAEA9B,EAAgB,MAAQ,aACxB,MAAM+B,EAAMnB,GAAkBN,GAAe,IAAI,EAEjD,GAAI,CACFF,EAAK,IAAI,UAAU2B,CAAG,EACtB3B,EAAG,OAASkB,GACZlB,EAAG,UAAYmB,GACfnB,EAAG,QAAUuB,GACbvB,EAAG,QAAUyB,EACf,OAAST,EAAO,CACd,QAAQ,MAAM,mDAAoDA,CAAK,EACvEpB,EAAgB,MAAQ,cAC1B,CACF,CAMA,SAAS8B,IAA0B,CAC7B1B,IAEFA,EAAG,OAAS,KACZA,EAAG,UAAY,KACfA,EAAG,QAAU,KACbA,EAAG,QAAU,MAETA,EAAG,aAAe,UAAU,MAAQA,EAAG,aAAe,UAAU,aAClEA,EAAG,MAAA,EAGLA,EAAK,KAET,CAKA,SAAS4B,IAAmB,CAC1BlB,GAAA,EACAgB,GAAA,EAEA9B,EAAgB,MAAQ,eACxBG,GAAkB,MAAQ,CAC5B,CAQA,SAAS8B,GAAkBC,EAAoC,CAC7D,GAAI,CAAC9B,GAAMA,EAAG,aAAe,UAAU,KAIrC,MAAO,GAGT,GAAI,CACF,OAAAA,EAAG,KAAK,KAAK,UAAU8B,CAAO,CAAC,EACxB,EACT,OAASd,EAAO,CACd,eAAQ,MAAM,+CAAgDA,CAAK,EAC5D,EACT,CACF,CASA,SAASe,GAAgBX,EAA8BL,EAAsC,CACtFX,EAAc,IAAIgB,CAAK,GAC1BhB,EAAc,IAAIgB,EAAO,IAAI,GAAK,EAGpC,MAAMN,EAAWV,EAAc,IAAIgB,CAAK,EACxC,OAAIN,GACFA,EAAS,IAAIC,CAAuB,EAI/B,IAAM,CACX,MAAMiB,EAAkB5B,EAAc,IAAIgB,CAAK,EAC3CY,IACFA,EAAgB,OAAOjB,CAAuB,EAC1CiB,EAAgB,OAAS,GAC3B5B,EAAc,OAAOgB,CAAK,EAGhC,CACF,CAQA,SAASa,GAAiBb,EAA8BL,EAAgC,CACtF,MAAMD,EAAWV,EAAc,IAAIgB,CAAK,EACpCN,IACFA,EAAS,OAAOC,CAAuB,EACnCD,EAAS,OAAS,GACpBV,EAAc,OAAOgB,CAAK,EAGhC,CAkBA,SAASc,GAAkBd,EAA8BL,EAAsC,CAC7F,MAAMoB,EAAmCtB,GAAS,CAChDoB,GAAIb,EAAOe,CAAc,EACzBpB,EAAQF,CAAI,CACd,EAEA,OAAOkB,GAAGX,EAAOe,CAAc,CACjC,CAsBA,SAASC,GACPhB,EACAL,EACY,CACZ,MAAMoB,EAAmCtB,GAAS,CACjCE,EAAQF,CAAI,IACZ,IACboB,GAAIb,EAAOe,CAAc,CAE7B,EAEA,OAAOJ,GAAGX,EAAOe,CAAc,CACjC,CAKA,SAASE,IAAmB,CAC1BT,GAAA,EACA9B,GAAc,MAAQ,KACtBM,EAAc,MAAA,EACdF,GAAiB,CAAE,GAAGP,EAAA,EACtBQ,GAAqB,EACvB,CAcO,SAASmC,GAAaC,EAA+B,GAAwB,EAG9E,CAACpC,IAAsBP,EAAgB,QAAU,kBACnDM,GAAiB,CAAE,GAAGP,GAAiB,GAAG4C,CAAA,EAC1CpC,GAAqB,IAMvB,MAAMqC,EAAYC,EAAAA,SAAS,IAAM7C,EAAgB,QAAU,WAAW,EAKhE8C,EAAiBD,EAAAA,SAAS,IAAM7C,EAAgB,QAAU,cAAc,EAO9E,OAAIU,MACFqC,EAAAA,UAAU,IAAM,CACVzC,GAAe,aACjBsB,GAAA,CAEJ,CAAC,EAGI,CAIL,gBAAiBiB,EAAAA,SAAS,IAAM7C,EAAgB,KAAK,EAKrD,UAAA4C,EAKA,eAAAE,EAKA,cAAeD,EAAAA,SAAS,IAAM3C,GAAc,KAAK,EAKjD,kBAAmB2C,EAAAA,SAAS,IAAM1C,GAAkB,KAAK,EAKzD,QAAAyB,GAKA,WAAAI,GAKA,KAAAC,GAKA,GAAAE,GAKA,IAAAE,GAKA,KAAAC,GAKA,QAAAE,GAKA,WAAAC,EAAA,CAEJ,CCpnBA,MAAMO,GAA2B,CAC/B,CACE,KAAM,IACN,SAAU,SAAA,EAEZ,CACE,KAAM,UACN,KAAM,SACN,UAAW,IAAM,QAAA,QAAA,EAAA,KAAA,IAAAC,EAAA,EACjB,KAAM,CACJ,MAAO,SACP,KAAM,OAAA,CACR,EAEF,CACE,KAAM,YACN,KAAM,WACN,UAAW,IAAM,QAAA,QAAA,EAAA,KAAA,IAAAC,EAAA,EACjB,KAAM,CACJ,MAAO,WACP,KAAM,OAAA,CACR,EAEF,CACE,KAAM,UACN,KAAM,SACN,UAAW,IAAM,QAAA,QAAA,EAAA,KAAA,IAAAC,EAAA,EACjB,KAAM,CACJ,MAAO,SACP,KAAM,UAAA,CACR,EAEF,CACE,KAAM,aACN,KAAM,YACN,UAAW,IAAM,QAAA,QAAA,EAAA,KAAA,IAAAC,EAAA,EACjB,KAAM,CACJ,MAAO,YACP,KAAM,KAAA,CACR,EAGF,CACE,KAAM,mBACN,KAAM,YACN,SAAU,SAAA,CAEd,EAQMC,GAASC,GAAAA,aAAa,CAC1B,QAASC,GAAAA,qBAAA,EACT,OAAAP,EACF,CAAC,iZC9DD,MAAMQ,EAAQC,GAAAA,SAAA,EACRJ,EAASK,GAAAA,UAAA,EAGTC,EAAOd,EAAAA,SAAS,IACpBG,GACG,OAAQY,GAAMA,EAAE,MAAQA,EAAE,MAAM,KAAK,EACrC,IAAKA,IAAO,CACX,KAAMA,EAAE,KACR,KAAMA,EAAE,KACR,MAAOA,EAAE,MAAM,MACf,KAAMA,EAAE,MAAM,IAAA,EACd,CAAA,EAIAC,EAAYhB,EAAAA,SAAS,IAAMW,EAAM,IAAc,EAGrD,SAASM,EAAWjD,EAAoB,CACtCwC,EAAO,KAAKxC,CAAI,CAClB,CAGA,MAAMkD,EAAwC,CAC5C,MAAO5E,GACP,MAAOT,EACP,SAAUG,GACV,IAAKiB,EAAA,EAIP,SAASkE,EAAQ7F,EAAgC,CAK/C,OAJa4F,EAAQ5F,CAAQ,GAIdgB,EACjB,CAGA,KAAM,CAAE,UAAW8E,CAAA,EAAgBvB,GAAA,0DAIjC,OAAAwB,YAAA,EAAAC,qBAgEM,MAhENC,GAgEM,CA9DJC,EAAAA,mBAoDS,SApDTC,GAoDS,CAnDPD,EAAAA,mBAGM,MAHNE,GAGM,CAFJC,cAA2CC,EAAAA,MAAA3E,EAAA,EAAA,CAAtC,MAAM,mBAAoB,KAAM,EAAA,GACrC4E,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAAuD,OAAA,CAAjD,MAAM,qBAAoB,mBAAgB,EAAA,EAAA,GAIlDA,EAAAA,mBAsBM,MAtBNM,GAsBM,kBArBJR,EAAAA,mBAoBSS,EAAAA,SAAA,KAAAC,EAAAA,WAnBOlB,EAAA,MAAPmB,kBADTX,EAAAA,mBAoBS,SAAA,CAlBN,IAAKW,EAAI,KACV,KAAK,MACJ,gBAAejB,EAAA,QAAciB,EAAI,KACjC,eAAcjB,EAAA,QAAciB,EAAI,YAAgB,OAChD,gBAAa,SAAWA,EAAI,IAAI,GAChC,SAAU,EACV,MAAKC,EAAAA,eAAA,wCAAsElB,EAAA,QAAciB,EAAI,IAAA,CAAI,GAIjG,QAAKE,GAAElB,EAAWgB,EAAI,IAAI,CAAA,IAE3BZ,EAAAA,UAAA,EAAAe,EAAAA,YAIEC,EAAAA,wBAHKlB,EAAQc,EAAI,IAAI,CAAA,EAAA,CACpB,KAAM,GACP,MAAM,eAAA,IAERT,EAAAA,mBAAmD,OAAnDc,GAAmDC,EAAAA,gBAAnBN,EAAI,KAAK,EAAA,CAAA,CAAA,mBAK7CT,EAAAA,mBAmBM,MAnBNgB,GAmBM,CAlBJhB,EAAAA,mBAiBM,MAjBNiB,GAiBM,CAhBJjB,EAAAA,mBAOE,OAAA,CANC,MAAKU,EAAAA,eAAA,0BAA0DN,QAAAR,CAAA,wFAOlEI,qBAEO,OAFPkB,GAEOH,kBADFX,EAAAA,MAAAR,CAAA,EAAW,YAAA,cAAA,EAAA,CAAA,GAEhBC,EAAAA,YAAAe,EAAAA,YAIEC,EAAAA,wBAHKT,EAAAA,MAAAR,CAAA,EAAcQ,EAAAA,MAAA7E,EAAA,EAAO6E,QAAA9E,EAAA,CAAO,EAAA,CAChC,KAAM,GACP,MAAM,yBAAA,UAOd0E,EAAAA,mBAMO,OANPmB,GAMO,CALLhB,EAAAA,YAIciB,EAAA,KAAA,CAHZ,QAAAC,EAAAA,QAAA,CAEa,CAHQ,UAAAC,KAAS,CAC9BnB,EAAAA,YAEaoB,EAAAA,WAAA,CAFD,KAAK,OAAO,KAAK,QAAA,qBAC3B,IAA6B,EAA7B1B,EAAAA,YAAAe,EAAAA,YAA6BC,EAAAA,wBAAbS,CAAS,CAAA,EAAA,8IC/FnC,SAASE,GAAaC,EAAa,CACjC,GAAI,CACF,OAAO,gBAAgBC,QAAMD,CAAK,CAAC,CACrC,MAAQ,CACN,OAAO,KAAK,MAAM,KAAK,UAAUA,CAAK,CAAC,CACzC,CACF,CAiDO,MAAME,GAAiBC,EAAAA,YAAY,SAAU,IAAM,CAMxD,MAAMC,EAA6BjG,EAAAA,IAAI,EAAE,EAGnCkG,EAAqClG,EAAAA,IAAI,IAAI,EAG7CmG,EAA+BnG,EAAAA,IAAI,EAAE,EAGrCoG,EAAgCpG,EAAAA,IAAI,EAAE,EAGtCqG,EAAwBrG,EAAAA,IAAI,EAAK,EAGjCmB,EAA4BnB,EAAAA,IAAI,IAAI,EASpCsG,EAAgD1D,EAAAA,SAAS,IACxDsD,EAAe,MACbD,EAAQ,MAAM,KAAMM,GAAMA,EAAE,OAASL,EAAe,KAAK,GAAK,KADnC,IAEnC,EAKKM,EAA4BxG,EAAAA,IAAI,EAAK,EAKrCyG,EAAgC7D,EAAAA,SAAS,IAAM4D,EAAY,KAAK,EAKhEE,EAAmC9D,EAAAA,SAAS,IAAMqD,EAAQ,MAAM,MAAM,EAKtEU,EAAkC/D,EAAAA,SAAS,IACxCqD,EAAQ,MAAM,OAAO,CAACW,EAAKC,IAAWD,EAAMC,EAAO,MAAO,CAAC,CACnE,EASD,eAAeC,GAA8B,CAC3CT,EAAQ,MAAQ,GAChBlF,EAAM,MAAQ,KAEd,GAAI,CACF,MAAM4F,EAAW,MAAM,MAAM,aAAa,EAC1C,GAAI,CAACA,EAAS,GACZ,MAAM,IAAI,MAAM,4BAA4BA,EAAS,UAAU,EAAE,EAGnE,MAAM/F,EAAO,MAAM+F,EAAS,KAAA,EAC5Bd,EAAQ,MAAQjF,EAAK,SAAW,CAAA,CAClC,OAASgG,EAAK,CACZ7F,EAAM,MAAQ6F,aAAe,MAAQA,EAAI,QAAU,0BACnD,QAAQ,MAAM,wCAAyCA,CAAG,CAC5D,QAAA,CACEX,EAAQ,MAAQ,EAClB,CACF,CAKA,eAAeY,EAAmBC,EAAmC,CAC/DhB,EAAe,QAAUgB,IAE7BhB,EAAe,MAAQgB,EACvB,MAAMC,EAAgBD,CAAU,EAClC,CAKA,eAAeC,EAAgBD,EAAmC,CAChEb,EAAQ,MAAQ,GAChBlF,EAAM,MAAQ,KAEd,GAAI,CACF,MAAM4F,EAAW,MAAM,MAAM,eAAe,mBAAmBG,CAAU,CAAC,EAAE,EAC5E,GAAI,CAACH,EAAS,GACZ,MAAM,IAAI,MAAM,gCAAgCA,EAAS,UAAU,EAAE,EAGvE,MAAM/F,EAAmB,MAAM+F,EAAS,KAAA,EAClCK,EAAQpG,EAAK,OAAS,CAAA,EAE5BmF,EAAa,MAAQP,GAAUwB,CAAK,EACpChB,EAAc,MAAQR,GAAUwB,CAAK,EACrCZ,EAAY,MAAQ,GAGpB,MAAMa,EAAcpB,EAAQ,MAAM,UAAWM,GAAMA,EAAE,OAASW,CAAU,EACpEG,IAAgB,KAClBpB,EAAQ,MAAMoB,CAAW,EAAE,MAAQrG,EAAK,MAE5C,OAASgG,EAAK,CACZ7F,EAAM,MAAQ6F,aAAe,MAAQA,EAAI,QAAU,8BACnD,QAAQ,MAAM,4CAA6CA,CAAG,CAChE,QAAA,CACEX,EAAQ,MAAQ,EAClB,CACF,CAKA,SAASiB,EAAYF,EAAsB,CAEzC,GAAI,CAAC,MAAM,QAAQA,CAAK,EAAG,CACzBjG,EAAM,MAAQ,2CACd,QAAQ,MAAM,sDAAuD,OAAOiG,CAAK,EACjF,MACF,CAEAjB,EAAa,MAAQiB,EAErBjG,EAAM,MAAQ,KAEdqF,EAAY,MAAQ,EACtB,CAKA,eAAee,GAA8B,CAC3C,GAAI,CAACrB,EAAe,MAClB,OAAA/E,EAAM,MAAQ,qBACP,GAGTkF,EAAQ,MAAQ,GAChBlF,EAAM,MAAQ,KAEd,GAAI,CACF,MAAM4F,EAAW,MAAM,MAAM,eAAe,mBAAmBb,EAAe,KAAK,CAAC,GAAI,CACtF,OAAQ,OACR,QAAS,CACP,eAAgB,kBAAA,EAElB,KAAM,KAAK,UAAUC,EAAa,KAAK,CAAA,CACxC,EAED,GAAI,CAACY,EAAS,GAAI,CAChB,MAAMS,EAAY,MAAMT,EAAS,KAAA,EAAO,MAAM,KAAO,CAAA,EAAG,EACxD,MAAM,IAAI,MAAMS,EAAU,OAAS,yBAAyBT,EAAS,UAAU,EAAE,CACnF,CAEA,MAAMU,EAAS,MAAMV,EAAS,KAAA,EAG9BX,EAAc,MAAQR,GAAUO,EAAa,KAAK,EAClDK,EAAY,MAAQ,GAGpB,MAAMa,EAAcpB,EAAQ,MAAM,UAAWM,GAAMA,EAAE,OAASL,EAAe,KAAK,EAClF,OAAImB,IAAgB,KAClBpB,EAAQ,MAAMoB,CAAW,EAAE,MAAQI,EAAO,SAAWtB,EAAa,MAAM,QAGnE,EACT,OAASa,EAAK,CACZ,OAAA7F,EAAM,MAAQ6F,aAAe,MAAQA,EAAI,QAAU,uBACnD,QAAQ,MAAM,oCAAqCA,CAAG,EAC/C,EACT,QAAA,CACEX,EAAQ,MAAQ,EAClB,CACF,CAKA,eAAeqB,GAAgC,CAC7C,GAAI,CAACxB,EAAe,MAClB,OAAA/E,EAAM,MAAQ,qBACP,GAGTkF,EAAQ,MAAQ,GAChBlF,EAAM,MAAQ,KAEd,GAAI,CACF,MAAM4F,EAAW,MAAM,MAAM,eAAe,mBAAmBb,EAAe,KAAK,CAAC,GAAI,CACtF,OAAQ,QAAA,CACT,EAED,GAAI,CAACa,EAAS,GACZ,MAAM,IAAI,MAAM,2BAA2BA,EAAS,UAAU,EAAE,EAIlEZ,EAAa,MAAQ,CAAA,EACrBC,EAAc,MAAQ,CAAA,EACtBI,EAAY,MAAQ,GAGpB,MAAMa,EAAcpB,EAAQ,MAAM,UAAWM,GAAMA,EAAE,OAASL,EAAe,KAAK,EAClF,OAAImB,IAAgB,KAClBpB,EAAQ,MAAMoB,CAAW,EAAE,MAAQ,GAG9B,EACT,OAASL,EAAK,CACZ,OAAA7F,EAAM,MAAQ6F,aAAe,MAAQA,EAAI,QAAU,yBACnD,QAAQ,MAAM,uCAAwCA,CAAG,EAClD,EACT,QAAA,CACEX,EAAQ,MAAQ,EAClB,CACF,CAKA,SAASsB,GAAuB,CAC9BxB,EAAa,MAAQP,GAAUQ,EAAc,KAAK,EAClDI,EAAY,MAAQ,EACtB,CAKA,eAAeoB,GAAyB,CAClC1B,EAAe,MACjB,MAAMiB,EAAgBjB,EAAe,KAAK,EAE1C,MAAMY,EAAA,CAEV,CAKA,SAASe,GAAc,CACrB5B,EAAQ,MAAQ,CAAA,EAChBC,EAAe,MAAQ,KACvBC,EAAa,MAAQ,CAAA,EACrBC,EAAc,MAAQ,CAAA,EACtBC,EAAQ,MAAQ,GAChBlF,EAAM,MAAQ,KACdqF,EAAY,MAAQ,EACtB,CAKA,SAASsB,EAAkB9G,EAA+D,CACxF,MAAMqG,EAAcpB,EAAQ,MAAM,UAAWM,GAAMA,EAAE,OAASvF,EAAK,MAAM,EACrEqG,IAAgB,KAClBpB,EAAQ,MAAMoB,CAAW,EAAE,MAAQrG,EAAK,OAItCkF,EAAe,QAAUlF,EAAK,SAC3ByF,EAAQ,MAIX,QAAQ,KACN,mDAAmDzF,EAAK,MAAM,2BAAA,EAJhEmG,EAAgBnG,EAAK,MAAM,EAQjC,CAKA,SAAS+G,EAAqB/G,EAAqD,CAC7EA,EAAK,UAEP8F,EAAA,EAGIZ,EAAe,QACZO,EAAQ,MAGX,QAAQ,KACN,gEAAgEP,EAAe,KAAK,2BAAA,EAHtFiB,EAAgBjB,EAAe,KAAK,GAQ5C,CAMA,MAAO,CAEL,QAAAD,EACA,eAAAC,EACA,aAAAC,EACA,QAAAE,EACA,MAAAlF,EAGA,cAAAmF,EACA,QAAAG,EACA,YAAAC,EACA,WAAAC,EAGA,aAAAG,EACA,mBAAAG,EACA,gBAAAE,EACA,YAAAG,EACA,UAAAC,EACA,YAAAG,EACA,eAAAC,EACA,QAAAC,EACA,MAAAC,EACA,kBAAAC,EACA,qBAAAC,CAAA,CAEJ,CAAC,EC3UYC,GAAmBhC,EAAAA,YAAY,WAAY,IAAM,CAM5D,MAAMiC,EAAYjI,EAAAA,IAAqB,EAAE,EAGnCkI,EAAQlI,EAAAA,IAAmB,CAC/B,eAAgB,EAChB,kBAAmB,EACnB,aAAc,EACd,eAAgB,EAChB,cAAe,CAAA,CAChB,EAGKmI,EAAYnI,EAAAA,IAAI,EAAK,EAGrBmB,EAAQnB,EAAAA,IAAmB,IAAI,EAG/BoI,EAAcpI,EAAAA,IAAI,EAAE,EAGpBqI,EAASrI,EAAAA,IAAoB,CACjC,QAAS,CAAA,EACT,WAAY,KACZ,QAAS,KACT,KAAM,CAAA,CAAC,CACR,EAGKsI,EAAsBtI,EAAAA,IAAmB,IAAI,EAG7CuI,EAAevI,EAAAA,IAAiB,IAAI,GAAK,EASzCwI,EAAU5F,EAAAA,SAAS,IAAM,CAC7B,MAAM6F,MAAa,IACnB,UAAWC,KAAYT,EAAU,MAC/B,UAAWU,KAAOD,EAAS,KACzBD,EAAO,IAAIE,CAAG,EAGlB,OAAO,MAAM,KAAKF,CAAM,EAAE,KAAA,CAC5B,CAAC,EAKKG,EAAahG,EAAAA,SAAS,IAAM,CAChC,MAAMiG,MAAgB,IACtB,UAAWH,KAAYT,EAAU,MAC3BS,EAAS,gBACXG,EAAU,IAAIH,EAAS,cAAc,EAGzC,OAAO,MAAM,KAAKG,CAAS,EAAE,KAAA,CAC/B,CAAC,EAKKC,EAAoBlG,EAAAA,SAAS,IAAM,CACvC,IAAI6E,EAASQ,EAAU,MAGvB,GAAIG,EAAY,MAAM,OAAQ,CAC5B,MAAMW,EAAQX,EAAY,MAAM,YAAA,EAAc,KAAA,EAC9CX,EAASA,EAAO,OAAQiB,GAEpBA,EAAS,KAAK,YAAA,EAAc,SAASK,CAAK,GAC1CL,EAAS,YAAY,YAAA,EAAc,SAASK,CAAK,GACjDL,EAAS,SAAS,YAAA,EAAc,SAASK,CAAK,GAC9CL,EAAS,KAAK,KAAMC,GAAQA,EAAI,YAAA,EAAc,SAASI,CAAK,CAAC,CAEhE,CACH,CAGA,OAAIV,EAAO,MAAM,QAAQ,OAAS,IAChCZ,EAASA,EAAO,OAAQiB,GAAaL,EAAO,MAAM,QAAQ,SAASK,EAAS,MAAM,CAAC,GAIjFL,EAAO,MAAM,aAAe,OAC9BZ,EAASA,EAAO,OAAQiB,GAAaA,EAAS,aAAeL,EAAO,MAAM,UAAU,GAIlFA,EAAO,MAAM,UAAY,OAC3BZ,EAASA,EAAO,OAAQiB,GAAaA,EAAS,UAAYL,EAAO,MAAM,OAAO,GAI5EA,EAAO,MAAM,KAAK,OAAS,IAC7BZ,EAASA,EAAO,OAAQiB,GACtBA,EAAS,KAAK,KAAMC,GAAQN,EAAO,MAAM,KAAK,SAASM,CAAG,CAAC,CAAA,GAIxDlB,CACT,CAAC,EAUKuB,EAAmBpG,EAAAA,SAAS,IAAuB,CACvD,MAAMqG,MAAa,IAEnB,UAAWP,KAAYI,EAAkB,MAAO,CAE9C,IAAII,EAEAR,EAAS,KAAK,OAAS,EAEzBQ,EAAWR,EAAS,KAAK,CAAC,EACjBA,EAAS,eAElBQ,EAAWR,EAAS,eAIpBQ,EADiBR,EAAS,KAAK,MAAM,GAAG,EAAE,OAAO,OAAO,EACpC,CAAC,GAAK,QAGvBO,EAAO,IAAIC,CAAQ,GACtBD,EAAO,IAAIC,EAAU,EAAE,EAEzBD,EAAO,IAAIC,CAAQ,GAAG,KAAKR,CAAQ,CACrC,CAGA,OAAO,MAAM,KAAKO,EAAO,QAAA,CAAS,EAC/B,IAAI,CAAC,CAACN,EAAKQ,CAAG,KAAO,CACpB,IAAAR,EACA,UAAWQ,EAAI,KAAK,CAACC,EAAGC,IAAMD,EAAE,KAAK,cAAcC,EAAE,IAAI,CAAC,EAC1D,WAAYd,EAAa,MAAM,IAAII,CAAG,CAAA,EACtC,EACD,KAAK,CAACS,EAAGC,IAAMD,EAAE,IAAI,cAAcC,EAAE,GAAG,CAAC,CAC9C,CAAC,EAKKC,EAAmB1G,EAAAA,SAAS,IAC3B0F,EAAoB,MAClBL,EAAU,MAAM,KAAMsB,GAAMA,EAAE,MAAQjB,EAAoB,KAAK,GAAK,KADpC,IAExC,EAKKkB,EAAe5G,EAAAA,SAAS,IAAMqF,EAAU,MAAM,OAAQsB,GAAMA,EAAE,UAAU,EAAE,MAAM,EAKhFE,EAAY7G,EAAAA,SAAS,IAAMqF,EAAU,MAAM,OAAQsB,GAAMA,EAAE,OAAO,EAAE,MAAM,EAShF,SAASG,EAAgB1I,EAA0B,CACjDiH,EAAU,MAAQjH,EAAK,UACvBkH,EAAM,MAAQlH,EAAK,MACnBG,EAAM,MAAQ,KAGd,UAAWuH,KAAY1H,EAAK,UACtB0H,EAAS,KAAK,OAAS,GACzBH,EAAa,MAAM,IAAIG,EAAS,KAAK,CAAC,CAAC,CAG7C,CAKA,SAASiB,EAAWtD,EAAwB,CAC1C8B,EAAU,MAAQ9B,CACpB,CAKA,SAASuD,EAASC,EAA4B,CAC5C1I,EAAM,MAAQ0I,EACd1B,EAAU,MAAQ,EACpB,CAKA,SAAS2B,GAAmB,CAC1B3I,EAAM,MAAQ,IAChB,CAKA,SAAS4I,EAAehB,EAAqB,CAC3CX,EAAY,MAAQW,CACtB,CAKA,SAASiB,EAAmBC,EAA0B,CACpD,MAAM9M,EAAQkL,EAAO,MAAM,QAAQ,QAAQ4B,CAAM,EAC7C9M,IAAU,GACZkL,EAAO,MAAM,QAAQ,KAAK4B,CAAM,EAEhC5B,EAAO,MAAM,QAAQ,OAAOlL,EAAO,CAAC,CAExC,CAKA,SAAS+M,EAAiBC,EAAkC,CAC1D9B,EAAO,MAAM,WAAa8B,CAC5B,CAKA,SAASC,EAAcC,EAA+B,CACpDhC,EAAO,MAAM,QAAUgC,CACzB,CAKA,SAASC,EAAgB3B,EAAmB,CAC1C,MAAMxL,EAAQkL,EAAO,MAAM,KAAK,QAAQM,CAAG,EACvCxL,IAAU,GACZkL,EAAO,MAAM,KAAK,KAAKM,CAAG,EAE1BN,EAAO,MAAM,KAAK,OAAOlL,EAAO,CAAC,CAErC,CAKA,SAASoN,GAAqB,CAC5BlC,EAAO,MAAQ,CACb,QAAS,CAAA,EACT,WAAY,KACZ,QAAS,KACT,KAAM,CAAA,CAAC,EAETD,EAAY,MAAQ,EACtB,CAKA,SAASoC,GAA4B,CACnC,OACEpC,EAAY,MAAM,KAAA,IAAW,IAC7BC,EAAO,MAAM,QAAQ,OAAS,GAC9BA,EAAO,MAAM,aAAe,MAC5BA,EAAO,MAAM,UAAY,MACzBA,EAAO,MAAM,KAAK,OAAS,CAE/B,CAKA,SAASoC,EAAeC,EAA0B,CAChDpC,EAAoB,MAAQoC,CAC9B,CAKA,SAASC,EAAYhC,EAAmB,CAClCJ,EAAa,MAAM,IAAII,CAAG,EAC5BJ,EAAa,MAAM,OAAOI,CAAG,EAE7BJ,EAAa,MAAM,IAAII,CAAG,CAE9B,CAKA,SAASiC,GAAwB,CAC/B,UAAWC,KAAS7B,EAAiB,MACnCT,EAAa,MAAM,IAAIsC,EAAM,GAAG,CAEpC,CAKA,SAASC,GAA0B,CACjCvC,EAAa,MAAM,MAAA,CACrB,CAMA,SAASwC,EAAoBC,EAAqC,CAChE,MAAMC,EAAa,IAAI,IAAID,CAAmB,EAC9C,UAAWtC,KAAYT,EAAU,MAC/BS,EAAS,WAAauC,EAAW,IAAIvC,EAAS,WAAW,CAE7D,CAMA,SAASwC,EAAiBC,EAA6B,CACrD,MAAMC,EAAU,IAAI,IAAID,CAAW,EACnC,UAAWzC,KAAYT,EAAU,MAC/BS,EAAS,QAAUA,EAAS,eAAiB0C,EAAQ,IAAI1C,EAAS,cAAc,EAAI,EAExF,CAMA,MAAO,CAEL,UAAAT,EACA,MAAAC,EACA,UAAAC,EACA,MAAAhH,EACA,YAAAiH,EACA,OAAAC,EACA,oBAAAC,EACA,aAAAC,EAGA,QAAAC,EACA,WAAAI,EACA,kBAAAE,EACA,iBAAAE,EACA,iBAAAM,EACA,aAAAE,EACA,UAAAC,EAGA,gBAAAC,EACA,WAAAC,EACA,SAAAC,EACA,WAAAE,EACA,eAAAC,EACA,mBAAAC,EACA,iBAAAE,EACA,cAAAE,EACA,gBAAAE,EACA,aAAAC,EACA,iBAAAC,EACA,eAAAC,EACA,YAAAE,EACA,gBAAAC,EACA,kBAAAE,EACA,oBAAAC,EACA,iBAAAG,CAAA,CAEJ,CAAC,EC/aYG,GAAyC,CACpD,CACE,GAAI,eACJ,MAAO,eACP,YAAa,+BACb,KAAM,QACN,OAAQ,IACR,MAAO,GAAA,EAET,CACE,GAAI,eACJ,MAAO,eACP,YAAa,mBACb,KAAM,QACN,OAAQ,IACR,KAAM,CAAE,MAAO,wBAAyB,QAAS,wBAAA,CAAyB,EAE5E,CACE,GAAI,aACJ,MAAO,eACP,YAAa,mBACb,KAAM,QACN,OAAQ,IACR,KAAM,CAAE,MAAO,oBAAqB,QAAS,qBAAA,CAAsB,EAErE,CACE,GAAI,YACJ,MAAO,YACP,YAAa,mBACb,KAAM,QACN,OAAQ,IACR,KAAM,CAAE,MAAO,YAAa,QAAS,oBAAA,CAAqB,EAE5D,CACE,GAAI,kBACJ,MAAO,kBACP,YAAa,oCACb,KAAM,QACN,OAAQ,IACR,MAAO,GAAA,EAET,CACE,GAAI,iBACJ,MAAO,iBACP,YAAa,mCACb,KAAM,QACN,OAAQ,IACR,KAAM,IAAA,EAER,CACE,GAAI,eACJ,MAAO,eACP,YAAa,mBACb,KAAM,QACN,OAAQ,IACR,KAAM,CAAE,MAAO,eAAgB,QAAS,yBAAA,CAA0B,CAEtE,EAWaC,GAAqBtF,EAAAA,YAAY,aAAc,IAAM,CAShE,MAAMuF,EAAcvL,EAAAA,IAAmC,IAAI,GAAK,EAM1DwL,EAAsBxL,EAAAA,IAA0C,IAAI,GAAK,EAKzEmI,EAAYnI,EAAAA,IAAI,EAAK,EAKrBmB,EAAQnB,EAAAA,IAAmB,IAAI,EAS/ByL,EAAoB7I,EAAAA,SAAS,IAC1B,MAAM,KAAK2I,EAAY,MAAM,QAAQ,CAC7C,EAKKG,EAAQ9I,EAAAA,SAAS,IAAM2I,EAAY,MAAM,IAAI,EAK7CI,EAAU/I,WAAS,IAAMyI,EAAkB,EAK3CO,EAAuBhJ,EAAAA,SAAS,IAAM2I,EAAY,MAAM,KAAO,CAAC,EAKhEM,EAAoBjJ,EAAAA,SAAS,IAAM,CACvC,MAAMkJ,EAAU,CACd,MAAO,CAAA,EACP,MAAO,CAAA,EACP,MAAO,CAAA,CAAC,EAGV,UAAWC,KAAcR,EAAY,MAAM,OAAA,EAAU,CACnD,MAAMxK,EAAOiL,EAAkBD,CAAU,EACzCD,EAAQ/K,CAAI,EAAE,KAAKgL,CAAU,CAC/B,CAEA,OAAOD,CACT,CAAC,EAKD,SAASE,EAAkBD,EAAoD,CAC7E,MAAME,EAASF,EAAW,SACtBV,GAAmB,KAAMa,GAAMA,EAAE,KAAOH,EAAW,QAAQ,EAC3D,KAEJ,OAAIE,EACKA,EAAO,KAGZF,EAAW,OAASA,EAAW,MAAQ,EAClC,QAGLA,EAAW,OAAS,KACf,QAGF,OACT,CASA,SAASI,EAAeC,EAA0C,CAChEb,EAAY,MAAM,MAAA,EAClB,UAAWQ,KAAcK,EACvBb,EAAY,MAAM,IAAIQ,EAAW,KAAMA,CAAU,EAEnD5K,EAAM,MAAQ,IAChB,CAOA,SAASkL,EAAmBN,EAA8BO,EAAmB,GAAa,CACxF,GAAIA,EAAkB,CAEpB,MAAMC,EAAWhB,EAAY,MAAM,IAAIQ,EAAW,IAAI,GAAK,KAC3DP,EAAoB,MAAM,IAAIO,EAAW,KAAMQ,CAAQ,CACzD,CACAhB,EAAY,MAAM,IAAIQ,EAAW,KAAMA,CAAU,CACnD,CAOA,SAASS,EAAsB5L,EAAc0L,EAAmB,GAAgB,CAC9E,GAAIA,EAAkB,CAEpB,MAAMC,EAAWhB,EAAY,MAAM,IAAI3K,CAAI,GAAK,KAChD4K,EAAoB,MAAM,IAAI5K,EAAM2L,CAAQ,CAC9C,CACA,OAAOhB,EAAY,MAAM,OAAO3K,CAAI,CACtC,CAMA,SAAS6L,GAA8B,CACrClB,EAAY,MAAM,MAAA,CACpB,CAKA,SAASmB,EAAc9L,EAA4C,CACjE,OAAO2K,EAAY,MAAM,IAAI3K,CAAI,CACnC,CAKA,SAAS+L,EAAc/L,EAAuB,CAC5C,OAAO2K,EAAY,MAAM,IAAI3K,CAAI,CACnC,CAKA,SAASgM,EAAUC,EAA0C,CAC3D,OAAOxB,GAAmB,KAAMa,GAAMA,EAAE,KAAOW,CAAE,CACnD,CAKA,SAASC,EACPlM,EACAmM,EACAC,EACyB,CACzB,MAAMf,EAASW,EAAUG,CAAQ,EACjC,OAAKd,EAKE,CACL,KAAArL,EACA,YAAAoM,EACA,OAAQf,EAAO,OACf,MAAOA,EAAO,MACd,KAAMA,EAAO,KACb,SAAUA,EAAO,EAAA,GAVjB9K,EAAM,MAAQ,qBAAqB4L,CAAQ,GACpC,KAWX,CAKA,SAASpD,EAAWtD,EAAwB,CAC1C8B,EAAU,MAAQ9B,CACpB,CAKA,SAASuD,EAASC,EAA4B,CAC5C1I,EAAM,MAAQ0I,EACd1B,EAAU,MAAQ,EACpB,CAKA,SAAS2B,GAAmB,CAC1B3I,EAAM,MAAQ,IAChB,CAMA,SAAS8L,EAAmBrM,EAAoB,CAC9C,GAAI,CAAC4K,EAAoB,MAAM,IAAI5K,CAAI,EACrC,OAGF,MAAM2L,EAAWf,EAAoB,MAAM,IAAI5K,CAAI,EAC/C2L,GAAa,KAEfhB,EAAY,MAAM,OAAO3K,CAAI,EAG7B2K,EAAY,MAAM,IAAI3K,EAAM2L,CAAQ,EAItCf,EAAoB,MAAM,OAAO5K,CAAI,CACvC,CAKA,SAASsM,EAAsBlM,EAA8B,CAG3D,QAAQ,IAAI,sBAAuBA,EAAK,IAAI,CAC9C,CAKA,SAASmM,EAAwBnM,EAA8B,CAC7DwL,EAAsBxL,EAAK,IAAI,EAC/B,QAAQ,IAAI,wBAAyBA,EAAK,IAAI,CAChD,CAKA,SAASoM,EAAyBpM,EAA+B,CAC/DyL,EAAA,EACA,QAAQ,IAAI,4BAA6BzL,EAAK,KAAK,CACrD,CAKA,SAASqM,EAAoBrM,EAAgD,CACvEA,EAAK,SAEPwK,EAAoB,MAAM,OAAOxK,EAAK,IAAI,EAC1C,QAAQ,IAAI,iCAAkCA,EAAK,IAAI,IAGvDiM,EAAmBjM,EAAK,IAAI,EAC5B4I,EAAS,gCAAgC5I,EAAK,IAAI,EAAE,GAEtD2I,EAAW,EAAK,CAClB,CAKA,SAAS2D,EAAwBtM,EAAgD,CAC3EA,EAAK,SAEPwK,EAAoB,MAAM,OAAOxK,EAAK,IAAI,EAC1C,QAAQ,IAAI,qCAAsCA,EAAK,IAAI,IAG3DiM,EAAmBjM,EAAK,IAAI,EAC5B4I,EAAS,kCAAkC5I,EAAK,IAAI,EAAE,GAExD2I,EAAW,EAAK,CAClB,CAMA,MAAO,CAEL,YAAA4B,EACA,UAAApD,EACA,MAAAhH,EAGA,kBAAAsK,EACA,MAAAC,EACA,QAAAC,EACA,qBAAAC,EACA,kBAAAC,EAGA,eAAAM,EACA,mBAAAE,EACA,sBAAAG,EACA,sBAAAC,EACA,cAAAC,EACA,cAAAC,EACA,UAAAC,EACA,2BAAAE,EACA,WAAAnD,EACA,SAAAC,EACA,WAAAE,EACA,mBAAAmD,EAGA,sBAAAC,EACA,wBAAAC,EACA,yBAAAC,EACA,oBAAAC,EACA,wBAAAC,CAAA,CAEJ,CAAC,ECrWYC,GAAmBvH,EAAAA,YAAY,WAAY,IAAM,CAM5D,MAAMwH,EAAUxN,EAAAA,IAAqB,EAAE,EAGjCmI,EAAYnI,EAAAA,IAAI,EAAK,EAGrBmB,EAAQnB,EAAAA,IAAmB,IAAI,EAG/BqI,EAASrI,EAAAA,IAAoB,CACjC,QAAS,CAAA,EACT,YAAa,CAAA,EACb,YAAa,GACb,cAAe,IAAA,CAChB,EAGKyN,EAAkBzN,EAAAA,IAAmB,IAAI,EAGzC0N,EAAa1N,EAAAA,IAAI,GAAG,EAGpB2N,MAAqB,IAS3B,SAASC,EAAkBC,EAAuD,CAChF,OAAIA,EAAS,IAAY,MACrBA,EAAS,IAAY,MACrBA,EAAS,IAAY,MACrBA,EAAS,IAAY,MAClB,KACT,CAKA,MAAMC,EAAkBlL,EAAAA,SAAS,IAAM,CACrC,IAAI6E,EAAS+F,EAAQ,MAGrB,GAAInF,EAAO,MAAM,YAAY,KAAA,EAAQ,CACnC,MAAMU,EAAQV,EAAO,MAAM,YAAY,YAAA,EAAc,KAAA,EACrDZ,EAASA,EAAO,OAAQsG,GAEpBA,EAAM,QAAQ,KAAK,YAAA,EAAc,SAAShF,CAAK,GAC/CgF,EAAM,QAAQ,YAAY,YAAA,EAAc,SAAShF,CAAK,CAEzD,CACH,CAGA,OAAIV,EAAO,MAAM,QAAQ,OAAS,IAChCZ,EAASA,EAAO,OAAQsG,GACtB1F,EAAO,MAAM,QAAQ,SAAS0F,EAAM,QAAQ,OAAO,YAAA,CAA2B,CAAA,GAK9E1F,EAAO,MAAM,YAAY,OAAS,IACpCZ,EAASA,EAAO,OAAQsG,GAAU,CAChC,GAAIA,EAAM,SAAW,KAAM,MAAO,GAClC,MAAMC,EAAWJ,EAAkBG,EAAM,MAAM,EAC/C,OAAO1F,EAAO,MAAM,YAAY,SAAS2F,CAAQ,CACnD,CAAC,GAIC3F,EAAO,MAAM,gBAAkB,OACjCZ,EAASA,EAAO,OAAQsG,GAAUA,EAAM,YAAc1F,EAAO,MAAM,aAAa,GAG3EZ,CACT,CAAC,EAKKwG,EAAgBrL,EAAAA,SAAS,IACxB6K,EAAgB,MACdD,EAAQ,MAAM,KAAMjE,GAAMA,EAAE,KAAOkE,EAAgB,KAAK,GAAK,KADjC,IAEpC,EAKKS,EAAatL,EAAAA,SAAS,IAAM4K,EAAQ,MAAM,MAAM,EAKhDW,EAAiBvL,EAAAA,SAAS,IAAM4K,EAAQ,MAAM,OAAQjE,GAAMA,EAAE,WAAa,IAAI,EAAE,MAAM,EAKvF6E,EAAexL,EAAAA,SAAS,IAAM4K,EAAQ,MAAM,OAAQjE,GAAMA,EAAE,WAAa,IAAI,EAAE,MAAM,EAKrF8E,EAAezL,EAAAA,SAAS,IAAM,CAClC,MAAM0L,EAAS,CACb,MAAO,EACP,MAAO,EACP,MAAO,EACP,MAAO,EACP,MAAO,CAAA,EAGT,UAAWP,KAASP,EAAQ,MAC1B,GAAIO,EAAM,SAAW,KAAM,CACzB,MAAMC,EAAWJ,EAAkBG,EAAM,MAAM,EAC/CO,EAAON,CAAQ,GACjB,CAGF,OAAOM,CACT,CAAC,EAKKC,EAAkB3L,EAAAA,SAAS,IAAM,CACrC,MAAM4L,EAAmBhB,EAAQ,MAAM,OAAQjE,GAAMA,EAAE,WAAa,IAAI,EACxE,GAAIiF,EAAiB,SAAW,EAAG,MAAO,GAE1C,MAAMC,EAAgBD,EAAiB,OAAO,CAAC5H,EAAK2C,IAAM3C,GAAO2C,EAAE,UAAY,GAAI,CAAC,EACpF,OAAO,KAAK,MAAMkF,EAAgBD,EAAiB,MAAM,CAC3D,CAAC,EASD,SAASE,EAAWC,EAAgC,CAClD,MAAMZ,EAAuB,CAC3B,GAAIY,EAAQ,GACZ,QAAAA,EACA,SAAU,KACV,OAAQ,KACR,SAAU,KACV,UAAW,EAAA,EAIPC,EAAmBjB,EAAe,IAAIgB,EAAQ,EAAE,EAClDC,IACFC,EAAcd,EAAOa,CAAgB,EAErCjB,EAAe,OAAOgB,EAAQ,EAAE,GAIlCnB,EAAQ,MAAM,QAAQO,CAAK,EAGvBP,EAAQ,MAAM,OAASE,EAAW,QACpCF,EAAQ,MAAQA,EAAQ,MAAM,MAAM,EAAGE,EAAW,KAAK,EAE3D,CAKA,SAASoB,EAAY/H,EAAkC,CACrD,MAAMgH,EAAQP,EAAQ,MAAM,KAAMjE,GAAMA,EAAE,KAAOxC,EAAS,SAAS,EACnE,GAAIgH,EAEFc,EAAcd,EAAOhH,CAAQ,EAE7B4G,EAAe,OAAO5G,EAAS,SAAS,UAGxC4G,EAAe,IAAI5G,EAAS,UAAWA,CAAQ,EAI3C4G,EAAe,KAAO,IAAK,CAC7B,MAAMoB,EAAYC,EAAgBjI,CAAQ,EAC1CyG,EAAQ,MAAM,QAAQuB,CAAS,EAC/BpB,EAAe,OAAO5G,EAAS,SAAS,EAGpCyG,EAAQ,MAAM,OAASE,EAAW,QACpCF,EAAQ,MAAQA,EAAQ,MAAM,MAAM,EAAGE,EAAW,KAAK,EAE3D,CAEJ,CAKA,SAASmB,EAAcd,EAAsBhH,EAAkC,CAC7EgH,EAAM,SAAWhH,EACjBgH,EAAM,OAAShH,EAAS,OACxBgH,EAAM,SAAWhH,EAAS,SAC1BgH,EAAM,UAAYhH,EAAS,SAC7B,CAKA,SAASiI,EAAgBjI,EAA2C,CAElE,MAAMkI,EAA+B,CACnC,GAAIlI,EAAS,UACb,OAAQ,UACR,KAAM,WACN,YAAa,UACb,UAAW,KAAK,IAAA,EAChB,QAAS,CAAA,EACT,MAAO,CAAA,EACP,KAAM,MAAA,EAGR,MAAO,CACL,GAAIA,EAAS,UACb,QAASkI,EACT,SAAAlI,EACA,OAAQA,EAAS,OACjB,SAAUA,EAAS,SACnB,UAAWA,EAAS,SAAA,CAExB,CAKA,SAASmI,EAAyBC,EAA8C,CAC9E,SAAW,CAACC,EAAWrI,CAAQ,IAAK4G,EAAgB,CAClD,MAAMI,EAAQoB,EAAW,IAAIC,CAAS,EAClCrB,GACFc,EAAcd,EAAOhH,CAAQ,EAC7B4G,EAAe,OAAOyB,CAAS,IAG/BD,EAAW,IAAIC,EAAWJ,EAAgBjI,CAAQ,CAAC,EACnD4G,EAAe,OAAOyB,CAAS,EAEnC,CACF,CAKA,SAASC,EACPF,EACAG,EACM,CACN,SAAW,CAACF,EAAWrI,CAAQ,IAAKuI,EAAmB,CACrD,MAAMvB,EAAQoB,EAAW,IAAIC,CAAS,EAClCrB,EACFc,EAAcd,EAAOhH,CAAQ,EAI7B4G,EAAe,IAAIyB,EAAWrI,CAAQ,CAE1C,CACF,CAMA,SAASwI,EAAgCJ,EAA8C,CACrF,SAAW,CAACC,EAAWrI,CAAQ,IAAK4G,EAC7BwB,EAAW,IAAIC,CAAS,IAC3BD,EAAW,IAAIC,EAAWJ,EAAgBjI,CAAQ,CAAC,EACnD4G,EAAe,OAAOyB,CAAS,EAGrC,CAMA,SAASI,EAAgBxO,EAA0B,CACjD,MAAMmO,MAAiB,IACjBG,MAAwB,IAG9B,UAAWG,KAAQzO,EAAK,QACtB,GAAIyO,EAAK,OAAS,UAAW,CAC3B,MAAMd,EAAUc,EAAK,KACrBN,EAAW,IAAIR,EAAQ,GAAI,CACzB,GAAIA,EAAQ,GACZ,QAAAA,EACA,SAAU,KACV,OAAQ,KACR,SAAU,KACV,UAAW,EAAA,CACZ,CACH,SAAWc,EAAK,OAAS,WAAY,CACnC,MAAM1I,EAAW0I,EAAK,KACtBH,EAAkB,IAAIvI,EAAS,UAAWA,CAAQ,CACpD,CAIFmI,EAAyBC,CAAU,EACnCE,EAAyBF,EAAYG,CAAiB,EAItDC,EAAgCJ,CAAU,EAG1C,MAAMO,EAAS,MAAM,KAAKP,EAAW,OAAA,CAAQ,EAAE,KAC7C,CAAC/F,EAAGC,IAAMA,EAAE,QAAQ,UAAYD,EAAE,QAAQ,SAAA,EAI5CoE,EAAQ,MAAQkC,EAAO,MAAM,EAAGhC,EAAW,KAAK,EAEhDvM,EAAM,MAAQ,IAChB,CAKA,SAASwO,GAAsB,CAC7BnC,EAAQ,MAAQ,CAAA,EAChBC,EAAgB,MAAQ,KACxBE,EAAe,MAAA,CACjB,CAKA,SAAShE,EAAWtD,EAAwB,CAC1C8B,EAAU,MAAQ9B,CACpB,CAKA,SAASuD,EAASC,EAA4B,CAC5C1I,EAAM,MAAQ0I,EACd1B,EAAU,MAAQ,EACpB,CAKA,SAAS2B,GAAmB,CAC1B3I,EAAM,MAAQ,IAChB,CAKA,SAAS4I,EAAehB,EAAqB,CAC3CV,EAAO,MAAM,YAAcU,CAC7B,CAKA,SAASiB,EAAmBC,EAA0B,CACpD,MAAM9M,EAAQkL,EAAO,MAAM,QAAQ,QAAQ4B,CAAM,EAC7C9M,IAAU,GACZkL,EAAO,MAAM,QAAQ,KAAK4B,CAAM,EAEhC5B,EAAO,MAAM,QAAQ,OAAOlL,EAAO,CAAC,CAExC,CAKA,SAASyS,EAAmB/B,EAAqD,CAC/E,MAAM1Q,EAAQkL,EAAO,MAAM,YAAY,QAAQwF,CAAM,EACjD1Q,IAAU,GACZkL,EAAO,MAAM,YAAY,KAAKwF,CAAM,EAEpCxF,EAAO,MAAM,YAAY,OAAOlL,EAAO,CAAC,CAE5C,CAKA,SAAS0S,EAAmBC,EAAiC,CAC3DzH,EAAO,MAAM,cAAgByH,CAC/B,CAKA,SAASvF,GAAqB,CAC5BlC,EAAO,MAAQ,CACb,QAAS,CAAA,EACT,YAAa,CAAA,EACb,YAAa,GACb,cAAe,IAAA,CAEnB,CAKA,SAASmC,GAA4B,CACnC,OACEnC,EAAO,MAAM,YAAY,SAAW,IACpCA,EAAO,MAAM,QAAQ,OAAS,GAC9BA,EAAO,MAAM,YAAY,OAAS,GAClCA,EAAO,MAAM,gBAAkB,IAEnC,CAKA,SAAS0H,EAAYlD,EAAyB,CAC5CY,EAAgB,MAAQZ,CAC1B,CAKA,SAASmD,EAAcC,EAAqB,CAE1C,MAAMC,EAAU,KAAK,IAAI,EAAGD,CAAK,EACjCvC,EAAW,MAAQwC,EAGf1C,EAAQ,MAAM,OAAS0C,IACzB1C,EAAQ,MAAQA,EAAQ,MAAM,MAAM,EAAG0C,CAAO,EAElD,CAMA,MAAO,CAEL,QAAA1C,EACA,UAAArF,EACA,MAAAhH,EACA,OAAAkH,EACA,gBAAAoF,EACA,WAAAC,EAGA,gBAAAI,EACA,cAAAG,EACA,WAAAC,EACA,eAAAC,EACA,aAAAC,EACA,aAAAC,EACA,gBAAAE,EAGA,WAAAG,EACA,YAAAI,EACA,gBAAAU,EACA,cAAAG,EACA,WAAAhG,EACA,SAAAC,EACA,WAAAE,EACA,eAAAC,EACA,mBAAAC,EACA,mBAAA4F,EACA,mBAAAC,EACA,aAAAtF,EACA,iBAAAC,EACA,YAAAuF,EACA,cAAAC,CAAA,CAEJ,CAAC,EC7iBKG,GAA0C,CAAC,QAAS,OAAQ,QAAQ,EAK1E,SAASC,GAAYvK,EAAoC,CACvD,OAAO,OAAOA,GAAU,UAAYsK,GAAkB,SAAStK,CAAkB,CACnF,CAKA,MAAMwK,GAAc,yBAKdC,EAAYtQ,EAAAA,IAAe,QAAQ,EACnCuQ,GAAoBvQ,EAAAA,IAAI,EAAK,EAKnC,IAAIwQ,GAA2C,KAC3CC,GAAiE,KAKrE,SAASjQ,IAAqB,CAC5B,OAAO,OAAO,OAAW,KAAe,OAAO,SAAa,GAC9D,CAMA,SAASC,IAA+B,CACtC,OAAOC,EAAAA,uBAAyB,IAClC,CAaO,SAASgQ,IAAW,CAIzB,MAAMC,EAAiB/N,EAAAA,SAA2B,IAC5C0N,EAAU,QAAU,SACfC,GAAkB,MAAQ,OAAS,QAErCD,EAAU,KAClB,EAKKM,EAAShO,EAAAA,SAAS,IAAM+N,EAAe,QAAU,MAAM,EAK7D,SAASE,GAAmB,CAC1B,GAAI,CAACrQ,KAAa,OAElB,MAAMsQ,EAAO,SAAS,gBAElBH,EAAe,QAAU,QAC3BG,EAAK,UAAU,IAAI,MAAM,EACzBA,EAAK,UAAU,OAAO,OAAO,IAE7BA,EAAK,UAAU,IAAI,OAAO,EAC1BA,EAAK,UAAU,OAAO,MAAM,EAEhC,CAKA,SAASC,EAASC,EAAuB,CACvC,GAAI,CAACZ,GAAYY,CAAI,EAAG,CACtB,QAAQ,KAAK,kCAAkCA,CAAI,EAAE,EACrD,MACF,CAIA,GAFAV,EAAU,MAAQU,EAEdxQ,KACF,GAAI,CACF,aAAa,QAAQ6P,GAAaW,CAAI,CACxC,MAAQ,CAEN,QAAQ,KAAK,+CAA+C,CAC9D,CAEJ,CAMA,SAASC,GAAoB,CACvBX,EAAU,QAAU,SAEtBS,EAASR,GAAkB,MAAQ,QAAU,MAAM,EAGnDQ,EAAST,EAAU,QAAU,OAAS,QAAU,MAAM,CAE1D,CAKA,SAASY,GAAsB,CAC7BH,EAAS,QAAQ,CACnB,CAKA,SAASI,GAA0B,CAC7BX,IAAqBC,KACvBD,GAAkB,oBAAoB,SAAUC,EAAmB,EACnED,GAAoB,KACpBC,GAAsB,KAE1B,CAKA,SAASW,GAAmB,CAC1B,GAAI,CAAC5Q,KAAa,OAGlB2Q,EAAA,EAGA,MAAME,EAAa,OAAO,WAAW,8BAA8B,EACnEd,GAAkB,MAAQc,EAAW,QAGrC,MAAMnQ,EAAWqI,GAAiC,CAChDgH,GAAkB,MAAQhH,EAAE,OAC9B,EAGA8H,EAAW,iBAAiB,SAAUnQ,CAAO,EAG7CsP,GAAoBa,EACpBZ,GAAsBvP,EAGtB,GAAI,CACF,MAAMoQ,EAAQ,aAAa,QAAQjB,EAAW,EAC1CD,GAAYkB,CAAK,IACnBhB,EAAU,MAAQgB,EAEtB,MAAQ,CAER,CAGAT,EAAA,CACF,CAMA,SAASrO,GAAmB,CAK1B,GAJA2O,EAAA,EACAb,EAAU,MAAQ,SAClBC,GAAkB,MAAQ,GAEtB/P,KAAa,CACF,SAAS,gBACjB,UAAU,OAAO,OAAQ,OAAO,EAErC,GAAI,CACF,aAAa,WAAW6P,EAAW,CACrC,MAAQ,CAER,CACF,CACF,CAGAkB,OAAAA,EAAAA,MAAM,CAACjB,EAAWC,EAAiB,EAAG,IAAM,CAC1CM,EAAA,CACF,CAAC,EAIGpQ,OAEFqC,EAAAA,UAAU,IAAM,CACdsO,EAAA,CACF,CAAC,EAGDI,EAAAA,YAAY,IAAM,CAChBL,EAAA,CACF,CAAC,GAGI,CAIL,UAAWvO,EAAAA,SAAS,IAAM0N,EAAU,KAAK,EAKzC,eAAAK,EAKA,OAAAC,EAKA,kBAAmBhO,EAAAA,SAAS,IAAM2N,GAAkB,KAAK,EAKzD,SAAAQ,EAKA,YAAAE,EAKA,cAAAC,EAKA,WAAAE,EAKA,WAAA5O,CAAA,CAEJ,CCnQA,IAAIiP,GAAiB,GACjBC,GAA0B,KAS9B,SAASC,IAAwB,CAE/B,GAAIF,GAIF,OAAOC,GAIT,MAAME,EAAMC,EAAAA,UAAUC,EAAY,EAG5BC,EAAQC,EAAAA,YAAA,EAGd,OAAAJ,EAAI,IAAIG,CAAK,EACbH,EAAI,IAAIxO,EAAM,EAMdwO,EAAI,MAAM,MAAM,EAGhBH,GAAiB,GACjBC,GAAcE,EAOPA,CACT,CAII,OAAO,OAAW,KAAe,SAAS,eAAe,KAAK,GAChED,GAAA,EClDK,SAASM,GAAehI,EAAwB,CACrD,OAAOA,EAAO,YAAA,CAChB,g+CCDA,MAAMpM,EAAQqU,EAKRC,EAAcvP,EAAAA,SAAS,IACpB/E,EAAM,UAAU,UAAYA,EAAM,SAAS,SAAS,OAAS,CACrE,EAKKuU,EAAkBxP,EAAAA,SAAS,IAC1B/E,EAAM,UAAU,SACdA,EAAM,SAAS,SAAS,IAAKwU,IAAS,CAC3C,KAAMA,EAAI,KACV,OAAQA,EAAI,OAAO,OAAS,EAAIA,EAAI,OAAO,KAAK,IAAI,EAAI,WAAA,EACxD,EAJoC,CAAA,CAKvC,gBAICpO,YAAA,EAAAC,qBAyIM,MAzINC,GAyIM,CAvIQ+N,EAAA,UASZjO,EAAAA,UAAA,EAAAC,qBA6HM,MA7HNI,GA6HM,CA3HJF,EAAAA,mBAaS,SAbTM,GAaS,CAZPN,EAAAA,mBAQO,OAAA,CAPJ,MAAKU,EAAAA,eAAA,sCAAgG,iBAAAoN,EAAA,SAAS,MAAM,EAAA,sBAMlH1N,EAAAA,MAAAyN,EAAA,EAAeC,EAAA,SAAS,MAAM,CAAA,EAAA,CAAA,EAEnC9N,EAAAA,mBAEK,KAFLkO,GAEKnN,EAAAA,gBADA+M,EAAA,SAAS,IAAI,EAAA,CAAA,CAAA,GAKpB9N,EAAAA,mBA6BM,MA7BNc,GA6BM,CA3BIgN,EAAA,SAAS,YADjBjO,EAAAA,YAAAC,EAAAA,mBAMM,MANNkB,GAMM,CAFJb,EAAAA,YAAmBC,EAAAA,MAAA9F,EAAA,EAAA,CAAZ,KAAM,GAAE,EACf+F,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAA+B,YAAzB,qBAAkB,EAAA,EAAA,gCAGlB8N,EAAA,SAAS,SADjBjO,EAAAA,YAAAC,EAAAA,mBAMM,MANNmB,GAMM,CAFJd,EAAAA,YAAqBC,EAAAA,MAAAlF,EAAA,EAAA,CAAZ,KAAM,GAAE,EACjBmF,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAA0B,YAApB,gBAAa,EAAA,EAAA,gCAGb+N,EAAA,OADRlO,EAAAA,UAAA,EAAAC,EAAAA,mBAMM,MANNoB,GAMM,CAFJf,EAAAA,YAAmBC,EAAAA,MAAAzF,EAAA,EAAA,CAAZ,KAAM,GAAE,EACf0F,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAAoC,YAA9B,0BAAuB,EAAA,EAAA,gCAGtB,CAAA8N,EAAA,SAAS,YAAU,CAAKA,EAAA,SAAS,SAD1CjO,YAAA,EAAAC,qBAMM,MANNqB,GAMM,CAFJhB,EAAAA,YAAuBC,EAAAA,MAAA3F,EAAA,EAAA,CAAZ,KAAM,GAAE,EACnB4F,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAAoC,YAA9B,0BAAuB,EAAA,EAAA,kCAKjCA,EAAAA,mBA0EM,MA1ENmO,GA0EM,CAxEJnO,EAAAA,mBAKU,UALVoO,GAKU,CAJR/N,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAAyD,KAAA,CAArD,MAAM,gCAAA,EAAiC,YAAS,EAAA,GACpDA,EAAAA,mBAEI,IAFJqO,GAEItN,EAAAA,gBADC+M,EAAA,SAAS,WAAW,EAAA,CAAA,CAAA,GAKZA,EAAA,SAAS,KAAK,OAAM,GAAnCjO,EAAAA,YAAAC,EAAAA,mBAcU,UAdVwO,GAcU,CAbRtO,EAAAA,mBAGK,KAHLuO,GAGK,CAFHpO,EAAAA,YAAkBC,EAAAA,MAAAjF,EAAA,EAAA,CAAZ,KAAM,GAAE,gCAAI,SAEpB,EAAA,EAAA,GACA6E,EAAAA,mBAQM,MARNwO,GAQM,EAPJ3O,EAAAA,UAAA,EAAA,EAAAC,EAAAA,mBAMOS,WAAA,KAAAC,EAAAA,WALSsN,EAAA,SAAS,KAAhBvJ,kBADTzE,EAAAA,mBAMO,OAAA,CAJJ,IAAKyE,EACN,MAAM,sBAAA,oBAEHA,CAAG,EAAA,CAAA,2CAMGuJ,EAAA,SAAS,SAAxBjO,EAAAA,YAAAC,EAAAA,mBAKU,UALV2O,GAKU,CAJRpO,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAAuD,KAAA,CAAnD,MAAM,gCAAA,EAAiC,UAAO,EAAA,GAClDA,EAAAA,mBAEI,IAFJ0O,GAEI3N,EAAAA,gBADC+M,EAAA,SAAS,OAAO,EAAA,CAAA,CAAA,gCAKRA,EAAA,SAAS,aAAxBjO,EAAAA,YAAAC,EAAAA,mBAKU,UALV6O,GAKU,CAJRtO,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAA2D,KAAA,CAAvD,MAAM,gCAAA,EAAiC,cAAW,EAAA,GACtDA,EAAAA,mBAEI,IAFJ4O,GAEI7N,EAAAA,gBADC+M,EAAA,SAAS,WAAW,EAAA,CAAA,CAAA,gCAKZA,EAAA,SAAS,gBAAxBjO,EAAAA,YAAAC,EAAAA,mBAQU,UARV+O,GAQU,CAPR7O,EAAAA,mBAGK,KAHL8O,GAGK,CAFH3O,EAAAA,YAAuBC,EAAAA,MAAA3F,EAAA,EAAA,CAAZ,KAAM,GAAE,kCAAI,oBAEzB,EAAA,EAAA,GACAuF,EAAAA,mBAEI,IAFJ+O,GAEIhO,EAAAA,gBADC+M,EAAA,SAAS,cAAc,EAAA,CAAA,CAAA,gCAKfC,EAAA,OAAflO,EAAAA,UAAA,EAAAC,EAAAA,mBAmBU,UAnBVkP,GAmBU,CAlBRhP,EAAAA,mBAGK,KAHLiP,GAGK,CAFH9O,EAAAA,YAAqBC,EAAAA,MAAAnF,EAAA,EAAA,CAAZ,KAAM,GAAE,kCAAI,aAEvB,EAAA,EAAA,GACA+E,EAAAA,mBAaM,MAbNkP,GAaM,kBAZJpP,EAAAA,mBAWMS,EAAAA,SAAA,KAAAC,EAAAA,WAVUwN,EAAA,MAAPC,kBADTnO,EAAAA,mBAWM,MAAA,CATH,IAAKmO,EAAI,KACV,MAAM,gCAAA,GAENjO,EAAAA,mBAEO,OAFPmP,GAEOpO,EAAAA,gBADFkN,EAAI,IAAI,EAAA,CAAA,EAEbjO,EAAAA,mBAEO,OAFPoP,GAEOrO,EAAAA,gBADFkN,EAAI,MAAM,EAAA,CAAA,CAAA,kDAhIzBpO,EAAAA,YAAAC,EAAAA,mBAMM,MANNG,GAMM,CALJE,cAA2DC,EAAAA,MAAA3F,EAAA,EAAA,CAAhD,KAAM,GAAI,MAAM,6BAAA,GAC3B4F,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAAkE,KAAA,CAA9D,MAAM,8BAAA,EAA+B,uBAAoB,EAAA,GAC7DK,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAEI,IAAA,CAFD,MAAM,0CAAyC,yDAElD,EAAA,EAAA,0uBC5BN,MAAMvG,EAAQqU,EAKRuB,EAAOC,EAUb,SAASC,EAAoBjL,EAA+B,CAC1D+K,EAAK,SAAU/K,EAAS,GAAG,CAC7B,CAKA,SAASkL,EAAkBjL,EAAmB,CAC5C8K,EAAK,eAAgB9K,CAAG,CAC1B,CAKA,SAASkL,EAAWnL,EAAkC,CACpD,OAAO7K,EAAM,cAAgB6K,EAAS,GACxC,eAIEzE,YAAA,EAAAC,qBAuFM,MAvFNC,GAuFM,CArFO+N,EAAA,OAAO,SAAM,GAAxBjO,EAAAA,UAAA,EAAAC,EAAAA,mBAEM,MAFNG,GAEM,CAAA,GAAAI,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAA,CADJL,EAAAA,mBAA4C,IAAA,CAAzC,MAAM,YAAA,EAAa,qBAAkB,EAAA,CAAA,OAI1CH,EAAAA,YAAAC,EAAAA,mBA+EM,MA/ENI,GA+EM,kBA9EJJ,EAAAA,mBA6EMS,EAAAA,SAAA,KAAAC,EAAAA,WA5EYsN,EAAA,OAATrH,kBADT3G,EAAAA,mBA6EM,MAAA,CA3EH,IAAK2G,EAAM,IACZ,MAAM,gBAAA,GAGNzG,EAAAA,mBAgBS,SAAA,CAfP,KAAK,SACL,MAAM,yBACL,gBAAeyG,EAAM,WACrB,gBAAa,SAAWA,EAAM,GAAG,GACjC,QAAK9F,GAAE6O,EAAkB/I,EAAM,GAAG,CAAA,IAEnC5G,EAAAA,YAAAe,EAAAA,YAIEC,EAAAA,wBAHK4F,EAAM,WAAarG,EAAAA,MAAApG,CAAA,EAAcoG,QAAAnG,EAAA,CAAY,EAAA,CACjD,KAAM,GACP,MAAM,yBAAA,IAER+F,EAAAA,mBAAwD,OAAxDkO,GAAwDnN,EAAAA,gBAAnB0F,EAAM,GAAG,EAAA,CAAA,EAC9CzG,qBAEO,OAFPc,GAA+C,KAC5CC,EAAAA,gBAAG0F,EAAM,UAAU,MAAM,EAAG,KAC/B,CAAA,CAAA,yBAIFzG,EAAAA,mBAmDM,MAAA,CAjDH,GAAE,SAAWyG,EAAM,GAAG,GACvB,MAAM,wBACN,KAAK,QACJ,aAAU,GAAKA,EAAM,GAAG,YAAA,IAEzB5G,YAAA,EAAA,EAAAC,EAAAA,mBA2CSS,EAAAA,SAAA,KAAAC,EAAAA,WA1CYiG,EAAM,UAAlBnC,kBADTxE,EAAAA,mBA2CS,SAAA,CAzCN,IAAKwE,EAAS,IACf,KAAK,SACJ,MAAK5D,EAAAA,eAAA,iBAA8E,CAAA,0BAAA+O,EAAWnL,CAAQ,CAAA,CAAA,GAItG,gBAAemL,EAAWnL,CAAQ,EAClC,QAAK3D,GAAE4O,EAAoBjL,CAAQ,CAAA,GAGpCtE,EAAAA,mBAOO,OAAA,CANJ,MAAKU,EAAAA,eAAA,gBAAqE,iBAAA4D,EAAS,MAAM,EAAA,sBAKvFlE,EAAAA,MAAAyN,EAAA,EAAevJ,EAAS,MAAM,CAAA,EAAA,CAAA,EAInCtE,EAAAA,mBAEO,OAFPkB,GAEOH,EAAAA,gBADFuD,EAAS,IAAI,EAAA,CAAA,EAIlBtE,EAAAA,mBAeM,MAfNmB,GAeM,CAbImD,EAAS,YADjBzE,EAAAA,UAAA,EAAAC,EAAAA,mBAMO,OANPqO,GAMO,CADLhO,EAAAA,YAAmBC,EAAAA,MAAA9F,EAAA,EAAA,CAAZ,KAAM,GAAE,CAAA,gCAGTgK,EAAS,SADjBzE,EAAAA,UAAA,EAAAC,EAAAA,mBAMO,OANPsO,GAMO,CADLjO,EAAAA,YAAqBC,EAAAA,MAAAlF,EAAA,EAAA,CAAZ,KAAM,GAAE,CAAA,0DA9Cf,CAAAwU,EAAAA,MAAAjJ,EAAM,UAAU,CAAA,66BC3ElC,MAAMkJ,EAAgB/L,GAAA,EAChB,CAAE,KAAAhG,EAAM,GAAAE,EAAI,UAAAS,CAAA,EAAcF,GAAA,EAG1BuR,EAAchU,EAAAA,IAAI,EAAK,EACvBiU,EAAiBjU,EAAAA,IAA6B,IAAI,EAGlDkU,EAA4B,CAChC,MACA,OACA,MACA,QACA,SACA,UACA,OACA,OAAA,EAMF,SAASC,GAAsB,CACzBxR,EAAU,QACZoR,EAAc,WAAW,EAAI,EAC7B/R,EAAK,CAAE,KAAM,eAAgB,EAEjC,CAKA,SAASoS,EAAmBpT,EAA0B,CACpD+S,EAAc,gBAAgB/S,CAAI,EAClC+S,EAAc,WAAW,EAAK,CAChC,CAKA,SAASM,EAAqB3J,EAAmB,CAC/CqJ,EAAc,eAAerJ,CAAG,CAClC,CAKA,SAAS4J,EAAkB3L,EAAmB,CAC5CoL,EAAc,YAAYpL,CAAG,CAC/B,CAKA,SAAS4L,EAAkBhT,EAAoB,CAC7C,MAAMiT,EAASjT,EAAM,OACrBwS,EAAc,eAAeS,EAAO,KAAK,CAC3C,CAKA,SAASC,GAAoB,CAC3BV,EAAc,eAAe,EAAE,EAC/BE,EAAe,OAAO,MAAA,CACxB,CAKA,SAASS,EAAazK,EAA0B,CAC9C8J,EAAc,mBAAmB9J,CAAM,CACzC,CAKA,SAAS0K,EAAe1K,EAA6B,CACnD,OAAO8J,EAAc,OAAO,QAAQ,SAAS9J,CAAM,CACrD,CAKA,SAAS2K,GAA4B,CACnC,MAAMC,EAAUd,EAAc,OAAO,WACrCA,EAAc,iBAAiBc,IAAY,GAAO,KAAO,EAAI,CAC/D,CAKA,SAASC,GAAyB,CAChC,MAAMD,EAAUd,EAAc,OAAO,QACrCA,EAAc,cAAcc,IAAY,GAAO,KAAO,EAAI,CAC5D,CAKA,SAASE,GAAwB,CAC/BhB,EAAc,aAAA,CAChB,CAKA,SAASiB,GAAsB,CAC7BhB,EAAY,MAAQ,CAACA,EAAY,KACnC,CAKA,MAAMxJ,EAAmB5H,EAAAA,SAAS,IAAMmR,EAAc,kBAAkB,EAGxE,IAAIkB,EAAqC,KACrCC,EAAqC,KACrCC,EAAkC,KAGtCrS,OAAAA,EAAAA,UAAU,IAAM,CAEdmS,EAAgB/S,EAAiB,WAAYkS,CAAkB,EAC/Dc,EAAgBhT,EAAG,mBAAoB,IAAMiS,EAAA,CAAe,EAC5DgB,EAAajT,EAAG,gBAAiB,IAAMiS,EAAA,CAAe,EAGlDxR,EAAU,OACZwR,EAAA,CAEJ,CAAC,EAGD3C,EAAAA,YAAY,IAAM,CAChByD,IAAA,EACAC,IAAA,EACAC,IAAA,CACF,CAAC,EAGD5D,QAAM5O,EAAYqB,GAAgB,CAC5BA,GACFmQ,EAAA,CAEJ,CAAC,UAIClQ,YAAA,EAAAC,qBAqLM,MArLNC,GAqLM,CAnLJC,EAAAA,mBAqDM,MArDNC,GAqDM,CAnDJD,EAAAA,mBAmBM,MAnBNE,GAmBM,CAlBJC,cAAiDC,EAAAA,MAAApF,EAAA,EAAA,CAAxC,KAAM,GAAI,MAAM,qBAAA,GACzBgF,EAAAA,mBAOE,QAAA,SANI,iBAAJ,IAAI6P,EACJ,KAAK,OACL,MAAM,6BACN,YAAY,sBACX,MAAOzP,EAAAA,MAAAuP,CAAA,EAAc,YACrB,QAAOQ,CAAA,cAGF/P,EAAAA,MAAAuP,CAAA,EAAc,2BADtB7P,EAAAA,mBAQS,SAAA,OANP,KAAK,SACL,MAAM,gDACN,MAAM,eACL,QAAOuQ,CAAA,GAERlQ,EAAAA,YAAgBC,EAAAA,MAAA5E,EAAA,EAAA,CAAZ,KAAM,GAAE,CAAA,kCAKhBwE,EAAAA,mBAiBS,SAAA,CAhBP,KAAK,SACJ,MAAKU,EAAAA,eAAA,2EAAqG0F,EAAA,KAAA,CAAgB,GAI1H,gBAAewJ,EAAA,MACf,QAAOgB,CAAA,GAERzQ,EAAAA,YAAqBC,EAAAA,MAAA4Q,EAAA,EAAA,CAAZ,KAAM,GAAE,EACjB3Q,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,qBAAoB,YAAd,UAAO,EAAA,GACDoG,EAAA,qBAAZtG,EAAAA,mBAIO,OAJPgB,GAIOC,EAAAA,gBAHFX,EAAAA,MAAAuP,CAAA,EAAc,OAAO,QAAQ,QAAsBvP,EAAAA,MAAAuP,CAAA,EAAc,OAAO,WAAU,EAAA,IAAyBvP,EAAAA,MAAAuP,CAAA,EAAc,OAAO,QAAO,EAAA,EAAA,EAAA,CAAA,8CAI5I/O,EAAAA,YAAoEC,EAAAA,wBAApD+O,QAAcxP,EAAAA,MAAAlG,EAAA,EAAYkG,EAAAA,MAAApG,CAAA,CAAW,EAAA,CAAG,KAAM,GAAE,EAAA,SAIlEgG,EAAAA,mBAQM,MARNgB,GAQM,CAPJhB,EAAAA,mBAEO,OAFPiB,GAEOF,EAAAA,gBADFX,EAAAA,MAAAuP,CAAA,EAAc,kBAAkB,MAAM,EAAG,cAC9C,CAAA,EACAtP,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAA8C,OAAA,CAAxC,MAAM,yBAAA,EAA0B,IAAC,EAAA,GACvCA,EAAAA,mBAEO,OAFPkB,GAEOH,EAAAA,gBADFX,EAAAA,MAAAuP,CAAA,EAAc,QAAQ,MAAM,EAAG,SACpC,CAAA,CAAA,KAKOC,EAAA,OAAX/P,EAAAA,UAAA,EAAAC,EAAAA,mBA6DM,MA7DNqB,GA6DM,CA3DJnB,EAAAA,mBAiBM,MAjBNmO,GAiBM,CAhBJ9N,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAA8C,KAAA,CAA1C,MAAM,uBAAA,EAAwB,UAAO,EAAA,GACzCA,EAAAA,mBAcM,MAdNoO,GAcM,gBAbJtO,EAAAA,mBAYSS,EAAAA,SAAA,KAAAC,aAXUsP,EAAVjK,GADT7F,EAAAA,mBAYS,SAAA,CAVN,IAAK6F,EACN,KAAK,SACJ,MAAKnF,EAAAA,eAAA,iCAAiEmF,CAAM,8BAA+C0K,EAAe1K,CAAM,GAAKzF,EAAAA,MAAAuP,CAAA,EAAc,OAAO,QAAQ,OAAM,CAAA,CAAA,GAKxL,QAAKhP,GAAE2P,EAAazK,CAAM,CAAA,EAExB9E,EAAAA,gBAAA8E,EAAO,aAAW,EAAA,GAAAwI,EAAA,YAM3BrO,EAAAA,mBA0BM,MA1BNsO,GA0BM,CAzBJjO,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAA6C,KAAA,CAAzC,MAAM,uBAAA,EAAwB,SAAM,EAAA,GACxCA,EAAAA,mBAuBM,MAvBNuO,GAuBM,CAtBJvO,EAAAA,mBAUS,SAAA,CATP,KAAK,SACJ,MAAKU,EAAAA,eAAA,oEAAsGN,EAAAA,MAAAuP,CAAA,EAAc,OAAO,UAAA,CAAU,GAI1I,QAAOa,CAAA,GAERrQ,EAAAA,YAAmBC,EAAAA,MAAA9F,EAAA,EAAA,CAAZ,KAAM,GAAE,EACf+F,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAAwB,YAAlB,cAAW,EAAA,EAAA,KAEnBA,EAAAA,mBAUS,SAAA,CATP,KAAK,SACJ,MAAKU,EAAAA,eAAA,oEAAsGN,EAAAA,MAAAuP,CAAA,EAAc,OAAO,OAAA,CAAO,GAIvI,QAAOe,CAAA,GAERvQ,EAAAA,YAAqBC,EAAAA,MAAAlF,EAAA,EAAA,CAAZ,KAAM,GAAE,EACjBmF,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAAqB,YAAf,WAAQ,EAAA,EAAA,SAMToG,EAAA,OAAXvG,EAAAA,UAAA,EAAAC,EAAAA,mBASM,MATN0O,GASM,CARJxO,EAAAA,mBAOS,SAAA,CANP,KAAK,SACL,MAAM,iBACL,QAAO2Q,CAAA,GAERxQ,EAAAA,YAAgBC,EAAAA,MAAA5E,EAAA,EAAA,CAAZ,KAAM,GAAE,gCAAI,sBAElB,EAAA,EAAA,iEAKJwE,EAAAA,mBA0DM,MA1DNyO,GA0DM,CAxDOrO,EAAAA,MAAAuP,CAAA,EAAc,WAAzB9P,EAAAA,UAAA,EAAAC,EAAAA,mBAGM,MAHN4O,GAGM,CAAA,GAAArO,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAA,CAFJL,EAAAA,mBAAuC,MAAA,CAAlC,MAAM,yBAAA,EAAyB,KAAA,EAAA,EACpCA,EAAAA,mBAAoD,OAAA,CAA9C,MAAM,YAAA,EAAa,uBAAoB,EAAA,CAAA,MAI/BI,EAAAA,MAAAuP,CAAA,EAAc,OAA9B9P,EAAAA,YAAAC,EAAAA,mBAKM,MALN6O,GAKM,CAJJ3O,qBAA8D,IAA9D4O,GAA8D7N,EAAAA,gBAA1BX,EAAAA,MAAAuP,CAAA,EAAc,KAAK,EAAA,CAAA,EACvD3P,EAAAA,mBAES,SAAA,CAFD,KAAK,SAAS,MAAM,mBAAoB,QAAO+P,CAAA,EAAe,SAEtE,CAAA,IAIc3P,EAAAA,MAAAuP,CAAA,EAAc,UAAU,SAAM,GAA9C9P,YAAA,EAAAC,qBAMM,MANN+O,GAMM,CALJ1O,cAA8CC,EAAAA,MAAAtF,EAAA,EAAA,CAAtC,KAAM,GAAI,MAAM,mBAAA,GACxBuF,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAAsD,KAAA,CAAlD,MAAM,oBAAA,EAAqB,qBAAkB,EAAA,GACjDK,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAEI,IAAA,CAFD,MAAM,4BAA2B,2EAEpC,EAAA,EAAA,IAIcI,EAAAA,MAAAuP,CAAA,EAAc,kBAAkB,SAAM,GAAtD9P,YAAA,EAAAC,qBAcM,MAdNgP,GAcM,CAbJ3O,cAA+CC,EAAAA,MAAApF,EAAA,EAAA,CAAtC,KAAM,GAAI,MAAM,mBAAA,GACzBqF,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAAL,EAAAA,mBAAyD,KAAA,CAArD,MAAM,oBAAA,EAAqB,wBAAqB,EAAA,GACpDK,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAAL,EAAAA,mBAEI,IAAA,CAFD,MAAM,0BAAA,EAA2B,0CAEpC,EAAA,GAEQoG,EAAA,qBADRtG,EAAAA,mBAOS,SAAA,OALP,KAAK,SACL,MAAM,qBACL,QAAO6Q,CAAA,EACT,iBAED,iDAIF7Q,EAAAA,mBAeWS,EAAAA,SAAA,CAAA,IAAA,GAAA,CAbTP,EAAAA,mBAOM,MAPN+O,GAOM,CANJ5O,EAAAA,YAKE8Q,GAAA,CAJC,OAAQ7Q,EAAAA,MAAAuP,CAAA,EAAc,iBACtB,eAAcvP,EAAAA,MAAAuP,CAAA,EAAc,oBAC5B,SAAQM,EACR,cAAcC,CAAA,sCAKnBlQ,EAAAA,mBAEM,MAFNgP,GAEM,CADJ7O,EAAAA,YAA6D+Q,GAAA,CAA5C,SAAU9Q,EAAAA,MAAAuP,CAAA,EAAc,gBAAA,43EChUnD,MAAMlW,EAAQqU,EAKRqD,EAAmBvV,EAAAA,IAAI,CAC3B,eAAgB,GAChB,aAAc,GACd,YAAa,GACb,gBAAiB,GACjB,aAAc,EAAA,CACf,EAKKwV,EAAcxV,EAAAA,IAAmB,IAAI,EAKrCyV,EAAqB7S,EAAAA,SAAS,IAC7B/E,EAAM,MACE,IAAI,KAAKA,EAAM,MAAM,QAAQ,SAAS,EACvC,eAAe,QAAS,CAClC,KAAM,UACN,MAAO,QACP,IAAK,UACL,KAAM,UACN,OAAQ,UACR,OAAQ,UACR,uBAAwB,EACxB,OAAQ,EAAA,CACT,EAXwB,EAY1B,EAKK6X,EAAoB9S,EAAAA,SAAS,IAC7B/E,EAAM,OAAO,UAAY,KAAa,aACtCA,EAAM,MAAM,SAAW,IAClB,GAAGA,EAAM,MAAM,QAAQ,KAEzB,IAAIA,EAAM,MAAM,SAAW,KAAM,QAAQ,CAAC,CAAC,GACnD,EAKK8X,EAAc/S,EAAAA,SAAS,IACtB/E,EAAM,OAAO,OACdA,EAAM,MAAM,OAAS,IAAY,oBACjCA,EAAM,MAAM,OAAS,IAAY,oBACjCA,EAAM,MAAM,OAAS,IAAY,oBACjCA,EAAM,MAAM,OAAS,IAAY,oBAC9B,oBAL0B,uBAMlC,EAKK+X,EAAiBhT,EAAAA,SAAS,IACzB/E,EAAM,OAAO,QAAQ,MACnB,OAAO,KAAKA,EAAM,MAAM,QAAQ,KAAK,EAAE,OAAS,EADf,EAEzC,EAKKgY,EAAoBjT,EAAAA,SAAS,IAC5B/E,EAAM,OAAO,QAAQ,QACnB,OAAO,KAAKA,EAAM,MAAM,QAAQ,OAAO,EAAE,OAAS,EADf,EAE3C,EAKKiY,EAAiBlT,EAAAA,SAAS,IACvB/E,EAAM,OAAO,QAAQ,OAAS,QAAaA,EAAM,OAAO,QAAQ,OAAS,IACjF,EAKKkY,EAAqBnT,EAAAA,SAAS,IAC7B/E,EAAM,OAAO,UAAU,QACrB,OAAO,KAAKA,EAAM,MAAM,SAAS,OAAO,EAAE,OAAS,EADd,EAE7C,EAKKmY,EAAkBpT,EAAAA,SAAS,IACxB/E,EAAM,OAAO,UAAU,OAAS,QAAaA,EAAM,OAAO,UAAU,OAAS,IACrF,EAKD,SAASoY,EAAWpQ,EAAwB,CAC1C,GAAI,CACF,OAAO,KAAK,UAAUA,EAAO,KAAM,CAAC,CACtC,MAAQ,CACN,OAAO,OAAOA,CAAK,CACrB,CACF,CAKA,SAASqQ,EAAcC,EAAoD,CACzEZ,EAAiB,MAAMY,CAAO,EAAI,CAACZ,EAAiB,MAAMY,CAAO,CACnE,CAKA,eAAeC,EAAgBC,EAAcC,EAAgC,CAC3E,GAAI,CACF,MAAM,UAAU,UAAU,UAAUD,CAAI,EACxCb,EAAY,MAAQc,EACpB,WAAW,IAAM,CACfd,EAAY,MAAQ,IACtB,EAAG,GAAI,CACT,OAASxO,EAAK,CACZ,QAAQ,MAAM,kBAAmBA,CAAG,CACtC,CACF,CAKA,eAAeuP,GAA+B,CAC5C,GAAI,CAAC1Y,EAAM,MAAO,OAClB,MAAMmD,EAAO,CACX,QAASnD,EAAM,MAAM,QACrB,SAAUA,EAAM,MAAM,QAAA,EAExB,MAAMuY,EAAgB,KAAK,UAAUpV,EAAM,KAAM,CAAC,EAAG,MAAM,CAC7D,eAIEiD,YAAA,EAAAC,qBA4PM,MA5PNC,GA4PM,CA1PQ+N,EAAA,OASZjO,EAAAA,UAAA,EAAAC,qBAgPM,MAhPNI,GAgPM,CA9OJF,EAAAA,mBAoCM,MApCNM,GAoCM,CAnCJN,EAAAA,mBAKM,MALNkO,GAKM,CAJJlO,EAAAA,mBAEO,OAAA,CAFA,wDAAyC8N,EAAA,MAAM,QAAQ,OAAO,YAAA,CAAW,EAAA,CAAA,CAAA,EAC3E/M,EAAAA,gBAAAX,QAAAyN,EAAA,EAAeC,EAAA,MAAM,QAAQ,MAAM,CAAA,EAAA,CAAA,EAExC9N,qBAA6E,OAA7Ec,GAA6EC,EAAAA,gBAA5B+M,QAAM,QAAQ,IAAI,EAAA,CAAA,CAAA,GAGrE9N,EAAAA,mBAeM,MAfNgB,GAeM,CAdQ8M,EAAA,MAAM,SAAM,oBAAxBhO,EAAAA,mBAEO,OAAA,OAF6B,uCAAwByR,EAAA,KAAW,CAAA,CAAA,EAClExQ,EAAAA,gBAAA+M,EAAA,MAAM,MAAM,EAAA,CAAA,kBAEjBhO,EAAAA,mBAAsE,OAAtEmB,GAAwD,SAAO,GAE/DjB,EAAAA,mBAGO,OAHPkB,GAGO,CAFLf,EAAAA,YAAoBC,EAAAA,MAAA/F,CAAA,EAAA,CAAZ,KAAM,GAAE,EAAI+X,EAAAA,gBAAA,sBACjBd,EAAA,KAAiB,EAAA,CAAA,CAAA,GAGVxD,EAAA,MAAM,WAAlBjO,EAAAA,YAAAC,EAAAA,mBAGO,OAHPqB,GAGO,CAFLhB,EAAAA,YAAkBC,EAAAA,MAAA3E,EAAA,EAAA,CAAZ,KAAM,GAAE,gCAAI,cAEpB,EAAA,EAAA,kCAGFuE,EAAAA,mBAUM,MAVNmO,GAUM,CATJnO,EAAAA,mBAQS,SAAA,CAPP,KAAK,SACL,MAAM,yBACN,MAAM,eACL,QAAOmS,CAAA,kBAERvR,EAAAA,YAAoEC,EAAAA,wBAApDuQ,UAAW,OAAchR,EAAAA,MAAArG,EAAA,EAAQqG,EAAAA,MAAA7F,EAAA,CAAI,EAAA,CAAG,KAAM,GAAE,GAAI6X,kBAAA,sBACjEhB,EAAA,QAAW,OAAA,UAAA,WAAA,EAAA,CAAA,CAAA,OAMpBpR,EAAAA,mBAaM,MAbNoO,GAaM,CAZJpO,EAAAA,mBAGM,MAHNqO,GAGM,CAFJhO,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAAL,EAAAA,mBAA0D,OAAA,CAApD,MAAM,6BAAA,EAA8B,YAAS,EAAA,GACnDA,EAAAA,mBAAmF,OAAnFsO,GAAmFvN,EAAAA,gBAA5BsQ,EAAA,KAAkB,EAAA,CAAA,CAAA,GAE3ErR,EAAAA,mBAGM,MAHNuO,GAGM,CAFJlO,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAAL,EAAAA,mBAA6D,OAAA,CAAvD,MAAM,6BAAA,EAA8B,eAAY,EAAA,GACtDA,qBAA0F,OAA1FwO,GAA0FzN,EAAAA,gBAAnC+M,QAAM,QAAQ,WAAW,EAAA,CAAA,CAAA,GAElF9N,EAAAA,mBAGM,MAHNyO,GAGM,CAFJpO,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAAL,EAAAA,mBAA2D,OAAA,CAArD,MAAM,6BAAA,EAA8B,aAAU,EAAA,GACpDA,EAAAA,mBAAyE,OAAzE0O,GAAyE3N,EAAAA,gBAAlB+M,EAAA,MAAM,EAAE,EAAA,CAAA,CAAA,KAKnE9N,EAAAA,mBAsGM,MAtGN2O,GAsGM,CArGJtO,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAAL,EAAAA,mBAAuD,KAAA,CAAnD,MAAM,gCAAA,EAAiC,UAAO,EAAA,GAGvCwR,EAAA,OAAX3R,EAAAA,UAAA,EAAAC,EAAAA,mBA+BM,MA/BN8O,GA+BM,CA9BJ5O,EAAAA,mBAaS,SAAA,CAZP,KAAK,SACL,MAAM,qCACL,gBAAemR,EAAA,MAAiB,aACjC,gBAAc,qBACb,uBAAOW,EAAa,cAAA,EAAA,kBAErBlR,EAAAA,YAGEC,EAAAA,wBAFKsQ,EAAA,MAAiB,aAAe/Q,EAAAA,MAAApG,CAAA,EAAcoG,EAAAA,MAAAnG,EAAA,CAAY,EAAA,CAC9D,KAAM,GAAE,GAEXoG,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAAL,qBAA6B,YAAvB,mBAAgB,EAAA,GACtBA,EAAAA,mBAA+E,OAA/E8O,GAAyB,IAAC/N,EAAAA,gBAAG,OAAO,KAAK+M,EAAA,MAAM,QAAQ,KAAK,EAAE,MAAM,EAAG,IAAC,CAAA,CAAA,QAE1EuE,iBAAArS,EAAAA,mBAeM,MAfN+O,GAeM,kBAVJjP,qBASMS,EAAAA,SAAA,KAAAC,EAAAA,WARmBsN,QAAM,QAAQ,MAAK,CAAlCrM,EAAO6E,mBADjBxG,EAAAA,mBASM,MAAA,CAPH,IAAAwG,EACD,MAAM,yBAAA,GAENtG,EAAAA,mBAAgE,OAAhEgP,GAAgEjO,EAAAA,gBAAbuF,CAAG,EAAA,CAAA,EACtDtG,EAAAA,mBAEO,OAFPiP,GAEOlO,EAAAA,gBADF,MAAM,QAAQU,CAAK,EAAIA,EAAM,WAAaA,CAAK,EAAA,CAAA,CAAA,kBAV9C,CAAAiO,EAAAA,MAAAyB,EAAA,MAAiB,YAAY,CAAA,kCAiB9BM,EAAA,OAAX5R,EAAAA,UAAA,EAAAC,EAAAA,mBA6BM,MA7BNoP,GA6BM,CA5BJlP,EAAAA,mBAaS,SAAA,CAZP,KAAK,SACL,MAAM,qCACL,gBAAemR,EAAA,MAAiB,eACjC,gBAAc,uBACb,uBAAOW,EAAa,gBAAA,EAAA,kBAErBlR,EAAAA,YAGEC,EAAAA,wBAFKsQ,EAAA,MAAiB,eAAiB/Q,EAAAA,MAAApG,CAAA,EAAcoG,EAAAA,MAAAnG,EAAA,CAAY,EAAA,CAChE,KAAM,GAAE,GAEXoG,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAAL,qBAAoB,YAAd,UAAO,EAAA,GACbA,EAAAA,mBAAiF,OAAjFoP,GAAyB,IAACrO,EAAAA,gBAAG,OAAO,KAAK+M,EAAA,MAAM,QAAQ,OAAO,EAAE,MAAM,EAAG,IAAC,CAAA,CAAA,QAE5EuE,iBAAArS,EAAAA,mBAaM,MAbNsS,GAaM,kBARJxS,qBAOMS,EAAAA,SAAA,KAAAC,EAAAA,WANmBsN,QAAM,QAAQ,QAAO,CAApCrM,EAAO6E,mBADjBxG,EAAAA,mBAOM,MAAA,CALH,IAAAwG,EACD,MAAM,yBAAA,GAENtG,EAAAA,mBAAgE,OAAhEuS,GAAgExR,EAAAA,gBAAbuF,CAAG,EAAA,CAAA,EACtDtG,EAAAA,mBAAoE,OAApEwS,GAAoEzR,EAAAA,gBAAfU,CAAK,EAAA,CAAA,CAAA,kBATpD,CAAAiO,EAAAA,MAAAyB,EAAA,MAAiB,cAAc,CAAA,kCAehCO,EAAA,OAAX7R,EAAAA,UAAA,EAAAC,EAAAA,mBA+BM,MA/BN2S,GA+BM,CA9BJzS,EAAAA,mBAsBM,MAtBN0S,GAsBM,CArBJ1S,EAAAA,mBAYS,SAAA,CAXP,KAAK,SACL,MAAM,qCACL,gBAAemR,EAAA,MAAiB,YACjC,gBAAc,oBACb,uBAAOW,EAAa,aAAA,EAAA,kBAErBlR,EAAAA,YAGEC,EAAAA,wBAFKsQ,EAAA,MAAiB,YAAc/Q,EAAAA,MAAApG,CAAA,EAAcoG,EAAAA,MAAAnG,EAAA,CAAY,EAAA,CAC7D,KAAM,GAAE,GAEXoG,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAAL,EAAAA,mBAAiB,YAAX,OAAI,EAAA,EAAA,QAEZA,EAAAA,mBAOS,SAAA,CANP,KAAK,SACL,MAAM,mCACN,MAAM,YACL,QAAKK,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAsS,EAAAA,cAAAhS,GAAOqR,EAAgBH,EAAW/D,EAAA,MAAM,QAAQ,IAAI,EAAA,SAAA,EAAA,CAAA,MAAA,CAAA,EAAA,kBAE1DlN,EAAAA,YAAuEC,EAAAA,wBAAvDuQ,UAAW,UAAiBhR,EAAAA,MAAArG,EAAA,EAAQqG,EAAAA,MAAA7F,EAAA,CAAI,EAAA,CAAG,KAAM,GAAE,EAAA,KAGvE8X,iBAAArS,EAAAA,mBAMM,MANN4S,GAMM,CADJ5S,EAAAA,mBAA6E,MAA7E6S,GAA6E9R,EAAAA,gBAAvC8Q,EAAW/D,EAAA,MAAM,QAAQ,IAAI,CAAA,EAAA,CAAA,CAAA,QAH3D,CAAA4B,EAAAA,MAAAyB,EAAA,MAAiB,WAAW,CAAA,oCAS/BrD,EAAA,MAAM,UAAjBjO,EAAAA,YAAAC,EAAAA,mBAoEM,MApENgT,GAoEM,CAnEJzS,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAAL,EAAAA,mBAAwD,KAAA,CAApD,MAAM,gCAAA,EAAiC,WAAQ,EAAA,GAGxC2R,EAAA,OAAX9R,EAAAA,UAAA,EAAAC,EAAAA,mBA6BM,MA7BNiT,GA6BM,CA5BJ/S,EAAAA,mBAaS,SAAA,CAZP,KAAK,SACL,MAAM,qCACL,gBAAemR,EAAA,MAAiB,gBACjC,gBAAc,wBACb,uBAAOW,EAAa,iBAAA,EAAA,kBAErBlR,EAAAA,YAGEC,EAAAA,wBAFKsQ,EAAA,MAAiB,gBAAkB/Q,EAAAA,MAAApG,CAAA,EAAcoG,EAAAA,MAAAnG,EAAA,CAAY,EAAA,CACjE,KAAM,GAAE,GAEXoG,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAAL,qBAAoB,YAAd,UAAO,EAAA,GACbA,EAAAA,mBAAkF,OAAlFgT,GAAyB,IAACjS,EAAAA,gBAAG,OAAO,KAAK+M,EAAA,MAAM,SAAS,OAAO,EAAE,MAAM,EAAG,IAAC,CAAA,CAAA,QAE7EuE,iBAAArS,EAAAA,mBAaM,MAbNiT,GAaM,kBARJnT,qBAOMS,EAAAA,SAAA,KAAAC,EAAAA,WANmBsN,QAAM,SAAS,QAAO,CAArCrM,EAAO6E,mBADjBxG,EAAAA,mBAOM,MAAA,CALH,IAAAwG,EACD,MAAM,yBAAA,GAENtG,EAAAA,mBAAgE,OAAhEkT,GAAgEnS,EAAAA,gBAAbuF,CAAG,EAAA,CAAA,EACtDtG,EAAAA,mBAAoE,OAApEmT,GAAoEpS,EAAAA,gBAAfU,CAAK,EAAA,CAAA,CAAA,kBATpD,CAAAiO,EAAAA,MAAAyB,EAAA,MAAiB,eAAe,CAAA,kCAejCS,EAAA,OAAX/R,EAAAA,UAAA,EAAAC,EAAAA,mBA+BM,MA/BNsT,GA+BM,CA9BJpT,EAAAA,mBAsBM,MAtBNqT,GAsBM,CArBJrT,EAAAA,mBAYS,SAAA,CAXP,KAAK,SACL,MAAM,qCACL,gBAAemR,EAAA,MAAiB,aACjC,gBAAc,qBACb,uBAAOW,EAAa,cAAA,EAAA,kBAErBlR,EAAAA,YAGEC,EAAAA,wBAFKsQ,EAAA,MAAiB,aAAe/Q,EAAAA,MAAApG,CAAA,EAAcoG,EAAAA,MAAAnG,EAAA,CAAY,EAAA,CAC9D,KAAM,GAAE,GAEXoG,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAAL,EAAAA,mBAAiB,YAAX,OAAI,EAAA,EAAA,QAEZA,EAAAA,mBAOS,SAAA,CANP,KAAK,SACL,MAAM,mCACN,MAAM,YACL,QAAKK,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAsS,EAAAA,cAAAhS,GAAOqR,EAAgBH,EAAW/D,EAAA,MAAM,SAAS,IAAI,EAAA,SAAA,EAAA,CAAA,MAAA,CAAA,EAAA,kBAE3DlN,EAAAA,YAAuEC,EAAAA,wBAAvDuQ,UAAW,UAAiBhR,EAAAA,MAAArG,EAAA,EAAQqG,EAAAA,MAAA7F,EAAA,CAAI,EAAA,CAAG,KAAM,GAAE,EAAA,KAGvE8X,iBAAArS,EAAAA,mBAMM,MANNsT,GAMM,CADJtT,EAAAA,mBAA8E,MAA9EuT,GAA8ExS,EAAAA,gBAAxC8Q,EAAW/D,EAAA,MAAM,SAAS,IAAI,CAAA,EAAA,CAAA,CAAA,QAH5D,CAAA4B,EAAAA,MAAAyB,EAAA,MAAiB,YAAY,CAAA,sCAS3CtR,EAAAA,UAAA,EAAAC,qBAMM,MANN0T,GAMM,CALJnT,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAAL,EAAAA,mBAAwD,KAAA,CAApD,MAAM,gCAAA,EAAiC,WAAQ,EAAA,GACnDA,EAAAA,mBAGM,MAHNyT,GAGM,CAFJtT,cAA0DC,EAAAA,MAAA/F,CAAA,EAAA,CAAlD,KAAM,GAAI,MAAM,+BAAA,GACxBgG,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAAL,EAAAA,mBAAuD,OAAA,CAAjD,MAAM,cAAa,0BAAuB,EAAA,EAAA,UAtPtDH,EAAAA,YAAAC,EAAAA,mBAMM,MANNG,GAMM,CALJE,cAAwDC,EAAAA,MAAA/F,CAAA,EAAA,CAAhD,KAAM,GAAI,MAAM,6BAAA,GACxBgG,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAA6D,KAAA,CAAzD,MAAM,8BAAA,EAA+B,kBAAe,EAAA,GACxDK,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAEI,IAAA,CAFD,MAAM,sCAAqC,mDAE9C,EAAA,EAAA,yhBCtJN,MAAMvG,EAAQqU,EAORuB,EAAOC,EAQPoE,EAAgBlV,EAAAA,SAAS,IAChB,IAAI,KAAK/E,EAAM,MAAM,QAAQ,SAAS,EACvC,mBAAmB,QAAS,CACtC,OAAQ,GACR,KAAM,UACN,OAAQ,UACR,OAAQ,UACR,uBAAwB,CAAA,CACzB,CACF,EAKK6X,EAAoB9S,EAAAA,SAAS,IAC7B/E,EAAM,MAAM,WAAa,KACpB,aAELA,EAAM,MAAM,SAAW,IAClB,GAAGA,EAAM,MAAM,QAAQ,KAEzB,IAAIA,EAAM,MAAM,SAAW,KAAM,QAAQ,CAAC,CAAC,GACnD,EAKK8X,EAAc/S,EAAAA,SAAS,IACvB/E,EAAM,MAAM,SAAW,KAAa,wBACpCA,EAAM,MAAM,OAAS,IAAY,oBACjCA,EAAM,MAAM,OAAS,IAAY,oBACjCA,EAAM,MAAM,OAAS,IAAY,oBACjCA,EAAM,MAAM,OAAS,IAAY,oBAC9B,mBACR,EAKKka,EAAanV,EAAAA,SAAS,IACtB/E,EAAM,MAAM,SAAW,KAAaY,EACpCZ,EAAM,MAAM,OAAS,IAAYma,GAC9BC,EACR,EAKKC,EAAYtV,EAAAA,SAAS,IAAM/E,EAAM,MAAM,WAAa,IAAI,EAK9D,SAASsa,GAAoB,CAC3B1E,EAAK,SAAU5V,EAAM,MAAM,EAAE,CAC/B,6BAIEqG,EAAAA,mBAgDS,SAAA,CA/CP,KAAK,SACJ,MAAKY,EAAAA,eAAA,8CAAgEoN,EAAA,UAAA,6BAAiDgG,EAAA,KAAA,EAAkD,CAAA,4BAAAhG,EAAA,MAAM,SAAA,CAAS,GAMvL,QAAOiG,CAAA,GAGR/T,EAAAA,mBAEM,MAFND,GAEMgB,EAAAA,gBADD2S,EAAA,KAAa,EAAA,CAAA,EAIlB1T,EAAAA,mBAIM,MAJNC,GAIM,CAHJD,EAAAA,mBAEO,OAAA,CAFA,wDAAyC8N,EAAA,MAAM,QAAQ,OAAO,YAAA,CAAW,EAAA,CAAA,CAAA,EAC3E/M,EAAAA,gBAAAX,QAAAyN,EAAA,EAAeC,EAAA,MAAM,QAAQ,MAAM,CAAA,EAAA,CAAA,CAAA,GAK1C9N,qBAEM,MAFNE,GAEMa,kBADD+M,QAAM,QAAQ,IAAI,EAAA,CAAA,EAIvB9N,EAAAA,mBASM,MATNM,GASM,CARQwN,EAAA,MAAM,SAAM,oBAAxBhO,EAAAA,mBAGO,OAAA,OAH6B,uCAAwByR,EAAA,KAAW,CAAA,CAAA,IACrE1R,YAAA,EAAAe,EAAAA,YAAyCC,0BAAzB8S,EAAA,KAAU,EAAA,CAAG,KAAM,GAAE,qBAAI,IACzC5S,EAAAA,gBAAG+M,EAAA,MAAM,MAAM,EAAA,CAAA,CAAA,OAEjBjO,EAAAA,YAAAC,EAAAA,mBAGO,OAHPoO,GAGO,CAFL/N,EAAAA,YAAoBC,EAAAA,MAAA/F,CAAA,EAAA,CAAZ,KAAM,GAAE,gCAAI,YAEtB,EAAA,EAAA,MAIF2F,EAAAA,mBAEM,MAFNc,GAEMC,EAAAA,gBADDuQ,EAAA,KAAiB,EAAA,CAAA,EAIXxD,EAAA,MAAM,WAAjBjO,EAAAA,YAAAC,EAAAA,mBAEM,MAFNkB,GAEM,CADJb,EAAAA,YAAkBC,EAAAA,MAAA3E,EAAA,EAAA,CAAZ,KAAM,GAAE,CAAA,+sCC1HpB,MAAMuY,EAAgB7K,GAAA,EAChB,CAAE,KAAAvL,EAAM,GAAAE,EAAI,UAAAS,CAAA,EAAcF,GAAA,EAG1BuR,EAAchU,EAAAA,IAAI,EAAK,EACvBiU,EAAiBjU,EAAAA,IAA6B,IAAI,EAGlDkU,EAA4B,CAChC,MACA,OACA,MACA,QACA,SACA,UACA,OACA,OAAA,EAIImE,EAAmB,CAAC,MAAO,MAAO,MAAO,KAAK,EAKpD,SAASC,GAAsB,CACzB3V,EAAU,QACZyV,EAAc,WAAW,EAAI,EAC7BpW,EAAK,CAAE,KAAM,eAAgB,EAEjC,CAKA,SAASuW,EAAmBvX,EAA0B,CACpDoX,EAAc,gBAAgBpX,CAAI,EAClCoX,EAAc,WAAW,EAAK,CAChC,CAKA,SAASI,EAAcxX,EAA6B,CAClDoX,EAAc,WAAWpX,CAAI,CAC/B,CAKA,SAASyX,EAAezX,EAA8B,CACpDoX,EAAc,YAAYpX,CAAI,CAChC,CAKA,SAAS0X,GAA8B,CACrCN,EAAc,cAAA,CAChB,CAKA,SAASzI,GAAsB,CAC7B3N,EAAK,CAAE,KAAM,iBAAkB,EAC/BoW,EAAc,cAAA,CAChB,CAKA,SAASO,EAAkB9L,EAAkB,CAC3CuL,EAAc,YAAYvL,CAAE,CAC9B,CAKA,SAAS0H,EAAkBhT,EAAoB,CAC7C,MAAMiT,EAASjT,EAAM,OACrB6W,EAAc,eAAe5D,EAAO,KAAK,CAC3C,CAKA,SAASC,GAAoB,CAC3B2D,EAAc,eAAe,EAAE,EAC/BnE,EAAe,OAAO,MAAA,CACxB,CAKA,SAASS,EAAazK,EAA0B,CAC9CmO,EAAc,mBAAmBnO,CAAM,CACzC,CAKA,SAAS0K,EAAe1K,EAA6B,CACnD,OAAOmO,EAAc,OAAO,QAAQ,SAASnO,CAAM,CACrD,CAKA,SAAS2O,EAAa/K,EAAqD,CACzEuK,EAAc,mBAAmBvK,CAAM,CACzC,CAKA,SAASgL,EAAehL,EAAwD,CAC9E,OAAOuK,EAAc,OAAO,YAAY,SAASvK,CAAM,CACzD,CAKA,SAASiL,GAA8B,CACrC,MAAMjE,EAAUuD,EAAc,OAAO,cACrCA,EAAc,mBAAmBvD,IAAY,GAAO,KAAO,EAAI,CACjE,CAKA,SAASE,GAAwB,CAC/BqD,EAAc,aAAA,CAChB,CAKA,SAASpD,GAAsB,CAC7BhB,EAAY,MAAQ,CAACA,EAAY,KACnC,CAKA,MAAMxJ,EAAmB5H,EAAAA,SAAS,IAAMwV,EAAc,kBAAkB,EAKlEW,EAAmBnW,EAAAA,SAAS,IAE9BwV,EAAc,OAAO,QAAQ,OAC7BA,EAAc,OAAO,YAAY,QAChCA,EAAc,OAAO,gBAAkB,KAAO,EAAI,EAEtD,EAGD,IAAIY,EAAqC,KACrCC,EAAoC,KACpCC,EAAqC,KACrCC,EAAoC,KAGxCrW,OAAAA,EAAAA,UAAU,IAAM,CAEdkW,EAAgB9W,EAAiB,WAAYqW,CAAkB,EAC/DU,EAAe/W,EAAoB,UAAWsW,CAAa,EAC3DU,EAAgBhX,EAAqB,WAAYuW,CAAc,EAC/DU,EAAejX,EAAG,mBAAoBwW,CAAqB,EAGvD/V,EAAU,OACZ2V,EAAA,CAEJ,CAAC,EAGD9G,EAAAA,YAAY,IAAM,CAChBwH,IAAA,EACAC,IAAA,EACAC,IAAA,EACAC,IAAA,CACF,CAAC,EAGD5H,QAAM5O,EAAYqB,GAAgB,CAC5BA,GACFsU,EAAA,CAEJ,CAAC,UAICrU,YAAA,EAAAC,qBA4MM,MA5MNC,GA4MM,CA1MJC,EAAAA,mBA8DM,MA9DNC,GA8DM,CA5DJD,EAAAA,mBAmBM,MAnBNE,GAmBM,CAlBJC,cAAmDC,EAAAA,MAAApF,EAAA,EAAA,CAA1C,KAAM,GAAI,MAAM,uBAAA,GACzBgF,EAAAA,mBAOE,QAAA,SANI,iBAAJ,IAAI6P,EACJ,KAAK,OACL,MAAM,+BACN,YAAY,iCACX,MAAOzP,EAAAA,MAAA4T,CAAA,EAAc,OAAO,YAC5B,QAAO7D,CAAA,cAGF/P,EAAAA,MAAA4T,CAAA,EAAc,OAAO,2BAD7BlU,EAAAA,mBAQS,SAAA,OANP,KAAK,SACL,MAAM,kDACN,MAAM,eACL,QAAOuQ,CAAA,GAERlQ,EAAAA,YAAgBC,EAAAA,MAAA5E,EAAA,EAAA,CAAZ,KAAM,GAAE,CAAA,kCAKhBwE,EAAAA,mBAeS,SAAA,CAdP,KAAK,SACJ,MAAKU,EAAAA,eAAA,+EAAyG0F,EAAA,KAAA,CAAgB,GAI9H,gBAAewJ,EAAA,MACf,QAAOgB,CAAA,GAERzQ,EAAAA,YAAqBC,EAAAA,MAAA4Q,EAAA,EAAA,CAAZ,KAAM,GAAE,EACjB3Q,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,qBAAoB,YAAd,UAAO,EAAA,GACD2U,EAAA,MAAgB,iBAA5B7U,EAAAA,mBAEO,OAFPgB,GAEOC,EAAAA,gBADF4T,EAAA,KAAgB,EAAA,CAAA,8CAErB/T,EAAAA,YAAoEC,EAAAA,wBAApD+O,QAAcxP,EAAAA,MAAAlG,EAAA,EAAYkG,EAAAA,MAAApG,CAAA,CAAW,EAAA,CAAG,KAAM,GAAE,EAAA,SAIlEgG,EAAAA,mBAQM,MARNgB,GAQM,CAPJhB,EAAAA,mBAEO,OAFPiB,GAEOF,EAAAA,gBADFX,EAAAA,MAAA4T,CAAA,EAAc,gBAAgB,MAAM,EAAG,aAC5C,CAAA,EACY5T,EAAAA,MAAA4T,CAAA,EAAc,gBAAe,iBAAzClU,EAAAA,mBAAyF,OAAzFoB,GAAiF,GAAC,+BACtEd,QAAA4T,CAAA,EAAc,gBAAe,iBAAzClU,EAAAA,mBAEO,OAFPqB,GAA4E,0BACnEf,EAAAA,MAAA4T,CAAA,EAAc,eAAe,EAAG,MACzC,CAAA,iCAIFhU,EAAAA,mBAQS,SAAA,CAPP,KAAK,SACL,MAAM,+BACN,MAAM,iBACL,SAAUI,EAAAA,MAAA4T,CAAA,EAAc,QAAQ,SAAM,EACtC,QAAOzI,CAAA,GAERpL,EAAAA,YAAqBC,EAAAA,MAAAhF,EAAA,EAAA,CAAZ,KAAM,GAAE,CAAA,UAKVwU,EAAA,OAAX/P,EAAAA,UAAA,EAAAC,EAAAA,mBAwEM,MAxENsO,GAwEM,CAtEJpO,EAAAA,mBAiBM,MAjBNqO,GAiBM,CAhBJhO,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAAgD,KAAA,CAA5C,MAAM,yBAAA,EAA0B,UAAO,EAAA,GAC3CA,EAAAA,mBAcM,MAdNsO,GAcM,gBAbJxO,EAAAA,mBAYSS,EAAAA,SAAA,KAAAC,aAXUsP,EAAVjK,GADT7F,EAAAA,mBAYS,SAAA,CAVN,IAAK6F,EACN,KAAK,SACJ,MAAKnF,EAAAA,eAAA,gBAAiE,iBAAAmF,EAAO,YAAA,CAAW,8BAAiD0K,EAAe1K,CAAM,GAAKzF,EAAAA,MAAA4T,CAAA,EAAc,OAAO,QAAQ,OAAM,CAAA,CAAA,GAKtM,QAAKrT,GAAE2P,EAAazK,CAAM,CAAA,oBAExBA,CAAM,EAAA,GAAA0I,EAAA,YAMfvO,EAAAA,mBAoBM,MApBNwO,GAoBM,CAnBJnO,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAA+C,KAAA,CAA3C,MAAM,yBAAA,EAA0B,SAAM,EAAA,GAC1CA,EAAAA,mBAiBM,MAjBNyO,GAiBM,gBAhBJ3O,EAAAA,mBAeSS,EAAAA,SAAA,KAAAC,aAdUyT,EAAVxK,GADTzJ,EAAAA,mBAeS,SAAA,CAbN,IAAKyJ,EACN,KAAK,SACJ,MAAK/I,EAAAA,eAAA,iEAAiG+I,CAAM,GAA4D,CAAA,uCAAAgL,EAAehL,CAAM,CAAA,CAAA,GAK7L,QAAK9I,GAAE6T,EAAa/K,CAAM,CAAA,GAExB2I,EAAAA,gBAAArR,EAAAA,gBAAA0I,CAAM,EAAG,IACZ,CAAA,EAAAzJ,EAAAA,mBAEO,OAFP2O,GAA6C,KAC1C5N,EAAAA,gBAAGX,EAAAA,MAAA4T,CAAA,EAAc,aAAavK,CAAM,CAAA,EAAI,KAC3C,CAAA,CAAA,mBAMNzJ,EAAAA,mBAcM,MAdN4O,GAcM,CAbJvO,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAA6C,KAAA,CAAzC,MAAM,yBAAA,EAA0B,OAAI,EAAA,GACxCA,EAAAA,mBAWM,MAXN6O,GAWM,CAVJ7O,EAAAA,mBASS,SAAA,CARP,KAAK,SACJ,MAAKU,EAAAA,eAAA,wEAA0GN,EAAAA,MAAA4T,CAAA,EAAc,OAAO,aAAA,CAAa,GAIjJ,QAAOU,CAAA,EACT,mBAED,CAAA,CAAA,KAKOtO,EAAA,OAAXvG,EAAAA,UAAA,EAAAC,EAAAA,mBASM,MATNgP,GASM,CARJ9O,EAAAA,mBAOS,SAAA,CANP,KAAK,SACL,MAAM,iBACL,QAAO2Q,CAAA,GAERxQ,EAAAA,YAAgBC,EAAAA,MAAA5E,EAAA,EAAA,CAAZ,KAAM,GAAE,gCAAI,sBAElB,EAAA,EAAA,iEAKJwE,EAAAA,mBA6DM,MA7DN+O,GA6DM,CA3DO3O,EAAAA,MAAA4T,CAAA,EAAc,WAAzBnU,EAAAA,UAAA,EAAAC,EAAAA,mBAGM,MAHNkP,GAGM,CAAA,GAAA3O,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAA,CAFJL,EAAAA,mBAAyC,MAAA,CAApC,MAAM,2BAAA,EAA2B,KAAA,EAAA,EACtCA,EAAAA,mBAAmD,OAAA,CAA7C,MAAM,YAAA,EAAa,sBAAmB,EAAA,CAAA,MAI9BI,EAAAA,MAAA4T,CAAA,EAAc,OAA9BnU,EAAAA,YAAAC,EAAAA,mBAKM,MALNmP,GAKM,CAJJjP,qBAAgE,IAAhEkP,GAAgEnO,EAAAA,gBAA1BX,EAAAA,MAAA4T,CAAA,EAAc,KAAK,EAAA,CAAA,EACzDhU,EAAAA,mBAES,SAAA,CAFD,KAAK,SAAS,MAAM,mBAAoB,QAAOkU,CAAA,EAAe,SAEtE,CAAA,IAIc9T,EAAAA,MAAA4T,CAAA,EAAc,QAAQ,SAAM,GAA5CnU,YAAA,EAAAC,qBAMM,MANNqP,GAMM,CALJhP,cAA8CC,EAAAA,MAAA/F,CAAA,EAAA,CAAtC,KAAM,GAAI,MAAM,mBAAA,GACxBgG,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAAmD,KAAA,CAA/C,MAAM,oBAAA,EAAqB,kBAAe,EAAA,GAC9CK,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAEI,IAAA,CAFD,MAAM,4BAA2B,iEAEpC,EAAA,EAAA,IAIcI,EAAAA,MAAA4T,CAAA,EAAc,gBAAgB,SAAM,GAApDnU,YAAA,EAAAC,qBAcM,MAdNsP,GAcM,CAbJjP,cAA+CC,EAAAA,MAAApF,EAAA,EAAA,CAAtC,KAAM,GAAI,MAAM,mBAAA,GACzBqF,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAAwD,KAAA,CAApD,MAAM,oBAAA,EAAqB,uBAAoB,EAAA,GACnDK,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAEI,IAAA,CAFD,MAAM,0BAAA,EAA2B,0CAEpC,EAAA,GAEQoG,EAAA,qBADRtG,EAAAA,mBAOS,SAAA,OALP,KAAK,SACL,MAAM,qBACL,QAAO6Q,CAAA,EACT,iBAED,iDAIF7Q,EAAAA,mBAkBWS,EAAAA,SAAA,CAAA,IAAA,GAAA,CAhBTP,EAAAA,mBAUM,MAVNsS,GAUM,CATJtS,EAAAA,mBAQM,MARNuS,GAQM,EAPJ1S,EAAAA,UAAA,EAAA,EAAAC,EAAAA,mBAMES,EAAAA,SAAA,KAAAC,aALgBJ,EAAAA,MAAA4T,CAAA,EAAc,gBAAvBrK,kBADT/I,EAAAA,YAMEoU,GAAA,CAJC,IAAKrL,EAAM,GACX,MAAAA,EACA,cAAavJ,EAAAA,MAAA4T,CAAA,EAAc,kBAAoBrK,EAAM,GACrD,SAAQ4K,CAAA,8CAMfvU,EAAAA,mBAEM,MAFNwS,GAEM,CADJrS,EAAAA,YAAuD8U,GAAA,CAAtC,MAAO7U,EAAAA,MAAA4T,CAAA,EAAc,aAAA,8rBC3XhD,MAAMva,EAAQqU,EAMRuB,EAAOC,EAOP2C,EAAOrW,EAAAA,IAAY,EAAE,EAGrBsZ,EAAkBtZ,EAAAA,IAAmB,IAAI,EAGzCuZ,EAAU3W,EAAAA,SAAS,IAAM0W,EAAgB,QAAU,IAAI,EAGvDE,EAAY5W,EAAAA,SAAS,IAClByT,EAAK,MAAM,MAAM;AAAA,CAAI,EAAE,MAC/B,EAGKoD,EAAc7W,EAAAA,SAAS,IACpB,MAAM,KAAK,CAAE,OAAQ4W,EAAU,KAAA,EAAS,CAACE,EAAGC,IAAMA,EAAI,CAAC,CAC/D,EASD,SAASC,GAAuB,CAC9B,GAAI,CACFvD,EAAK,MAAQ,KAAK,UAAUxY,EAAM,WAAY,KAAM,CAAC,EACrDyb,EAAgB,MAAQ,IAC1B,MAAc,CACZjD,EAAK,MAAQ,GACbiD,EAAgB,MAAQ,uBAC1B,CACF,CAGAM,EAAA,EAGArI,EAAAA,MACE,IAAM1T,EAAM,WACZ,IAAM,CAEJ,GAAI,CACF,MAAMgc,EAAgB,KAAK,MAAMxD,EAAK,KAAK,EACvC,KAAK,UAAUwD,CAAa,IAAM,KAAK,UAAUhc,EAAM,UAAU,GACnE+b,EAAA,CAEJ,MAAQ,CAENA,EAAA,CACF,CACF,CAAA,EAUF,SAASE,EAAYvY,EAAoB,CACvC,MAAMiT,EAASjT,EAAM,OACrB8U,EAAK,MAAQ7B,EAAO,MACpBuF,EAAA,CACF,CAKA,SAASA,GAAwB,CAC/B,GAAI1D,EAAK,MAAM,KAAA,IAAW,GAAI,CAC5BiD,EAAgB,MAAQ,KACxB7F,EAAK,oBAAqB,EAAE,EAC5B,MACF,CAEA,GAAI,CACF,MAAMuG,EAAS,KAAK,MAAM3D,EAAK,KAAK,EACpCiD,EAAgB,MAAQ,KACxB7F,EAAK,oBAAqBuG,CAAM,CAClC,OAAShT,EAAK,CACZ,GAAIA,aAAe,MAAO,CAExB,MAAMrK,EAAQqK,EAAI,QAAQ,MAAM,gBAAgB,EAChD,GAAIrK,EAAO,CACT,MAAMsd,EAAW,OAAO,SAAStd,EAAM,CAAC,EAAG,EAAE,EACvCud,EAAQ7D,EAAK,MAAM,UAAU,EAAG4D,CAAQ,EAAE,MAAM;AAAA,CAAI,EACpDE,EAAOD,EAAM,OACbE,EAASF,EAAMA,EAAM,OAAS,CAAC,EAAE,OAAS,EAChDZ,EAAgB,MAAQ,QAAQa,CAAI,YAAYC,CAAM,KAAKpT,EAAI,OAAO,EACxE,MACEsS,EAAgB,MAAQtS,EAAI,OAEhC,MACEsS,EAAgB,MAAQ,cAE5B,CACF,CAKA,SAASrD,GAAmB,CAC1B,GAAI,CACF,MAAM+D,EAAS,KAAK,MAAM3D,EAAK,KAAK,EACpCA,EAAK,MAAQ,KAAK,UAAU2D,EAAQ,KAAM,CAAC,EAC3CV,EAAgB,MAAQ,KACxB7F,EAAK,oBAAqBuG,CAAM,CAClC,MAAQ,CAER,CACF,CAKA,SAASK,EAAc9Y,EAA4B,CACjD,GAAIA,EAAM,MAAQ,MAAO,CACvBA,EAAM,eAAA,EACN,MAAMiT,EAASjT,EAAM,OACf+Y,EAAQ9F,EAAO,eACf+F,EAAM/F,EAAO,aAGbgG,EAAU,GAAGnE,EAAK,MAAM,UAAU,EAAGiE,CAAK,CAAC,KAAKjE,EAAK,MAAM,UAAUkE,CAAG,CAAC,GAC/ElE,EAAK,MAAQmE,EAGb,WAAW,IAAM,CACfhG,EAAO,eAAiBA,EAAO,aAAe8F,EAAQ,CACxD,EAAG,CAAC,EAEJP,EAAA,CACF,CACF,CAMA,OAAAU,EAAa,CACX,WAAAxE,EACA,QAAAsD,CAAA,CACD,UAICtV,YAAA,EAAAC,qBA8CM,MA9CNC,GA8CM,CA5CJC,EAAAA,mBAuBM,MAvBNC,GAuBM,CArBJD,EAAAA,mBAQM,MARNE,GAQM,kBAPJJ,EAAAA,mBAMMS,EAAAA,SAAA,KAAAC,EAAAA,WALc6U,EAAA,MAAXiB,kBADTxW,EAAAA,mBAMM,MAAA,CAJH,IAAKwW,EACN,MAAM,0BAAA,oBAEHA,CAAO,EAAA,CAAA,YAKdtW,EAAAA,mBASE,WAAA,CARC,MAAOiS,EAAA,MACP,SAAUnE,EAAA,SACV,YAAaA,EAAA,YACb,qCAAuBA,EAAA,SAAS,KAAA,EACjC,MAAM,wBACN,WAAW,QACV,QAAO4H,EACP,UAASO,CAAA,gBAKdjW,EAAAA,mBAiBM,MAjBNkO,GAiBM,CAhBJlO,EAAAA,mBAUM,MAVNc,GAUM,CAROqU,EAAA,OAAXtV,EAAAA,UAAA,EAAAC,EAAAA,mBAGM,MAHNkB,GAGM,CAFJb,EAAAA,YAAoBC,EAAAA,MAAArG,EAAA,EAAA,CAAZ,KAAM,GAAE,EAChBsG,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAAuB,YAAjB,aAAU,EAAA,EAAA,IAEFkV,EAAA,OAAhBrV,EAAAA,YAAAC,EAAAA,mBAGM,MAHNmB,GAGM,CAFJd,EAAAA,YAA0BC,EAAAA,MAAAmW,EAAA,EAAA,CAAZ,KAAM,GAAE,EACtBvW,EAAAA,mBAAkC,8BAAzBkV,EAAA,KAAe,EAAA,CAAA,CAAA,kCAI5BlV,EAAAA,mBAGM,MAHNkB,GAGM,CADJlB,EAAAA,mBAA4D,OAA5DmB,GAA4DJ,EAAAA,gBAAzBqU,EAAA,KAAS,EAAG,SAAM,CAAA,CAAA,8CCpMvDoB,GAAS5a,EAAAA,IAAa,EAAE,EACxB6a,EAAgBC,EAAAA,SAAwB,CAC5C,QAAS,GACT,MAAO,GACP,QAAS,GACT,YAAa,UACb,WAAY,SACZ,UAAW,KACX,SAAU,IACZ,CAAC,EAGKC,OAAe,IAGrB,IAAIC,EAAoD,KAMpDC,GAAiB,EAErB,SAASC,IAA0B,CACjC,MAAO,SAAS,KAAK,IAAA,CAAK,IAAID,IAAgB,EAChD,CAEA,SAASE,GAASpa,EAAiBS,EAAiB4Z,EAAW,IAAc,CAC3E,MAAMvO,EAAKqO,GAAA,EACLG,EAAe,CACnB,GAAAxO,EACA,KAAA9L,EACA,QAAAS,EACA,SAAA4Z,EACA,UAAW,KAAK,IAAA,CAAI,EAMtB,GAHAR,GAAO,MAAM,KAAKS,CAAK,EAGnBD,EAAW,EAAG,CAChB,MAAME,EAAY,WAAW,IAAM,CACjCC,GAAY1O,CAAE,EACdkO,GAAS,OAAOlO,CAAE,CACpB,EAAGuO,CAAQ,EACXL,GAAS,IAAIlO,EAAIyO,CAAS,CAC5B,CAEA,OAAOzO,CACT,CAEA,SAAS0O,GAAY1O,EAAkB,CAErC,MAAMyO,EAAYP,GAAS,IAAIlO,CAAE,EAC7ByO,IAAc,SAChB,aAAaA,CAAS,EACtBP,GAAS,OAAOlO,CAAE,GAIpB,MAAM1P,EAAQyd,GAAO,MAAM,UAAWY,GAAMA,EAAE,KAAO3O,CAAE,EACnD1P,IAAU,IACZyd,GAAO,MAAM,OAAOzd,EAAO,CAAC,CAEhC,CAWO,SAASse,IAAmB,CAIjC,SAASC,EAAQla,EAAiB4Z,EAA2B,CAC3D,OAAOD,GAAS,UAAW3Z,EAAS4Z,CAAQ,CAC9C,CAKA,SAASja,EAAMK,EAAiB4Z,EAA2B,CACzD,OAAOD,GAAS,QAAS3Z,EAAS4Z,CAAQ,CAC5C,CAKA,SAASO,EAAKna,EAAiB4Z,EAA2B,CACxD,OAAOD,GAAS,OAAQ3Z,EAAS4Z,CAAQ,CAC3C,CAKA,SAASQ,EAAQpa,EAAiB4Z,EAA2B,CAC3D,OAAOD,GAAS,UAAW3Z,EAAS4Z,CAAQ,CAC9C,CAOA,SAASS,EACPra,EACAkB,EAKkB,CAClB,OAAO,IAAI,QAASoZ,GAAY,CAE1Bd,IACFA,EAAe,EAAK,EACpBA,EAAiB,MAInBA,EAAiBc,EAEjBjB,EAAc,QAAU,GACxBA,EAAc,MAAQnY,GAAS,OAAS,UACxCmY,EAAc,QAAUrZ,EACxBqZ,EAAc,YAAcnY,GAAS,aAAe,UACpDmY,EAAc,WAAanY,GAAS,YAAc,SAElDmY,EAAc,UAAY,IAAM,CAC9BA,EAAc,QAAU,GACpBG,IACFA,EAAe,EAAI,EACnBA,EAAiB,KAErB,EAEAH,EAAc,SAAW,IAAM,CAC7BA,EAAc,QAAU,GACpBG,IACFA,EAAe,EAAK,EACpBA,EAAiB,KAErB,CACF,CAAC,CACH,CAKA,SAASe,GAAqB,CAC5BlB,EAAc,QAAU,GACpBG,IACFA,EAAe,EAAK,EACpBA,EAAiB,KAErB,CAKA,SAASgB,EAAQnP,EAAkB,CACjC0O,GAAY1O,CAAE,CAChB,CAKA,SAASoP,GAAiB,CAExB,UAAWX,KAAaP,GAAS,SAC/B,aAAaO,CAAS,EAExBP,GAAS,MAAA,EACTH,GAAO,MAAQ,CAAA,CACjB,CAEA,MAAO,CAEL,OAAAA,GACA,cAAAC,EAGA,QAAAa,EACA,MAAAva,EACA,KAAAwa,EACA,QAAAC,EACA,QAAAI,EACA,SAAAC,EAGA,QAAAJ,EACA,aAAAE,CAAA,CAEJ,u+BC5NA,MAAMG,EAAcnW,GAAA,EACd,CAAE,KAAA/D,EAAM,GAAAE,EAAI,UAAAS,CAAA,EAAcF,GAAA,EAC1B,CAAE,QAAAiZ,EAAS,MAAOS,EAAa,QAAAN,CAAA,EAAYJ,GAAA,EAO3CW,EAAgBpc,EAAAA,IAA4C,IAAI,EAGhEqc,EAAmBrc,EAAAA,IAAI,EAAK,EAMlC8C,EAAAA,UAAU,SAAY,CAEpB,GAAI,CACF,MAAMoZ,EAAY,aAAA,EAGdA,EAAY,QAAQ,OAAS,GAAK,CAACA,EAAY,gBACjD,MAAMA,EAAY,mBAAmBA,EAAY,QAAQ,CAAC,EAAE,IAAI,CAEpE,OAASlV,EAAK,CAEPkV,EAAY,QACfA,EAAY,MAAQlV,aAAe,MAAQA,EAAI,QAAU,yBAE7D,CACF,CAAC,EAOD9E,EAAG,gBAAkBlB,GAAS,CAE5B,MAAMsb,EAAUtb,EAChB,GACE,OAAOA,GAAS,UAChBA,IAAS,MACT,OAAOsb,EAAQ,QAAW,UAC1B,OAAOA,EAAQ,QAAW,UAC1B,OAAOA,EAAQ,OAAU,SACzB,CACA,QAAQ,KAAK,8CAA+Ctb,CAAI,EAChE,MACF,CAEAkb,EAAY,kBAAkBlb,CAAyD,CACzF,CAAC,EAGDkB,EAAG,WAAalB,GAAS,CAEvB,MAAMsb,EAAUtb,EAChB,GACE,OAAOA,GAAS,UAChBA,IAAS,MACT,OAAOsb,EAAQ,SAAY,WAC3B,CAAC,MAAM,QAAQA,EAAQ,OAAO,EAC9B,CACA,QAAQ,KAAK,yCAA0Ctb,CAAI,EAC3D,MACF,CAEAkb,EAAY,qBAAqBlb,CAA+C,CAClF,CAAC,EAODuQ,EAAAA,MACE,IAAM2K,EAAY,eAClB,SAAY,CACNE,EAAc,OAASF,EAAY,aAAa,OAAS,IAE3D,MAAMK,WAAA,EACNH,EAAc,OAAO,WAAA,EAEzB,CAAA,EAUF,eAAeI,EAAatV,EAAmC,CACzDgV,EAAY,SASV,CARc,MAAML,EACtB,qEACA,CACE,MAAO,kBACP,YAAa,gBACb,WAAY,QAAA,CACd,GAKJ,MAAMK,EAAY,mBAAmBhV,CAAU,CACjD,CAKA,eAAeK,GAA2B,CACxC,GAAI,CAAC6U,EAAc,OAAO,QAAS,CACjCD,EAAY,wDAAwD,EACpE,MACF,CAGA,GADc,MAAMD,EAAY,UAAA,EAE9BR,EAAQ,0BAA0B,MAC7B,CAEL,MAAM7R,EAAeqS,EAAY,OAAS,uBAC1CC,EAAYtS,CAAY,CAC1B,CACF,CAKA,eAAelC,GAAgC,CAC7C,GAAI,CAACuU,EAAY,QAAS,OAER,MAAML,EAAQ,gDAAiD,CAC/E,MAAO,kBACP,YAAa,UACb,WAAY,QAAA,CACb,IAECK,EAAY,eAAA,EACZR,EAAQ,mBAAmB,EAE/B,CAKA,eAAehU,GAA6B,CAC1C2U,EAAiB,MAAQ,GAEzB,GAAI,CAEF,GADgB,MAAMH,EAAY,YAAA,EAEhCR,EAAQ,6BAA6B,MAChC,CAEL,MAAM7R,EAAeqS,EAAY,OAAS,yBAC1CC,EAAYtS,CAAY,CAC1B,CACF,OAAS7C,EAAK,CACZ,MAAM6C,EAAe7C,aAAe,MAAQA,EAAI,QAAU,yBAC1DmV,EAAYtS,CAAY,CAC1B,CACF,CAKA,eAAe4S,GAA2B,CACxC,GAAI,CAAC9Z,EAAU,MAAO,CACpBwZ,EAAY,iDAAiD,EAC7D,MACF,CAEkB,MAAMN,EACtB,2EACA,CACE,MAAO,qBACP,YAAa,SACb,WAAY,QAAA,CACd,IAIF7Z,EAAK,CAAE,KAAM,SAAU,EACvB0Z,EAAQ,qBAAqB,EAC/B,CAKA,SAASgB,EAAmB7W,EAAsB,CAChDqW,EAAY,YAAYrW,CAAK,CAC/B,eAIE5B,YAAA,EAAAC,qBAsKM,MAtKNC,GAsKM,CApKJC,EAAAA,mBAoCQ,QApCRC,GAoCQ,CAnCND,EAAAA,mBAIM,MAJNE,GAIM,CAHJC,EAAAA,YAAuBC,EAAAA,MAAA5F,EAAA,EAAA,CAAZ,KAAM,GAAE,EACnB6F,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,qBAAoB,YAAd,UAAO,EAAA,GACbA,qBAAwE,OAAxEM,GAAwES,EAAAA,gBAAjCX,EAAAA,MAAA0X,CAAA,EAAY,WAAW,EAAA,CAAA,CAAA,GAIrD1X,QAAA0X,CAAA,EAAY,SAAW1X,EAAAA,SAAY,QAAQ,SAAM,GAA5DP,EAAAA,UAAA,EAAAC,qBAGM,MAHNoO,GAGM,CAAA,GAAA7N,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAA,CAFJL,EAAAA,mBAAuB,MAAA,CAAlB,MAAM,SAAA,EAAS,KAAA,EAAA,EACpBA,EAAAA,mBAAuB,YAAjB,aAAU,EAAA,CAAA,OAIlBH,EAAAA,YAAAC,EAAAA,mBAaM,MAbNgB,GAaM,EAZJjB,EAAAA,UAAA,EAAA,EAAAC,EAAAA,mBAWSS,EAAAA,SAAA,KAAAC,aAVUJ,EAAAA,MAAA0X,CAAA,EAAY,QAAtBrV,kBADT3C,EAAAA,mBAWS,SAAA,CATN,IAAK2C,EAAO,KACZ,MAAK/B,EAAAA,eAAA,wBAAsF,CAAA,+BAAAN,EAAAA,MAAA0X,CAAA,EAAY,iBAAmBrV,EAAO,IAAA,CAAI,GAIrI,QAAK9B,GAAEyX,EAAa3V,EAAO,IAAI,CAAA,GAEhCzC,EAAAA,mBAA2D,OAA3DiB,GAA2DF,EAAAA,gBAArB0B,EAAO,IAAI,EAAA,CAAA,EACjDzC,EAAAA,mBAA6D,OAA7DkB,GAA6DH,EAAAA,gBAAtB0B,EAAO,KAAK,EAAA,CAAA,CAAA,oBAKvDzC,EAAAA,mBAKM,MALNmB,GAKM,CAJJnB,EAAAA,mBAGM,MAHNmO,GAGM,CAFJ9N,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAA4C,OAAA,CAAtC,MAAM,YAAA,EAAa,eAAY,EAAA,GACrCA,qBAA2D,OAA3DoO,GAA2DrN,EAAAA,gBAAhCX,EAAAA,MAAA0X,CAAA,EAAY,UAAU,EAAA,CAAA,CAAA,OAMvD9X,EAAAA,mBAkGO,OAlGPqO,GAkGO,CAjGWjO,QAAA0X,CAAA,EAAY,8BAA5BhY,EAAAA,mBAiFWS,WAAA,CAAA,IAAA,GAAA,CA/ETP,EAAAA,mBAwDM,MAxDNsO,GAwDM,CAvDJtO,EAAAA,mBASM,MATNuO,GASM,CARJvO,qBAA+D,OAA/DwO,GAA+DzN,EAAAA,gBAApCX,EAAAA,MAAA0X,CAAA,EAAY,cAAc,EAAA,CAAA,EACrD9X,EAAAA,mBAA6E,OAA7EyO,GAAyB,IAAC1N,EAAAA,gBAAGX,EAAAA,MAAA0X,CAAA,EAAY,aAAa,MAAM,EAAG,UAAO,CAAA,EAE9D1X,EAAAA,MAAA0X,CAAA,EAAY,uBADpBhY,EAAAA,mBAKO,OALP4O,GAGC,WAED,iCAGF1O,EAAAA,mBA2CM,MA3CN2O,GA2CM,CAxCIvO,EAAAA,MAAA0X,CAAA,EAAY,uBADpBhY,EAAAA,mBAQS,SAAA,OANP,MAAM,iBACN,MAAM,kBACL,QAAOyD,CAAA,GAERpD,EAAAA,YAAgBC,EAAAA,MAAA5E,EAAA,EAAA,CAAZ,KAAM,GAAE,EACZ6E,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAAoB,YAAd,UAAO,EAAA,EAAA,gCAIfA,EAAAA,mBAQS,SAAA,CAPN,UAAWI,EAAAA,MAAA0X,CAAA,EAAY,SAAW1X,EAAAA,MAAA0X,CAAA,EAAY,QAC/C,MAAM,mBACN,MAAM,eACL,QAAO3U,CAAA,GAERhD,EAAAA,YAAmBC,EAAAA,MAAArF,EAAA,EAAA,CAAZ,KAAM,GAAE,EACfsF,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAAiB,YAAX,OAAI,EAAA,EAAA,QAIZA,EAAAA,mBAOS,SAAA,CANP,MAAM,kBACN,MAAM,kBACL,uBAAOiY,EAAA,MAAgB,GAAA,GAExB9X,EAAAA,YAAqBC,EAAAA,MAAAhF,EAAA,EAAA,CAAZ,KAAM,GAAE,EACjBiF,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAAkB,YAAZ,QAAK,EAAA,EAAA,GAIbA,EAAAA,mBAQS,SAAA,CAPN,UAAWI,EAAAA,MAAA7B,CAAA,EACZ,MAAM,qBACN,MAAM,yCACL,QAAO8Z,CAAA,GAERlY,EAAAA,YAAwBC,EAAAA,MAAAvF,EAAA,EAAA,CAAZ,KAAM,GAAE,EACpBwF,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAAL,EAAAA,mBAAuB,YAAjB,aAAU,EAAA,EAAA,YAMXI,EAAAA,MAAA0X,CAAA,EAAY,OAAvBjY,EAAAA,YAAAC,EAAAA,mBAEM,MAFNgP,GAEM,CADJ9O,qBAAuC,OAAA,KAAjC,MAAGe,EAAAA,gBAAGX,EAAAA,MAAA0X,CAAA,EAAY,KAAK,EAAA,CAAA,CAAA,gCAI/B9X,EAAAA,mBAQM,MARN+O,GAQM,CAPJ5O,EAAAA,YAMEoY,GAAA,SALI,gBAAJ,IAAIP,EACH,cAAa5X,EAAAA,MAAA0X,CAAA,EAAY,aACzB,SAAU1X,EAAAA,MAAA0X,CAAA,EAAY,QACtB,aAAY,IACZ,sBAAoBQ,CAAA,uCAKdlY,EAAAA,MAAA0X,CAAA,EAAY,SAAvBjY,EAAAA,UAAA,EAAAC,EAAAA,mBAGM,MAHNkP,GAGM,CAAA,GAAA3O,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAA,CAFJL,EAAAA,mBAAuB,MAAA,CAAlB,MAAM,SAAA,EAAS,KAAA,EAAA,EACpBA,EAAAA,mBAAuB,YAAjB,aAAU,EAAA,CAAA,yCAKpBH,EAAAA,YAAAC,EAAAA,mBAYM,MAZNmP,GAYM,CAVO7O,EAAAA,MAAA0X,CAAA,EAAY,OAAvBjY,EAAAA,YAAAC,EAAAA,mBAEM,MAFNoP,GAEM,CADJlP,qBAAuC,OAAA,KAAjC,MAAGe,EAAAA,gBAAGX,EAAAA,MAAA0X,CAAA,EAAY,KAAK,EAAA,CAAA,CAAA,mBAE/BhY,EAAAA,mBAMWS,EAAAA,SAAA,CAAA,IAAA,GAAA,CALTJ,cAAiDC,EAAAA,MAAA5F,EAAA,EAAA,CAAtC,KAAM,GAAI,MAAM,mBAAA,GAC3B6F,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAAL,EAAAA,mBAAmD,KAAA,CAA/C,MAAM,oBAAA,EAAqB,kBAAe,EAAA,GAC9CK,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAAL,EAAAA,mBAEI,IAAA,CAFD,MAAM,4BAA2B,gEAEpC,EAAA,EAAA,2BAMNY,EAAAA,YAuBW4X,EAAAA,SAAA,CAvBD,GAAG,QAAM,CACNP,EAAA,qBAAXnY,EAAAA,mBAqBM,MAAA,OArBuB,MAAM,gBAAiB,uBAAOmY,EAAA,MAAgB,GAAA,GACzEjY,EAAAA,mBAmBM,MAAA,CAnBD,MAAM,QAAS,oCAAD,IAAA,CAAA,EAAW,CAAA,MAAA,CAAA,EAAA,iBAC5BA,EAAAA,mBAEM,MAAA,CAFD,MAAM,iBAAe,CACxBA,qBAA0B,UAAtB,mBAAiB,CAAA,OAEvBA,EAAAA,mBAMM,MANNmP,GAMM,CALJnP,EAAAA,mBAGI,IAAA,KAAA,iCAHD,iDAED,EAAA,GAAAA,qBAAiD,SAAA,KAAAe,EAAAA,gBAAtCX,EAAAA,MAAA0X,CAAA,EAAY,cAAc,EAAA,CAAA,kCAAY,KACnD,EAAA,EAAA,GACAzX,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAAL,EAAAA,mBAAuD,IAAA,CAApD,MAAM,cAAa,gCAA6B,EAAA,EAAA,GAErDA,EAAAA,mBAOM,MAPNoP,GAOM,CANJpP,EAAAA,mBAES,SAAA,CAFD,MAAM,iBAAkB,uBAAOiY,EAAA,MAAgB,GAAA,EAAU,UAEjE,EACAjY,EAAAA,mBAES,SAAA,CAFD,MAAM,kBAAmB,QAAOsD,CAAA,EAAa,gBAErD,CAAA,m7BCxVZ,MAAMmV,EAAkBvR,GAAA,EAClByI,EAAgB/L,GAAA,EAChB,CAAE,KAAAhG,EAAM,GAAAE,CAAA,EAAOO,GAAA,EAOfqa,EAAoB9c,EAAAA,IAAI,EAAE,EAG1B+c,EAAsB/c,EAAAA,IAAI,KAAK,EAG/Bgd,EAAmBhd,EAAAA,IAAmB,IAAI,EAG1CsI,EAAsBtI,EAAAA,IAAmB,IAAI,EAG7CkU,EAAc,CAAC,MAAO,OAAQ,MAAO,QAAS,SAAU,UAAW,MAAM,EAG/E,IAAI+I,EAAmC,CAAA,EAGvC,MAAMC,EAAgBld,EAAAA,IAAiB,IAAI,GAAK,EAS1Cmd,EAAqBva,EAAAA,SAAS,IAC3BmR,EAAc,UAAU,IAAKxK,IAAO,CACzC,IAAKA,EAAE,IACP,MAAO,GAAGA,EAAE,OAAO,aAAa,IAAIA,EAAE,IAAI,GAC1C,OAAQA,EAAE,OAAO,YAAA,EACjB,KAAMA,EAAE,KACR,YAAaA,EAAE,WAAA,EACf,CACH,EAKK6T,EAAmBxa,EAAAA,SAAS,IAAM,CACtC,MAAMya,EAAUP,EAAkB,MAAM,KAAA,IAAW,GAC7CQ,EAAYN,EAAiB,QAAU,KAC7C,OAAOK,GAAWC,CACpB,CAAC,EAKK7R,EAAoB7I,EAAAA,SAAS,IAC1Bia,EAAgB,kBAAkB,IAAKU,GAAQ,CACpD,MAAMtR,EAASsR,EAAI,SAAWV,EAAgB,UAAUU,EAAI,QAAQ,EAAI,KACxE,MAAO,CACL,GAAGA,EACH,OAAAtR,CAAA,CAEJ,CAAC,CACF,EAKKuR,EAAkB5a,EAAAA,SAAS,IAAMia,EAAgB,KAAK,EAS5D,SAASY,GAAsB,CAI7B,GAHI,CAACL,EAAiB,OAAS,CAACJ,EAAiB,OAG7C,CADWH,EAAgB,UAAUG,EAAiB,KAAK,EAClD,OAGb,MAAMU,EAAcZ,EAAkB,MAAM,KAAA,EAG5C,GAAI,CAACY,EAAY,WAAW,GAAG,EAAG,CAChCb,EAAgB,SAAS,wBAAwB,EACjD,MACF,CAGA,GAAIa,EAAY,OAAS,IAAK,CAC5Bb,EAAgB,SAAS,uCAAuC,EAChE,MACF,CAGA,GAAI,CAAC,mBAAmB,KAAKa,CAAW,EAAG,CACzCb,EAAgB,SAAS,kCAAkC,EAC3D,MACF,CAGA,MAAMc,EAAiB,GAAGZ,EAAoB,MAAM,aAAa,IAAIW,CAAW,GAC1E3R,EAAa8Q,EAAgB,2BACjCc,EACAX,EAAiB,MACjB,MAAA,EAGGjR,IAGL8Q,EAAgB,mBAAmB9Q,EAAY,EAAI,EACnD8Q,EAAgB,WAAW,EAAI,EAG/B7a,EAAK,CACH,KAAM,iBACN,KAAM,CACJ,KAAM+J,EAAW,KACjB,OAAQA,EAAW,OACnB,MAAOA,EAAW,MAClB,KAAMA,EAAW,IAAA,CACnB,CACD,EAGD+Q,EAAkB,MAAQ,GAC1BE,EAAiB,MAAQ,KACzB1U,EAAoB,MAAQ,KAC9B,CAKA,SAASsV,EAAiBhd,EAAoB,CAE5Cic,EAAgB,sBAAsBjc,EAAM,EAAI,EAChDic,EAAgB,WAAW,EAAI,EAG/B7a,EAAK,CACH,KAAM,mBACN,KAAM,CAAE,KAAApB,CAAA,CAAK,CACd,CACH,CAKA,SAASid,GAA4B,CACnC,GAAIL,EAAgB,QAAU,EAG9B,WAAWzR,KAAc8Q,EAAgB,kBACvCK,EAAc,MAAM,IAAInR,EAAW,IAAI,EAGvC8Q,EAAgB,sBAAsB9Q,EAAW,KAAM,EAAI,EAG3D/J,EAAK,CACH,KAAM,mBACN,KAAM,CAAE,KAAM+J,EAAW,IAAA,CAAK,CAC/B,EAGH8Q,EAAgB,WAAW,EAAI,EAKjC,CAKA,SAASiB,GAA6B,CACpC,GAAI,CAACxV,EAAoB,MAAO,OAEhC,MAAMI,EAAWqL,EAAc,UAAU,KAAMxK,GAAMA,EAAE,MAAQjB,EAAoB,KAAK,EACnFI,IAELqU,EAAoB,MAAQrU,EAAS,OAAO,YAAA,EAC5CoU,EAAkB,MAAQpU,EAAS,KACrC,CAKA,SAASqV,GAA0B,CAEjCzV,EAAoB,MAAQ,IAC9B,CAMAxF,OAAAA,EAAAA,UAAU,IAAM,CAEdma,EAAgB,CACd/a,EAAG,oBAAsBlB,GAAgC,CACvD6b,EAAgB,eAAe7b,EAAK,WAAW,CACjD,CAAC,EAEDkB,EAAG,mBAAqBlB,GAA8B,CACpD6b,EAAgB,sBAAsB7b,CAAI,CAC5C,CAAC,EAEDkB,EAAG,qBAAuBlB,GAA8B,CACtD6b,EAAgB,wBAAwB7b,CAAI,CAC9C,CAAC,EAEDkB,EAAG,sBAAwBlB,GAAkC,CAC3D6b,EAAgB,yBAAyB7b,CAAI,CAC/C,CAAC,EAEDkB,EAAG,iBAAmBlB,GAA6B,CACjD6b,EAAgB,oBAAoB7b,CAAI,CAC1C,CAAC,EAEDkB,EAAG,qBAAuBlB,GAAiC,CAErDkc,EAAc,MAAM,IAAIlc,EAAK,IAAI,GACnCkc,EAAc,MAAM,OAAOlc,EAAK,IAAI,EAItC6b,EAAgB,wBAAwB7b,CAAI,CAC9C,CAAC,CAAA,EAIHgB,EAAK,CAAE,KAAM,eAAgB,CAC/B,CAAC,EAGDwP,EAAAA,YAAY,IAAM,CAChB,UAAWwM,KAASf,EAClBe,EAAA,CAEJ,CAAC,UAIC/Z,YAAA,EAAAC,qBAkJM,MAlJNC,GAkJM,CAhJJC,EAAAA,mBA6EM,MA7ENC,GA6EM,CA5EJD,EAAAA,mBAGM,MAHNE,GAGM,CAFJC,EAAAA,YAAkBC,EAAAA,MAAA3E,EAAA,EAAA,CAAZ,KAAM,GAAE,EACd4E,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAA2B,YAArB,iBAAc,EAAA,EAAA,GAGtBA,EAAAA,mBAsEM,MAtENM,GAsEM,CApEOyY,EAAA,MAAmB,OAAM,GAApClZ,EAAAA,YAAAC,EAAAA,mBAgBM,MAhBNoO,GAgBM,CAfJ7N,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAAwE,QAAA,CAAjE,MAAM,uBAAA,EAAwB,8BAA2B,EAAA,oBAChEA,EAAAA,mBAaS,SAAA,sCAZEkE,EAAmB,MAAAvD,GAC5B,MAAM,QACL,SAAQ+Y,CAAA,GAETrZ,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAA8C,SAAA,CAArC,MAAO,IAAA,EAAM,kBAAe,EAAA,oBACrCF,EAAAA,mBAMSS,EAAAA,SAAA,KAAAC,EAAAA,WALYuY,EAAA,MAAZzU,kBADTxE,EAAAA,mBAMS,SAAA,CAJN,IAAKwE,EAAS,IACd,MAAOA,EAAS,GAAA,EAEdvD,EAAAA,gBAAAuD,EAAS,KAAK,EAAA,EAAAxD,EAAA,iCAVVoD,EAAA,KAAmB,CAAA,kCAgBhClE,EAAAA,mBAiBM,MAjBNgB,GAiBM,kBAhBJhB,EAAAA,mBAQS,SAAA,sCAPE2Y,EAAmB,MAAAhY,GAC5B,MAAM,+BACL,SAAQgZ,CAAA,kBAET7Z,EAAAA,mBAESS,EAAAA,SAAA,KAAAC,aAFgBsP,EAAVjK,GAAf7F,EAAAA,mBAES,SAAA,CAF8B,IAAK6F,EAAS,MAAOA,CAAA,oBACvDA,CAAM,EAAA,EAAA5E,EAAA,+BALF0X,EAAA,KAAmB,CAAA,oBAQ9B3Y,EAAAA,mBAME,QAAA,sCALS0Y,EAAiB,MAAA/X,GAC1B,KAAK,OACL,MAAM,6BACN,YAAY,YACX,QAAOgZ,CAAA,2BAJCjB,EAAA,KAAiB,CAAA,KAS9B1Y,EAAAA,mBAkBM,MAlBNkB,GAkBM,EAjBJrB,EAAAA,UAAA,EAAA,EAAAC,EAAAA,mBAgBSS,EAAAA,SAAA,KAAAC,aAfUJ,EAAAA,MAAAqY,CAAA,EAAgB,QAA1B5Q,kBADT/H,EAAAA,mBAgBS,SAAA,CAdN,IAAK+H,EAAO,GACZ,MAAKnH,EAAAA,eAAA,kDAAoFkY,EAAA,QAAqB/Q,EAAO,EAAA,EAAyC,qBAAAA,EAAO,IAAI,EAAA,GAKzK,MAAOA,EAAO,YACd,QAAKlH,GAAEiY,EAAA,MAAmB/Q,EAAO,EAAA,kBAElCjH,EAAAA,YAGEC,EAAAA,wBAFKgH,EAAO,OAAI,QAAezH,EAAAA,MAAA/F,CAAA,EAAQ+F,EAAAA,MAAAyT,EAAA,CAAa,EAAA,CACnD,KAAM,GAAE,GAEX7T,EAAAA,mBAA+D,OAA/DmO,GAA+DpN,EAAAA,gBAAtB8G,EAAO,KAAK,EAAA,CAAA,CAAA,mBAKzD7H,EAAAA,mBAOS,SAAA,CANP,MAAM,mBACL,SAAQ,CAAGgZ,EAAA,OAAoB5Y,EAAAA,MAAAqY,CAAA,EAAgB,UAC/C,QAAOY,CAAA,GAERlZ,EAAAA,YAAmBC,EAAAA,MAAAxF,EAAA,EAAA,CAAZ,KAAM,GAAE,EACfyF,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAA2B,YAArB,iBAAc,EAAA,EAAA,YAM1BA,EAAAA,mBA+DM,MA/DNqO,GA+DM,CA9DJrO,EAAAA,mBAaM,MAbNsO,GAaM,CAZJtO,qBAEO,OAFPuO,GAAsC,wBAChBxN,EAAAA,gBAAGqY,EAAA,KAAe,EAAG,KAC3C,CAAA,EAEQA,EAAA,MAAe,iBADvBtZ,EAAAA,mBAQS,SAAA,OANP,MAAM,iBACL,SAAUM,EAAAA,MAAAqY,CAAA,EAAgB,UAC1B,QAAOgB,CAAA,GAERtZ,EAAAA,YAAqBC,EAAAA,MAAAhF,EAAA,EAAA,CAAZ,KAAM,GAAE,EACjBiF,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAAsB,YAAhB,YAAS,EAAA,EAAA,uCAInBA,EAAAA,mBA8CM,MA9CNyO,GA8CM,kBA7CJ3O,EAAAA,mBAmCMS,EAAAA,SAAA,KAAAC,EAAAA,WAlCiB6G,EAAA,MAAdM,kBADT7H,EAAAA,mBAmCM,MAAA,CAjCH,IAAK6H,EAAW,KACjB,MAAM,2BAAA,GAEN3H,EAAAA,mBAIM,MAJN0O,GAIM,CAHJ1O,EAAAA,mBAEO,OAFP2O,GAEO5N,EAAAA,gBADF4G,EAAW,IAAI,EAAA,CAAA,CAAA,GAGtB3H,EAAAA,mBAgBM,MAhBN4O,GAgBM,gBAfJhO,EAAAA,YAQEC,0BAPK8G,EAAW,QAAQ,OAAI,QAAevH,EAAAA,MAAA/F,CAAA,EAAQ+F,EAAAA,MAAAyT,EAAA,CAAa,EAAA,CAC/D,KAAM,GACN,MAAKnT,EAAAA,eAAA,gBAAoCiH,EAAW,QAAQ,OAAI,qBAA4CA,EAAW,QAAQ,OAAI,qBAA4CA,EAAW,QAAQ,OAAI,OAAA,uBAMzM3H,EAAAA,mBAEO,OAAA,KAAAe,EAAAA,gBADF4G,EAAW,QAAQ,OAAK,QAAYA,EAAW,MAAM,EAAA,EAAA,CAAA,EAE9CA,EAAW,qBAAvB7H,EAAAA,mBAEO,OAFP+O,GAAiD,uBAC3ClH,EAAW,KAAK,EAAG,OACzB,CAAA,iCAEF3H,EAAAA,mBAOS,SAAA,CANP,MAAM,2BACN,MAAM,oBACL,SAAUI,EAAAA,MAAAqY,CAAA,EAAgB,UAC1B,QAAK9X,GAAE6Y,EAAiB7R,EAAW,IAAI,CAAA,GAExCxH,EAAAA,YAAqBC,EAAAA,MAAAhF,EAAA,EAAA,CAAZ,KAAM,GAAE,CAAA,kBAKVge,EAAA,QAAe,GAA1BvZ,EAAAA,YAAAC,EAAAA,mBAMM,MANNiP,GAMM,CALJ5O,cAA4CC,EAAAA,MAAA3E,EAAA,EAAA,CAAtC,KAAM,GAAI,MAAM,mBAAA,GACtB4E,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAAyD,KAAA,CAArD,MAAM,oBAAA,EAAqB,wBAAqB,EAAA,GACpDK,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAL,EAAAA,mBAEI,IAAA,CAFD,MAAM,4BAA2B,sEAEpC,EAAA,EAAA","x_google_ignoreList":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]}
|
|
1
|
+
{"version":3,"file":"devtools.umd.cjs","sources":["../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/shared/src/utils.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/defaultAttributes.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/Icon.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/createLucideIcon.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/check.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/chevron-down.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/chevron-right.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/chevron-up.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/circle-alert.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/circle-check-big.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/clock.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/code.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/copy.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/database.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/file-json.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/funnel.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/lock.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/plus.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/refresh-cw.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/route.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/save.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/search.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/shield.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/sprout.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/tag.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/trash-2.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/triangle-alert.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/wifi-off.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/wifi.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/x.js","../../../node_modules/.pnpm/lucide-vue-next@0.513.0_vue@3.5.27_typescript@5.9.3_/node_modules/lucide-vue-next/dist/esm/icons/zap.js","../src/composables/useWebSocket.ts","../src/router.ts","../src/App.vue","../src/stores/models.ts","../src/stores/registry.ts","../src/stores/simulation.ts","../src/stores/timeline.ts","../src/composables/useTheme.ts","../src/main.ts","../src/utils/format.ts","../src/components/EndpointDetail.vue","../src/components/EndpointList.vue","../src/pages/RoutesPage.vue","../src/components/TimelineDetail.vue","../src/components/TimelineEntry.vue","../src/pages/TimelinePage.vue","../src/utils/data-table.ts","../src/components/DataTable.vue","../src/components/JsonEditor.vue","../src/composables/useNotifications.ts","../src/pages/ModelsPage.vue","../src/pages/SimulatorPage.vue"],"sourcesContent":["/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, \"$1-$2\").toLowerCase();\nconst toCamelCase = (string) => string.replace(\n /^([A-Z])|[\\s-_]+(\\w)/g,\n (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()\n);\nconst toPascalCase = (string) => {\n const camelCase = toCamelCase(string);\n return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);\n};\nconst mergeClasses = (...classes) => classes.filter((className, index, array) => {\n return Boolean(className) && className.trim() !== \"\" && array.indexOf(className) === index;\n}).join(\" \").trim();\n\nexport { mergeClasses, toCamelCase, toKebabCase, toPascalCase };\n//# sourceMappingURL=utils.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nvar defaultAttributes = {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: 24,\n height: 24,\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n \"stroke-width\": 2,\n \"stroke-linecap\": \"round\",\n \"stroke-linejoin\": \"round\"\n};\n\nexport { defaultAttributes as default };\n//# sourceMappingURL=defaultAttributes.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { h } from 'vue';\nimport { mergeClasses, toKebabCase, toPascalCase } from './shared/src/utils.js';\nimport defaultAttributes from './defaultAttributes.js';\n\nconst Icon = ({ size, strokeWidth = 2, absoluteStrokeWidth, color, iconNode, name, class: classes, ...props }, { slots }) => {\n return h(\n \"svg\",\n {\n ...defaultAttributes,\n width: size || defaultAttributes.width,\n height: size || defaultAttributes.height,\n stroke: color || defaultAttributes.stroke,\n \"stroke-width\": absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,\n class: mergeClasses(\n \"lucide\",\n ...name ? [`lucide-${toKebabCase(toPascalCase(name))}-icon`, `lucide-${toKebabCase(name)}`] : [\"lucide-icon\"]\n ),\n ...props\n },\n [...iconNode.map((child) => h(...child)), ...slots.default ? [slots.default()] : []]\n );\n};\n\nexport { Icon as default };\n//# sourceMappingURL=Icon.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { h } from 'vue';\nimport Icon from './Icon.js';\n\nconst createLucideIcon = (iconName, iconNode) => (props, { slots }) => h(\n Icon,\n {\n ...props,\n iconNode,\n name: iconName\n },\n slots\n);\n\nexport { createLucideIcon as default };\n//# sourceMappingURL=createLucideIcon.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Check = createLucideIcon(\"check\", [[\"path\", { d: \"M20 6 9 17l-5-5\", key: \"1gmf2c\" }]]);\n\nexport { Check as default };\n//# sourceMappingURL=check.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst ChevronDown = createLucideIcon(\"chevron-down\", [\n [\"path\", { d: \"m6 9 6 6 6-6\", key: \"qrunsl\" }]\n]);\n\nexport { ChevronDown as default };\n//# sourceMappingURL=chevron-down.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst ChevronRight = createLucideIcon(\"chevron-right\", [\n [\"path\", { d: \"m9 18 6-6-6-6\", key: \"mthhwq\" }]\n]);\n\nexport { ChevronRight as default };\n//# sourceMappingURL=chevron-right.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst ChevronUp = createLucideIcon(\"chevron-up\", [\n [\"path\", { d: \"m18 15-6-6-6 6\", key: \"153udz\" }]\n]);\n\nexport { ChevronUp as default };\n//# sourceMappingURL=chevron-up.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst CircleAlert = createLucideIcon(\"circle-alert\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"line\", { x1: \"12\", x2: \"12\", y1: \"8\", y2: \"12\", key: \"1pkeuh\" }],\n [\"line\", { x1: \"12\", x2: \"12.01\", y1: \"16\", y2: \"16\", key: \"4dfq90\" }]\n]);\n\nexport { CircleAlert as default };\n//# sourceMappingURL=circle-alert.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst CircleCheckBig = createLucideIcon(\"circle-check-big\", [\n [\"path\", { d: \"M21.801 10A10 10 0 1 1 17 3.335\", key: \"yps3ct\" }],\n [\"path\", { d: \"m9 11 3 3L22 4\", key: \"1pflzl\" }]\n]);\n\nexport { CircleCheckBig as default };\n//# sourceMappingURL=circle-check-big.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Clock = createLucideIcon(\"clock\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"polyline\", { points: \"12 6 12 12 16 14\", key: \"68esgv\" }]\n]);\n\nexport { Clock as default };\n//# sourceMappingURL=clock.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Code = createLucideIcon(\"code\", [\n [\"path\", { d: \"m16 18 6-6-6-6\", key: \"eg8j8\" }],\n [\"path\", { d: \"m8 6-6 6 6 6\", key: \"ppft3o\" }]\n]);\n\nexport { Code as default };\n//# sourceMappingURL=code.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Copy = createLucideIcon(\"copy\", [\n [\"rect\", { width: \"14\", height: \"14\", x: \"8\", y: \"8\", rx: \"2\", ry: \"2\", key: \"17jyea\" }],\n [\"path\", { d: \"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\", key: \"zix9uf\" }]\n]);\n\nexport { Copy as default };\n//# sourceMappingURL=copy.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Database = createLucideIcon(\"database\", [\n [\"ellipse\", { cx: \"12\", cy: \"5\", rx: \"9\", ry: \"3\", key: \"msslwz\" }],\n [\"path\", { d: \"M3 5V19A9 3 0 0 0 21 19V5\", key: \"1wlel7\" }],\n [\"path\", { d: \"M3 12A9 3 0 0 0 21 12\", key: \"mv7ke4\" }]\n]);\n\nexport { Database as default };\n//# sourceMappingURL=database.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst FileJson = createLucideIcon(\"file-json\", [\n [\"path\", { d: \"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\", key: \"1rqfz7\" }],\n [\"path\", { d: \"M14 2v4a2 2 0 0 0 2 2h4\", key: \"tnqrlb\" }],\n [\n \"path\",\n { d: \"M10 12a1 1 0 0 0-1 1v1a1 1 0 0 1-1 1 1 1 0 0 1 1 1v1a1 1 0 0 0 1 1\", key: \"1oajmo\" }\n ],\n [\n \"path\",\n { d: \"M14 18a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1 1 1 0 0 1-1-1v-1a1 1 0 0 0-1-1\", key: \"mpwhp6\" }\n ]\n]);\n\nexport { FileJson as default };\n//# sourceMappingURL=file-json.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Funnel = createLucideIcon(\"funnel\", [\n [\n \"path\",\n {\n d: \"M10 20a1 1 0 0 0 .553.895l2 1A1 1 0 0 0 14 21v-7a2 2 0 0 1 .517-1.341L21.74 4.67A1 1 0 0 0 21 3H3a1 1 0 0 0-.742 1.67l7.225 7.989A2 2 0 0 1 10 14z\",\n key: \"sc7q7i\"\n }\n ]\n]);\n\nexport { Funnel as default };\n//# sourceMappingURL=funnel.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Lock = createLucideIcon(\"lock\", [\n [\"rect\", { width: \"18\", height: \"11\", x: \"3\", y: \"11\", rx: \"2\", ry: \"2\", key: \"1w4ew1\" }],\n [\"path\", { d: \"M7 11V7a5 5 0 0 1 10 0v4\", key: \"fwvmzm\" }]\n]);\n\nexport { Lock as default };\n//# sourceMappingURL=lock.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Plus = createLucideIcon(\"plus\", [\n [\"path\", { d: \"M5 12h14\", key: \"1ays0h\" }],\n [\"path\", { d: \"M12 5v14\", key: \"s699le\" }]\n]);\n\nexport { Plus as default };\n//# sourceMappingURL=plus.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst RefreshCw = createLucideIcon(\"refresh-cw\", [\n [\"path\", { d: \"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8\", key: \"v9h5vc\" }],\n [\"path\", { d: \"M21 3v5h-5\", key: \"1q7to0\" }],\n [\"path\", { d: \"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16\", key: \"3uifl3\" }],\n [\"path\", { d: \"M8 16H3v5\", key: \"1cv678\" }]\n]);\n\nexport { RefreshCw as default };\n//# sourceMappingURL=refresh-cw.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Route = createLucideIcon(\"route\", [\n [\"circle\", { cx: \"6\", cy: \"19\", r: \"3\", key: \"1kj8tv\" }],\n [\"path\", { d: \"M9 19h8.5a3.5 3.5 0 0 0 0-7h-11a3.5 3.5 0 0 1 0-7H15\", key: \"1d8sl\" }],\n [\"circle\", { cx: \"18\", cy: \"5\", r: \"3\", key: \"gq8acd\" }]\n]);\n\nexport { Route as default };\n//# sourceMappingURL=route.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Save = createLucideIcon(\"save\", [\n [\n \"path\",\n {\n d: \"M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z\",\n key: \"1c8476\"\n }\n ],\n [\"path\", { d: \"M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7\", key: \"1ydtos\" }],\n [\"path\", { d: \"M7 3v4a1 1 0 0 0 1 1h7\", key: \"t51u73\" }]\n]);\n\nexport { Save as default };\n//# sourceMappingURL=save.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Search = createLucideIcon(\"search\", [\n [\"path\", { d: \"m21 21-4.34-4.34\", key: \"14j7rj\" }],\n [\"circle\", { cx: \"11\", cy: \"11\", r: \"8\", key: \"4ej97u\" }]\n]);\n\nexport { Search as default };\n//# sourceMappingURL=search.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Shield = createLucideIcon(\"shield\", [\n [\n \"path\",\n {\n d: \"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z\",\n key: \"oel41y\"\n }\n ]\n]);\n\nexport { Shield as default };\n//# sourceMappingURL=shield.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Sprout = createLucideIcon(\"sprout\", [\n [\"path\", { d: \"M7 20h10\", key: \"e6iznv\" }],\n [\"path\", { d: \"M10 20c5.5-2.5.8-6.4 3-10\", key: \"161w41\" }],\n [\n \"path\",\n {\n d: \"M9.5 9.4c1.1.8 1.8 2.2 2.3 3.7-2 .4-3.5.4-4.8-.3-1.2-.6-2.3-1.9-3-4.2 2.8-.5 4.4 0 5.5.8z\",\n key: \"9gtqwd\"\n }\n ],\n [\n \"path\",\n {\n d: \"M14.1 6a7 7 0 0 0-1.1 4c1.9-.1 3.3-.6 4.3-1.4 1-1 1.6-2.3 1.7-4.6-2.7.1-4 1-4.9 2z\",\n key: \"bkxnd2\"\n }\n ]\n]);\n\nexport { Sprout as default };\n//# sourceMappingURL=sprout.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Tag = createLucideIcon(\"tag\", [\n [\n \"path\",\n {\n d: \"M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z\",\n key: \"vktsd0\"\n }\n ],\n [\"circle\", { cx: \"7.5\", cy: \"7.5\", r: \".5\", fill: \"currentColor\", key: \"kqv944\" }]\n]);\n\nexport { Tag as default };\n//# sourceMappingURL=tag.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Trash2 = createLucideIcon(\"trash-2\", [\n [\"path\", { d: \"M3 6h18\", key: \"d0wm0j\" }],\n [\"path\", { d: \"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6\", key: \"4alrt4\" }],\n [\"path\", { d: \"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2\", key: \"v07s0e\" }],\n [\"line\", { x1: \"10\", x2: \"10\", y1: \"11\", y2: \"17\", key: \"1uufr5\" }],\n [\"line\", { x1: \"14\", x2: \"14\", y1: \"11\", y2: \"17\", key: \"xtxkd\" }]\n]);\n\nexport { Trash2 as default };\n//# sourceMappingURL=trash-2.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst TriangleAlert = createLucideIcon(\"triangle-alert\", [\n [\n \"path\",\n {\n d: \"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\",\n key: \"wmoenq\"\n }\n ],\n [\"path\", { d: \"M12 9v4\", key: \"juzpu7\" }],\n [\"path\", { d: \"M12 17h.01\", key: \"p32p05\" }]\n]);\n\nexport { TriangleAlert as default };\n//# sourceMappingURL=triangle-alert.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst WifiOff = createLucideIcon(\"wifi-off\", [\n [\"path\", { d: \"M12 20h.01\", key: \"zekei9\" }],\n [\"path\", { d: \"M8.5 16.429a5 5 0 0 1 7 0\", key: \"1bycff\" }],\n [\"path\", { d: \"M5 12.859a10 10 0 0 1 5.17-2.69\", key: \"1dl1wf\" }],\n [\"path\", { d: \"M19 12.859a10 10 0 0 0-2.007-1.523\", key: \"4k23kn\" }],\n [\"path\", { d: \"M2 8.82a15 15 0 0 1 4.177-2.643\", key: \"1grhjp\" }],\n [\"path\", { d: \"M22 8.82a15 15 0 0 0-11.288-3.764\", key: \"z3jwby\" }],\n [\"path\", { d: \"m2 2 20 20\", key: \"1ooewy\" }]\n]);\n\nexport { WifiOff as default };\n//# sourceMappingURL=wifi-off.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Wifi = createLucideIcon(\"wifi\", [\n [\"path\", { d: \"M12 20h.01\", key: \"zekei9\" }],\n [\"path\", { d: \"M2 8.82a15 15 0 0 1 20 0\", key: \"dnpr2z\" }],\n [\"path\", { d: \"M5 12.859a10 10 0 0 1 14 0\", key: \"1x1e6c\" }],\n [\"path\", { d: \"M8.5 16.429a5 5 0 0 1 7 0\", key: \"1bycff\" }]\n]);\n\nexport { Wifi as default };\n//# sourceMappingURL=wifi.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst X = createLucideIcon(\"x\", [\n [\"path\", { d: \"M18 6 6 18\", key: \"1bl5f8\" }],\n [\"path\", { d: \"m6 6 12 12\", key: \"d8bk6v\" }]\n]);\n\nexport { X as default };\n//# sourceMappingURL=x.js.map\n","/**\n * @license lucide-vue-next v0.513.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Zap = createLucideIcon(\"zap\", [\n [\n \"path\",\n {\n d: \"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z\",\n key: \"1xq2db\"\n }\n ]\n]);\n\nexport { Zap as default };\n//# sourceMappingURL=zap.js.map\n","/**\n * useWebSocket Composable\n *\n * What: Provides reactive WebSocket connection management for the DevTools SPA\n * How: Manages WebSocket lifecycle with auto-reconnect and event subscription\n * Why: Enables real-time communication between DevTools and the mock server\n *\n * @module composables/useWebSocket\n */\n\nimport type { ComputedRef } from 'vue';\nimport { computed, getCurrentInstance, onMounted, ref } from 'vue';\n\n/**\n * Server event types that can be received from the server\n * These match the ServerEvent types defined in @websublime/vite-plugin-open-api-core\n */\nexport type ServerEventType =\n | 'connected'\n | 'request'\n | 'response'\n | 'timeline:cleared'\n | 'store:updated'\n | 'handler:reloaded'\n | 'handlers:updated'\n | 'seed:reloaded'\n | 'seeds:updated'\n | 'simulation:active'\n | 'simulation:added'\n | 'simulation:removed'\n | 'simulations:cleared'\n | 'registry'\n | 'timeline'\n | 'store'\n | 'store:set'\n | 'store:cleared'\n | 'simulation:set'\n | 'simulation:cleared'\n | 'reseeded'\n | 'error';\n\n/**\n * Server event structure\n */\nexport interface ServerEvent<T = unknown> {\n type: ServerEventType;\n data: T;\n}\n\n/**\n * Connected event data\n */\nexport interface ConnectedEventData {\n serverVersion: string;\n}\n\n/**\n * Client command types that can be sent to the server\n */\nexport type ClientCommandType =\n | 'get:registry'\n | 'get:timeline'\n | 'get:store'\n | 'set:store'\n | 'clear:store'\n | 'set:simulation'\n | 'clear:simulation'\n | 'clear:timeline'\n | 'reseed';\n\n/**\n * Client command structure\n */\nexport interface ClientCommand<T = unknown> {\n type: ClientCommandType;\n data?: T;\n}\n\n/**\n * WebSocket connection state\n */\nexport type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting';\n\n/**\n * Event handler function type\n */\nexport type EventHandler<T = unknown> = (data: T) => void;\n\n/**\n * Configuration options for useWebSocket\n */\nexport interface UseWebSocketOptions {\n /**\n * WebSocket URL path (default: '/_ws')\n */\n path?: string;\n\n /**\n * Reconnection delay in milliseconds (default: 2000)\n */\n reconnectDelay?: number;\n\n /**\n * Maximum reconnection attempts (default: Infinity)\n */\n maxReconnectAttempts?: number;\n\n /**\n * Whether to auto-connect on mount (default: true)\n */\n autoConnect?: boolean;\n}\n\n/**\n * Return type for useWebSocket composable\n *\n * Provides explicit typing for the composable return value as required by CLAUDE.md\n */\nexport interface UseWebSocketReturn {\n /** Current connection state */\n connectionState: ComputedRef<ConnectionState>;\n /** Whether the WebSocket is connected */\n connected: ComputedRef<boolean>;\n /** Whether the WebSocket is attempting to reconnect */\n isReconnecting: ComputedRef<boolean>;\n /** Server version received on connection */\n serverVersion: ComputedRef<string | null>;\n /** Number of reconnection attempts made */\n reconnectAttempts: ComputedRef<number>;\n /** Connect to the WebSocket server */\n connect: () => void;\n /** Disconnect from the WebSocket server */\n disconnect: () => void;\n /** Send a command to the server */\n send: <T = unknown>(command: ClientCommand<T>) => boolean;\n /** Subscribe to a server event */\n on: <T = unknown>(event: ServerEventType | '*', handler: EventHandler<T>) => () => void;\n /** Unsubscribe from a server event */\n off: <T = unknown>(event: ServerEventType | '*', handler: EventHandler<T>) => void;\n /**\n * Subscribe to an event and automatically unsubscribe after the first invocation.\n * This is a standard one-shot subscription.\n */\n once: <T = unknown>(event: ServerEventType | '*', handler: EventHandler<T>) => () => void;\n /**\n * Subscribe to an event and unsubscribe when the handler returns true.\n * Useful for conditional one-time events where you need to wait for specific data.\n */\n onUntil: <T = unknown>(\n event: ServerEventType | '*',\n handler: (data: T) => boolean | undefined,\n ) => () => void;\n /** Reset the composable state (useful for testing) */\n resetState: () => void;\n}\n\n/**\n * Default options\n */\nconst DEFAULT_OPTIONS: Required<UseWebSocketOptions> = {\n path: '/_ws',\n reconnectDelay: 2000,\n maxReconnectAttempts: Number.POSITIVE_INFINITY,\n autoConnect: true,\n};\n\n/**\n * Singleton state for WebSocket - shared across all component instances\n */\nconst connectionState = ref<ConnectionState>('disconnected');\nconst serverVersion = ref<string | null>(null);\nconst reconnectAttempts = ref(0);\n\n/**\n * Store the WebSocket instance and configuration\n */\nlet ws: WebSocket | null = null;\nlet reconnectTimer: ReturnType<typeof setTimeout> | null = null;\nlet currentOptions: Required<UseWebSocketOptions> = { ...DEFAULT_OPTIONS };\n\n/**\n * Flag to track if options have been initialized\n * Options are only set on the first call to useWebSocket or when disconnected\n */\nlet optionsInitialized = false;\n\n/**\n * Event handlers map - stores handlers for each event type\n */\nconst eventHandlers = new Map<string, Set<EventHandler>>();\n\n/**\n * Check if we're running in a browser environment\n */\nfunction isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof WebSocket !== 'undefined';\n}\n\n/**\n * Check if we're inside a Vue component context\n */\nfunction hasComponentContext(): boolean {\n return getCurrentInstance() !== null;\n}\n\n/**\n * Build the WebSocket URL based on current location\n */\nfunction buildWebSocketUrl(path: string): string {\n if (!isBrowser()) {\n return `ws://localhost${path}`;\n }\n\n const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';\n return `${protocol}//${window.location.host}${path}`;\n}\n\n/**\n * Clear the reconnect timer if active\n */\nfunction clearReconnectTimer(): void {\n if (reconnectTimer !== null) {\n clearTimeout(reconnectTimer);\n reconnectTimer = null;\n }\n}\n\n/**\n * Dispatch an event to all registered handlers\n */\nfunction dispatchEvent(type: string, data: unknown): void {\n const handlers = eventHandlers.get(type);\n if (handlers) {\n for (const handler of handlers) {\n try {\n handler(data);\n } catch (error) {\n console.error(`[DevTools WebSocket] Error in event handler for '${type}':`, error);\n }\n }\n }\n\n // Also dispatch to wildcard handlers\n const wildcardHandlers = eventHandlers.get('*');\n if (wildcardHandlers) {\n for (const handler of wildcardHandlers) {\n try {\n handler({ type, data });\n } catch (error) {\n console.error('[DevTools WebSocket] Error in wildcard event handler:', error);\n }\n }\n }\n}\n\n/**\n * Handle WebSocket open event\n */\nfunction handleOpen(): void {\n connectionState.value = 'connected';\n reconnectAttempts.value = 0;\n clearReconnectTimer();\n\n if (import.meta.env.DEV) {\n console.log('[DevTools WebSocket] Connected');\n }\n}\n\n/**\n * Handle WebSocket message event\n */\nfunction handleMessage(event: MessageEvent): void {\n try {\n const message = JSON.parse(event.data) as ServerEvent;\n\n // Handle connected event specially to extract server version\n if (message.type === 'connected') {\n const connectedData = message.data as ConnectedEventData;\n serverVersion.value = connectedData.serverVersion;\n\n if (import.meta.env.DEV) {\n console.log(`[DevTools WebSocket] Server version: ${connectedData.serverVersion}`);\n }\n }\n\n // Dispatch to registered handlers\n dispatchEvent(message.type, message.data);\n } catch (error) {\n console.error('[DevTools WebSocket] Failed to parse message:', error);\n }\n}\n\n/**\n * Handle WebSocket close event\n */\nfunction handleClose(): void {\n const wasConnected = connectionState.value === 'connected';\n connectionState.value = 'disconnected';\n ws = null;\n\n if (wasConnected && import.meta.env.DEV) {\n console.log('[DevTools WebSocket] Disconnected');\n }\n\n // Attempt to reconnect if within limits\n if (reconnectAttempts.value < currentOptions.maxReconnectAttempts) {\n connectionState.value = 'reconnecting';\n reconnectAttempts.value++;\n\n if (import.meta.env.DEV) {\n console.log(\n `[DevTools WebSocket] Reconnecting in ${currentOptions.reconnectDelay}ms (attempt ${reconnectAttempts.value})`,\n );\n }\n\n reconnectTimer = setTimeout(() => {\n connect();\n }, currentOptions.reconnectDelay);\n } else if (import.meta.env.DEV) {\n console.warn('[DevTools WebSocket] Max reconnection attempts reached');\n }\n}\n\n/**\n * Handle WebSocket error event\n */\nfunction handleError(event: Event): void {\n console.error('[DevTools WebSocket] Error:', event);\n}\n\n/**\n * Connect to the WebSocket server\n */\nfunction connect(): void {\n if (!isBrowser()) {\n if (import.meta.env.DEV) {\n console.warn('[DevTools WebSocket] Cannot connect outside browser environment');\n }\n return;\n }\n\n // Don't connect if already connected or connecting\n // Check connectionState first to prevent race condition when connect() is called rapidly\n if (\n connectionState.value === 'connecting' ||\n connectionState.value === 'connected' ||\n (ws && (ws.readyState === WebSocket.CONNECTING || ws.readyState === WebSocket.OPEN))\n ) {\n return;\n }\n\n // Clean up existing connection without resetting reconnect state\n cleanupConnection();\n\n connectionState.value = 'connecting';\n const url = buildWebSocketUrl(currentOptions.path);\n\n try {\n ws = new WebSocket(url);\n ws.onopen = handleOpen;\n ws.onmessage = handleMessage;\n ws.onclose = handleClose;\n ws.onerror = handleError;\n } catch (error) {\n console.error('[DevTools WebSocket] Failed to create WebSocket:', error);\n connectionState.value = 'disconnected';\n }\n}\n\n/**\n * Clean up WebSocket connection without resetting reconnect state.\n * Used internally when reconnecting.\n */\nfunction cleanupConnection(): void {\n if (ws) {\n // Remove event handlers to prevent close handler from triggering reconnect\n ws.onopen = null;\n ws.onmessage = null;\n ws.onclose = null;\n ws.onerror = null;\n\n if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {\n ws.close();\n }\n\n ws = null;\n }\n}\n\n/**\n * Disconnect from the WebSocket server\n */\nfunction disconnect(): void {\n clearReconnectTimer();\n cleanupConnection();\n\n connectionState.value = 'disconnected';\n reconnectAttempts.value = 0;\n}\n\n/**\n * Send a command to the server\n *\n * @param command - The command to send\n * @returns true if the command was sent, false otherwise\n */\nfunction send<T = unknown>(command: ClientCommand<T>): boolean {\n if (!ws || ws.readyState !== WebSocket.OPEN) {\n if (import.meta.env.DEV) {\n console.warn('[DevTools WebSocket] Cannot send command - not connected');\n }\n return false;\n }\n\n try {\n ws.send(JSON.stringify(command));\n return true;\n } catch (error) {\n console.error('[DevTools WebSocket] Failed to send command:', error);\n return false;\n }\n}\n\n/**\n * Subscribe to a server event\n *\n * @param event - The event type to subscribe to (or '*' for all events)\n * @param handler - The handler function to call when the event is received\n * @returns An unsubscribe function\n */\nfunction on<T = unknown>(event: ServerEventType | '*', handler: EventHandler<T>): () => void {\n if (!eventHandlers.has(event)) {\n eventHandlers.set(event, new Set());\n }\n\n const handlers = eventHandlers.get(event);\n if (handlers) {\n handlers.add(handler as EventHandler);\n }\n\n // Return unsubscribe function\n return () => {\n const currentHandlers = eventHandlers.get(event);\n if (currentHandlers) {\n currentHandlers.delete(handler as EventHandler);\n if (currentHandlers.size === 0) {\n eventHandlers.delete(event);\n }\n }\n };\n}\n\n/**\n * Unsubscribe from a server event\n *\n * @param event - The event type to unsubscribe from\n * @param handler - The handler function to remove\n */\nfunction off<T = unknown>(event: ServerEventType | '*', handler: EventHandler<T>): void {\n const handlers = eventHandlers.get(event);\n if (handlers) {\n handlers.delete(handler as EventHandler);\n if (handlers.size === 0) {\n eventHandlers.delete(event);\n }\n }\n}\n\n/**\n * Subscribe to an event and automatically unsubscribe after the first invocation.\n * This is a standard one-shot subscription - the handler is called exactly once.\n *\n * @param event - The event type to subscribe to\n * @param handler - The handler function to call once\n * @returns An unsubscribe function (can be used to cancel before the event fires)\n *\n * @example\n * ```typescript\n * // Wait for the first 'connected' event\n * once('connected', (data) => {\n * console.log('Connected with version:', data.serverVersion);\n * });\n * ```\n */\nfunction once<T = unknown>(event: ServerEventType | '*', handler: EventHandler<T>): () => void {\n const wrappedHandler: EventHandler<T> = (data) => {\n off(event, wrappedHandler);\n handler(data);\n };\n\n return on(event, wrappedHandler);\n}\n\n/**\n * Subscribe to an event and unsubscribe when the handler returns true.\n * Useful for conditional one-time events where you need to wait for specific data.\n *\n * @param event - The event type to subscribe to\n * @param handler - The handler function that returns true to unsubscribe\n * @returns An unsubscribe function\n *\n * @example\n * ```typescript\n * // Wait until we receive a response with status 200\n * onUntil('response', (data) => {\n * if (data.status === 200) {\n * console.log('Success response received');\n * return true; // Unsubscribe\n * }\n * return false; // Keep listening\n * });\n * ```\n */\nfunction onUntil<T = unknown>(\n event: ServerEventType | '*',\n handler: (data: T) => boolean | undefined,\n): () => void {\n const wrappedHandler: EventHandler<T> = (data) => {\n const result = handler(data);\n if (result === true) {\n off(event, wrappedHandler);\n }\n };\n\n return on(event, wrappedHandler);\n}\n\n/**\n * Reset the composable state (useful for testing)\n */\nfunction resetState(): void {\n disconnect();\n serverVersion.value = null;\n eventHandlers.clear();\n currentOptions = { ...DEFAULT_OPTIONS };\n optionsInitialized = false;\n}\n\n/**\n * useWebSocket composable\n *\n * Provides WebSocket connection management functionality including:\n * - Reactive connection state\n * - Auto-reconnect with configurable delay\n * - Event subscription system\n * - Command sending\n *\n * @param options - Configuration options\n * @returns WebSocket management utilities\n */\nexport function useWebSocket(options: UseWebSocketOptions = {}): UseWebSocketReturn {\n // Only merge options when not connected and not initialized, or when disconnected\n // This prevents race conditions when multiple components pass different options\n if (!optionsInitialized || connectionState.value === 'disconnected') {\n currentOptions = { ...DEFAULT_OPTIONS, ...options };\n optionsInitialized = true;\n }\n\n /**\n * Computed property indicating if the WebSocket is connected\n */\n const connected = computed(() => connectionState.value === 'connected');\n\n /**\n * Computed property indicating if the WebSocket is attempting to reconnect\n */\n const isReconnecting = computed(() => connectionState.value === 'reconnecting');\n\n // Note: We don't disconnect on component unmount because this is singleton state\n // and other components may still be using the connection.\n // The connection will be cleaned up when the page unloads.\n\n // Only register lifecycle hooks when inside a Vue component context\n if (hasComponentContext()) {\n onMounted(() => {\n if (currentOptions.autoConnect) {\n connect();\n }\n });\n }\n\n return {\n /**\n * Current connection state\n */\n connectionState: computed(() => connectionState.value),\n\n /**\n * Whether the WebSocket is connected\n */\n connected,\n\n /**\n * Whether the WebSocket is attempting to reconnect\n */\n isReconnecting,\n\n /**\n * Server version received on connection\n */\n serverVersion: computed(() => serverVersion.value),\n\n /**\n * Number of reconnection attempts made\n */\n reconnectAttempts: computed(() => reconnectAttempts.value),\n\n /**\n * Connect to the WebSocket server\n */\n connect,\n\n /**\n * Disconnect from the WebSocket server\n */\n disconnect,\n\n /**\n * Send a command to the server\n */\n send,\n\n /**\n * Subscribe to a server event\n */\n on,\n\n /**\n * Unsubscribe from a server event\n */\n off,\n\n /**\n * Subscribe to an event once (one-shot, auto-unsubscribes after first call)\n */\n once,\n\n /**\n * Subscribe to an event until handler returns true\n */\n onUntil,\n\n /**\n * Reset the composable state (useful for testing)\n */\n resetState,\n };\n}\n","/**\n * Vue Router Configuration\n *\n * What: Defines routing configuration for the DevTools SPA\n * How: Creates routes for each main page/tab in the application\n * Why: Enables navigation between different DevTools features\n */\n\nimport { createRouter, createWebHashHistory, type RouteRecordRaw } from 'vue-router';\n\n/**\n * Route definitions for the DevTools SPA\n *\n * Each route corresponds to a tab in the DevTools interface:\n * - Routes: Endpoint listing and details\n * - Timeline: Request/response log with real-time updates\n * - Models: Store data editor for viewing/modifying mock data\n * - Simulator: Error simulation controls\n */\nconst routes: RouteRecordRaw[] = [\n {\n path: '/',\n redirect: '/routes',\n },\n {\n path: '/routes',\n name: 'routes',\n component: () => import('@/pages/RoutesPage.vue'),\n meta: {\n title: 'Routes',\n icon: 'route',\n },\n },\n {\n path: '/timeline',\n name: 'timeline',\n component: () => import('@/pages/TimelinePage.vue'),\n meta: {\n title: 'Timeline',\n icon: 'clock',\n },\n },\n {\n path: '/models',\n name: 'models',\n component: () => import('@/pages/ModelsPage.vue'),\n meta: {\n title: 'Models',\n icon: 'database',\n },\n },\n {\n path: '/simulator',\n name: 'simulator',\n component: () => import('@/pages/SimulatorPage.vue'),\n meta: {\n title: 'Simulator',\n icon: 'zap',\n },\n },\n // Catch-all route for undefined paths - redirects to routes page\n {\n path: '/:pathMatch(.*)*',\n name: 'not-found',\n redirect: '/routes',\n },\n];\n\n/**\n * Create the router instance\n *\n * Uses hash history mode for compatibility when embedded in iframes\n * or served from arbitrary paths in the dev server\n */\nconst router = createRouter({\n history: createWebHashHistory(),\n routes,\n});\n\nexport { routes };\nexport default router;\n","<!--\n App.vue - Main Application Component\n\n What: Root component for the DevTools SPA\n How: Provides the main layout with header, tab navigation, and router view\n Why: Acts as the entry point for the Vue application and defines the overall structure\n-->\n\n<script setup lang=\"ts\">\nimport { Clock, Database, Route, Wifi, WifiOff, Zap } from 'lucide-vue-next';\nimport { computed } from 'vue';\nimport { useRoute, useRouter } from 'vue-router';\nimport { useWebSocket } from '@/composables/useWebSocket';\nimport { routes } from '@/router';\n\nconst route = useRoute();\nconst router = useRouter();\n\n// Navigation tabs derived from routes\nconst tabs = computed(() =>\n routes\n .filter((r) => r.name && r.meta?.title)\n .map((r) => ({\n name: r.name as string,\n path: r.path,\n title: r.meta?.title as string,\n icon: r.meta?.icon as string,\n })),\n);\n\n// Current active tab\nconst activeTab = computed(() => route.name as string);\n\n// Navigate to a tab\nfunction navigateTo(path: string): void {\n router.push(path);\n}\n\n// Icon component map\nconst iconMap: Record<string, typeof Route> = {\n route: Route,\n clock: Clock,\n database: Database,\n zap: Zap,\n};\n\n// Get icon with fallback for unknown icon names\nfunction getIcon(iconName: string): typeof Route {\n const icon = iconMap[iconName];\n if (!icon && import.meta.env.DEV) {\n console.warn(`[DevTools] Unknown icon name: \"${iconName}\". Using fallback.`);\n }\n return icon ?? Route;\n}\n\n// Connection status from WebSocket composable\nconst { connected: isConnected } = useWebSocket();\n</script>\n\n<template>\n <div class=\"app\">\n <!-- Header with branding and connection status -->\n <header class=\"app-header\">\n <div class=\"app-header__brand\">\n <Zap class=\"app-header__logo\" :size=\"20\" />\n <span class=\"app-header__title\">OpenAPI DevTools</span>\n </div>\n\n <!-- Tab Navigation -->\n <nav class=\"app-nav\" role=\"tablist\" aria-label=\"DevTools navigation\">\n <button\n v-for=\"tab in tabs\"\n :key=\"tab.name\"\n role=\"tab\"\n :aria-selected=\"activeTab === tab.name\"\n :aria-current=\"activeTab === tab.name ? 'true' : undefined\"\n :aria-controls=\"`panel-${tab.name}`\"\n :tabindex=\"0\"\n :class=\"[\n 'app-nav__tab',\n { 'app-nav__tab--active': activeTab === tab.name },\n ]\"\n @click=\"navigateTo(tab.path)\"\n >\n <component\n :is=\"getIcon(tab.icon)\"\n :size=\"16\"\n class=\"app-nav__icon\"\n />\n <span class=\"app-nav__label\">{{ tab.title }}</span>\n </button>\n </nav>\n\n <!-- Connection Status -->\n <div class=\"app-header__status\">\n <div class=\"connection-status\">\n <span\n :class=\"[\n 'connection-status__dot',\n isConnected\n ? 'connection-status__dot--connected'\n : 'connection-status__dot--disconnected',\n ]\"\n />\n <span class=\"connection-status__text\">\n {{ isConnected ? 'Connected' : 'Disconnected' }}\n </span>\n <component\n :is=\"isConnected ? Wifi : WifiOff\"\n :size=\"14\"\n class=\"connection-status__icon\"\n />\n </div>\n </div>\n </header>\n\n <!-- Main Content Area -->\n <main class=\"app-main\">\n <router-view v-slot=\"{ Component }\">\n <transition name=\"fade\" mode=\"out-in\">\n <component :is=\"Component\" />\n </transition>\n </router-view>\n </main>\n </div>\n</template>\n\n<style scoped>\n.app {\n display: flex;\n flex-direction: column;\n height: 100%;\n background-color: var(--devtools-bg);\n}\n\n/* Header styles */\n.app-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n height: var(--devtools-header-height);\n padding: 0 var(--devtools-space-md);\n background-color: var(--devtools-surface);\n border-bottom: 1px solid var(--devtools-border);\n position: sticky;\n top: 0;\n z-index: 100;\n}\n\n.app-header__brand {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n}\n\n.app-header__logo {\n color: var(--devtools-primary);\n}\n\n.app-header__title {\n font-weight: var(--font-weight-6);\n font-size: var(--font-size-1);\n color: var(--devtools-text);\n}\n\n.app-header__status {\n display: flex;\n align-items: center;\n}\n\n/* Navigation styles */\n.app-nav {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n height: 100%;\n}\n\n.app-nav__tab {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n height: 100%;\n padding: 0 var(--devtools-space-md);\n background: none;\n border: none;\n border-bottom: 2px solid transparent;\n color: var(--devtools-text-muted);\n font-family: var(--devtools-font-sans);\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.app-nav__tab:hover {\n color: var(--devtools-text);\n background-color: var(--devtools-surface-elevated);\n}\n\n.app-nav__tab:focus {\n outline: none;\n}\n\n.app-nav__tab:focus-visible {\n outline: 2px solid var(--devtools-primary);\n outline-offset: -2px;\n background-color: var(--devtools-surface-elevated);\n}\n\n/* High contrast mode support */\n@media (forced-colors: active) {\n .app-nav__tab:focus-visible {\n outline: 3px solid CanvasText;\n outline-offset: 2px;\n }\n}\n\n.app-nav__tab--active {\n color: var(--devtools-primary);\n border-bottom-color: var(--devtools-primary);\n}\n\n.app-nav__tab--active:focus-visible {\n outline-color: var(--devtools-primary-hover);\n}\n\n.app-nav__icon {\n flex-shrink: 0;\n}\n\n.app-nav__label {\n white-space: nowrap;\n}\n\n/* Connection status styles */\n.connection-status {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n}\n\n.connection-status__icon {\n opacity: 0.7;\n}\n\n/* Main content styles */\n.app-main {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n</style>\n\n<style>\n/* Page transition - must be unscoped to apply to router-view children */\n.fade-enter-active,\n.fade-leave-active {\n transition: opacity var(--devtools-transition-normal);\n}\n\n.fade-enter-from,\n.fade-leave-to {\n opacity: 0;\n}\n</style>\n","/**\n * Models Store - Store Data Management\n *\n * What: Manages in-memory store data for viewing and editing mock data\n * How: Fetches data from /_api/store endpoints and sends WebSocket commands\n * Why: Provides centralized state management for the Models page\n *\n * API Endpoints Used:\n * - GET /_api/store - List all schemas\n * - GET /_api/store/:schema - Get items for a schema\n * - POST /_api/store/:schema - Bulk replace items\n * - DELETE /_api/store/:schema - Clear schema data\n *\n * WebSocket Commands:\n * - reseed - Trigger reseed of all schemas\n */\n\nimport { defineStore } from 'pinia';\nimport type { ComputedRef, Ref } from 'vue';\nimport { computed, ref, toRaw } from 'vue';\n\n/**\n * Safe clone helper that handles Vue reactive/proxy values\n * Attempts structuredClone with toRaw, falls back to JSON serialization\n */\nfunction safeClone<T>(value: T): T {\n try {\n return structuredClone(toRaw(value));\n } catch {\n return JSON.parse(JSON.stringify(value)) as T;\n }\n}\n\n/**\n * Schema metadata from the server\n */\nexport interface SchemaInfo {\n /** Schema name from OpenAPI components */\n name: string;\n /** Number of items in the store for this schema */\n count: number;\n /** ID field name for this schema */\n idField: string;\n}\n\n/**\n * Schema data response from the server\n */\nexport interface SchemaData {\n /** Schema name */\n schema: string;\n /** Number of items */\n count: number;\n /** ID field name */\n idField: string;\n /** Array of data items */\n items: unknown[];\n}\n\n/**\n * Store state data\n */\nexport interface ModelsData {\n /** List of available schemas */\n schemas: SchemaInfo[];\n /** Currently selected schema name */\n selectedSchema: string | null;\n /** Items for the currently selected schema */\n currentItems: unknown[];\n /** Loading state */\n loading: boolean;\n /** Error message if any */\n error: string | null;\n /** Editing state - whether data has been modified */\n isDirty: boolean;\n}\n\n/**\n * Models store for managing store data\n */\nexport const useModelsStore = defineStore('models', () => {\n // ==========================================================================\n // State\n // ==========================================================================\n\n /** List of available schemas with metadata */\n const schemas: Ref<SchemaInfo[]> = ref([]);\n\n /** Currently selected schema name */\n const selectedSchema: Ref<string | null> = ref(null);\n\n /** Items for the currently selected schema */\n const currentItems: Ref<unknown[]> = ref([]);\n\n /** Original items (before editing) for dirty detection */\n const originalItems: Ref<unknown[]> = ref([]);\n\n /** Loading state */\n const loading: Ref<boolean> = ref(false);\n\n /** Error message */\n const error: Ref<string | null> = ref(null);\n\n // ==========================================================================\n // Computed\n // ==========================================================================\n\n /**\n * Currently selected schema metadata\n */\n const currentSchema: ComputedRef<SchemaInfo | null> = computed(() => {\n if (!selectedSchema.value) return null;\n return schemas.value.find((s) => s.name === selectedSchema.value) ?? null;\n });\n\n /**\n * Dirty state flag - updated by functions that mutate state\n */\n const isDirtyFlag: Ref<boolean> = ref(false);\n\n /**\n * Whether the current data has been modified\n */\n const isDirty: ComputedRef<boolean> = computed(() => isDirtyFlag.value);\n\n /**\n * Total number of schemas\n */\n const schemaCount: ComputedRef<number> = computed(() => schemas.value.length);\n\n /**\n * Total number of items across all schemas\n */\n const totalItems: ComputedRef<number> = computed(() => {\n return schemas.value.reduce((sum, schema) => sum + schema.count, 0);\n });\n\n // ==========================================================================\n // Actions\n // ==========================================================================\n\n /**\n * Fetch the list of schemas from the server\n */\n async function fetchSchemas(): Promise<void> {\n loading.value = true;\n error.value = null;\n\n try {\n const response = await fetch('/_api/store');\n if (!response.ok) {\n throw new Error(`Failed to fetch schemas: ${response.statusText}`);\n }\n\n const data = await response.json();\n schemas.value = data.schemas ?? [];\n } catch (err) {\n error.value = err instanceof Error ? err.message : 'Failed to fetch schemas';\n console.error('[ModelsStore] Error fetching schemas:', err);\n } finally {\n loading.value = false;\n }\n }\n\n /**\n * Select a schema and fetch its data\n */\n async function selectSchemaByName(schemaName: string): Promise<void> {\n if (selectedSchema.value === schemaName) return;\n\n selectedSchema.value = schemaName;\n await fetchSchemaData(schemaName);\n }\n\n /**\n * Fetch data for a specific schema\n */\n async function fetchSchemaData(schemaName: string): Promise<void> {\n loading.value = true;\n error.value = null;\n\n try {\n const response = await fetch(`/_api/store/${encodeURIComponent(schemaName)}`);\n if (!response.ok) {\n throw new Error(`Failed to fetch schema data: ${response.statusText}`);\n }\n\n const data: SchemaData = await response.json();\n const items = data.items ?? [];\n // Clone items to avoid shared references between current and original\n currentItems.value = safeClone(items);\n originalItems.value = safeClone(items);\n isDirtyFlag.value = false;\n\n // Update schema count in the list\n const schemaIndex = schemas.value.findIndex((s) => s.name === schemaName);\n if (schemaIndex !== -1) {\n schemas.value[schemaIndex].count = data.count;\n }\n } catch (err) {\n error.value = err instanceof Error ? err.message : 'Failed to fetch schema data';\n console.error('[ModelsStore] Error fetching schema data:', err);\n } finally {\n loading.value = false;\n }\n }\n\n /**\n * Update the current items (for editing)\n */\n function updateItems(items: unknown): void {\n // Validate that items is an array\n if (!Array.isArray(items)) {\n error.value = 'Invalid data: Expected an array of items';\n console.error('[ModelsStore] updateItems received non-array value:', typeof items);\n return;\n }\n\n currentItems.value = items;\n // Clear any previous validation errors\n error.value = null;\n // Mark as dirty since items were updated\n isDirtyFlag.value = true;\n }\n\n /**\n * Save the current items to the server\n */\n async function saveItems(): Promise<boolean> {\n if (!selectedSchema.value) {\n error.value = 'No schema selected';\n return false;\n }\n\n loading.value = true;\n error.value = null;\n\n try {\n const response = await fetch(`/_api/store/${encodeURIComponent(selectedSchema.value)}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(currentItems.value),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new Error(errorData.error || `Failed to save items: ${response.statusText}`);\n }\n\n const result = await response.json();\n\n // Update original items to match saved items\n originalItems.value = safeClone(currentItems.value);\n isDirtyFlag.value = false;\n\n // Update schema count\n const schemaIndex = schemas.value.findIndex((s) => s.name === selectedSchema.value);\n if (schemaIndex !== -1) {\n schemas.value[schemaIndex].count = result.created ?? currentItems.value.length;\n }\n\n return true;\n } catch (err) {\n error.value = err instanceof Error ? err.message : 'Failed to save items';\n console.error('[ModelsStore] Error saving items:', err);\n return false;\n } finally {\n loading.value = false;\n }\n }\n\n /**\n * Clear all items for the current schema\n */\n async function clearSchema(): Promise<boolean> {\n if (!selectedSchema.value) {\n error.value = 'No schema selected';\n return false;\n }\n\n loading.value = true;\n error.value = null;\n\n try {\n const response = await fetch(`/_api/store/${encodeURIComponent(selectedSchema.value)}`, {\n method: 'DELETE',\n });\n\n if (!response.ok) {\n throw new Error(`Failed to clear schema: ${response.statusText}`);\n }\n\n // Update local state\n currentItems.value = [];\n originalItems.value = [];\n isDirtyFlag.value = false;\n\n // Update schema count\n const schemaIndex = schemas.value.findIndex((s) => s.name === selectedSchema.value);\n if (schemaIndex !== -1) {\n schemas.value[schemaIndex].count = 0;\n }\n\n return true;\n } catch (err) {\n error.value = err instanceof Error ? err.message : 'Failed to clear schema';\n console.error('[ModelsStore] Error clearing schema:', err);\n return false;\n } finally {\n loading.value = false;\n }\n }\n\n /**\n * Discard changes and revert to original items\n */\n function discardChanges(): void {\n currentItems.value = safeClone(originalItems.value);\n isDirtyFlag.value = false;\n }\n\n /**\n * Refresh the current schema data from the server\n */\n async function refresh(): Promise<void> {\n if (selectedSchema.value) {\n await fetchSchemaData(selectedSchema.value);\n } else {\n await fetchSchemas();\n }\n }\n\n /**\n * Reset the store state\n */\n function reset(): void {\n schemas.value = [];\n selectedSchema.value = null;\n currentItems.value = [];\n originalItems.value = [];\n loading.value = false;\n error.value = null;\n isDirtyFlag.value = false;\n }\n\n /**\n * Handle store update from WebSocket event\n */\n function handleStoreUpdate(data: { schema: string; action: string; count: number }): void {\n const schemaIndex = schemas.value.findIndex((s) => s.name === data.schema);\n if (schemaIndex !== -1) {\n schemas.value[schemaIndex].count = data.count;\n }\n\n // If the updated schema is currently selected, refresh it only if no unsaved changes\n if (selectedSchema.value === data.schema) {\n if (!isDirty.value) {\n fetchSchemaData(data.schema);\n } else {\n // Don't auto-refresh when there are unsaved changes\n console.warn(\n `[ModelsStore] Skipping auto-refresh for schema \"${data.schema}\" - unsaved changes exist`,\n );\n }\n }\n }\n\n /**\n * Handle reseed completion from WebSocket event\n */\n function handleReseedComplete(data: { success: boolean; schemas: string[] }): void {\n if (data.success) {\n // Refresh schema list\n fetchSchemas();\n\n // Refresh current schema data only if no unsaved changes\n if (selectedSchema.value) {\n if (!isDirty.value) {\n fetchSchemaData(selectedSchema.value);\n } else {\n console.warn(\n `[ModelsStore] Skipping auto-refresh after reseed for schema \"${selectedSchema.value}\" - unsaved changes exist`,\n );\n }\n }\n }\n }\n\n // ==========================================================================\n // Return store interface\n // ==========================================================================\n\n return {\n // State\n schemas,\n selectedSchema,\n currentItems,\n loading,\n error,\n\n // Computed\n currentSchema,\n isDirty,\n schemaCount,\n totalItems,\n\n // Actions\n fetchSchemas,\n selectSchemaByName,\n fetchSchemaData,\n updateItems,\n saveItems,\n clearSchema,\n discardChanges,\n refresh,\n reset,\n handleStoreUpdate,\n handleReseedComplete,\n };\n});\n\nexport type ModelsStore = ReturnType<typeof useModelsStore>;\n","/**\n * Registry Store\n *\n * What: Pinia store for managing endpoint registry data\n * How: Fetches and caches endpoint data from the server via WebSocket\n * Why: Provides reactive access to endpoint data for the Routes Page\n *\n * @module stores/registry\n */\n\nimport { defineStore } from 'pinia';\nimport { computed, ref } from 'vue';\n\n/**\n * HTTP method type\n */\nexport type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete' | 'options' | 'head' | 'trace';\n\n/**\n * Security requirement from OpenAPI spec\n */\nexport interface SecurityRequirement {\n name: string;\n scopes: string[];\n}\n\n/**\n * Endpoint entry from the server\n */\nexport interface EndpointEntry {\n key: string;\n operationId: string;\n method: HttpMethod;\n path: string;\n summary?: string;\n description?: string;\n tags: string[];\n responseSchema?: string;\n hasHandler: boolean;\n hasSeed: boolean;\n security: SecurityRequirement[];\n}\n\n/**\n * Registry statistics\n */\nexport interface RegistryStats {\n totalEndpoints: number;\n withCustomHandler: number;\n totalSchemas: number;\n withCustomSeed: number;\n autoGenerated: number;\n}\n\n/**\n * Registry data from server\n */\nexport interface RegistryData {\n endpoints: EndpointEntry[];\n stats: RegistryStats;\n}\n\n/**\n * Grouped endpoints by tag\n */\nexport interface EndpointGroup {\n tag: string;\n endpoints: EndpointEntry[];\n isExpanded: boolean;\n}\n\n/**\n * Filter options for endpoints\n */\nexport interface EndpointFilter {\n methods: HttpMethod[];\n hasHandler: boolean | null;\n hasSeed: boolean | null;\n tags: string[];\n}\n\n/**\n * Registry store for endpoint data management\n *\n * Provides:\n * - Endpoint data storage and retrieval\n * - Grouping by tags\n * - Search and filter functionality\n * - Selected endpoint tracking\n */\nexport const useRegistryStore = defineStore('registry', () => {\n // ==========================================================================\n // State\n // ==========================================================================\n\n /** All endpoints from the server */\n const endpoints = ref<EndpointEntry[]>([]);\n\n /** Registry statistics */\n const stats = ref<RegistryStats>({\n totalEndpoints: 0,\n withCustomHandler: 0,\n totalSchemas: 0,\n withCustomSeed: 0,\n autoGenerated: 0,\n });\n\n /** Loading state */\n const isLoading = ref(false);\n\n /** Error state */\n const error = ref<string | null>(null);\n\n /** Search query */\n const searchQuery = ref('');\n\n /** Active filters */\n const filter = ref<EndpointFilter>({\n methods: [],\n hasHandler: null,\n hasSeed: null,\n tags: [],\n });\n\n /** Currently selected endpoint key */\n const selectedEndpointKey = ref<string | null>(null);\n\n /** Expanded tag groups */\n const expandedTags = ref<Set<string>>(new Set());\n\n // ==========================================================================\n // Getters / Computed\n // ==========================================================================\n\n /**\n * All unique tags from endpoints\n */\n const allTags = computed(() => {\n const tagSet = new Set<string>();\n for (const endpoint of endpoints.value) {\n for (const tag of endpoint.tags) {\n tagSet.add(tag);\n }\n }\n return Array.from(tagSet).sort();\n });\n\n /**\n * All unique response schemas\n */\n const allSchemas = computed(() => {\n const schemaSet = new Set<string>();\n for (const endpoint of endpoints.value) {\n if (endpoint.responseSchema) {\n schemaSet.add(endpoint.responseSchema);\n }\n }\n return Array.from(schemaSet).sort();\n });\n\n /**\n * Filtered endpoints based on search and filters\n */\n const filteredEndpoints = computed(() => {\n let result = endpoints.value;\n\n // Apply search query\n if (searchQuery.value.trim()) {\n const query = searchQuery.value.toLowerCase().trim();\n result = result.filter((endpoint) => {\n return (\n endpoint.path.toLowerCase().includes(query) ||\n endpoint.operationId.toLowerCase().includes(query) ||\n endpoint.summary?.toLowerCase().includes(query) ||\n endpoint.tags.some((tag) => tag.toLowerCase().includes(query))\n );\n });\n }\n\n // Apply method filter\n if (filter.value.methods.length > 0) {\n result = result.filter((endpoint) => filter.value.methods.includes(endpoint.method));\n }\n\n // Apply handler filter\n if (filter.value.hasHandler !== null) {\n result = result.filter((endpoint) => endpoint.hasHandler === filter.value.hasHandler);\n }\n\n // Apply seed filter\n if (filter.value.hasSeed !== null) {\n result = result.filter((endpoint) => endpoint.hasSeed === filter.value.hasSeed);\n }\n\n // Apply tag filter\n if (filter.value.tags.length > 0) {\n result = result.filter((endpoint) =>\n endpoint.tags.some((tag) => filter.value.tags.includes(tag)),\n );\n }\n\n return result;\n });\n\n /**\n * Endpoints grouped by tag\n *\n * Grouping logic (from PRD):\n * 1. By tags (if they exist in spec)\n * 2. Fallback: By response schema\n * 3. Final fallback: By first path segment\n */\n const groupedEndpoints = computed((): EndpointGroup[] => {\n const groups = new Map<string, EndpointEntry[]>();\n\n for (const endpoint of filteredEndpoints.value) {\n // Determine group key\n let groupKey: string;\n\n if (endpoint.tags.length > 0) {\n // Use first tag as group\n groupKey = endpoint.tags[0];\n } else if (endpoint.responseSchema) {\n // Fallback to response schema\n groupKey = endpoint.responseSchema;\n } else {\n // Final fallback: first path segment\n const segments = endpoint.path.split('/').filter(Boolean);\n groupKey = segments[0] || 'Other';\n }\n\n if (!groups.has(groupKey)) {\n groups.set(groupKey, []);\n }\n groups.get(groupKey)?.push(endpoint);\n }\n\n // Convert to array and sort\n return Array.from(groups.entries())\n .map(([tag, eps]) => ({\n tag,\n endpoints: eps.sort((a, b) => a.path.localeCompare(b.path)),\n isExpanded: expandedTags.value.has(tag),\n }))\n .sort((a, b) => a.tag.localeCompare(b.tag));\n });\n\n /**\n * Currently selected endpoint\n */\n const selectedEndpoint = computed(() => {\n if (!selectedEndpointKey.value) return null;\n return endpoints.value.find((e) => e.key === selectedEndpointKey.value) ?? null;\n });\n\n /**\n * Count of endpoints with custom handlers\n */\n const handlerCount = computed(() => endpoints.value.filter((e) => e.hasHandler).length);\n\n /**\n * Count of endpoints with seed data\n */\n const seedCount = computed(() => endpoints.value.filter((e) => e.hasSeed).length);\n\n // ==========================================================================\n // Actions\n // ==========================================================================\n\n /**\n * Set registry data from server response\n */\n function setRegistryData(data: RegistryData): void {\n endpoints.value = data.endpoints;\n stats.value = data.stats;\n error.value = null;\n\n // Auto-expand all groups initially\n for (const endpoint of data.endpoints) {\n if (endpoint.tags.length > 0) {\n expandedTags.value.add(endpoint.tags[0]);\n }\n }\n }\n\n /**\n * Set loading state\n */\n function setLoading(loading: boolean): void {\n isLoading.value = loading;\n }\n\n /**\n * Set error state\n */\n function setError(errorMessage: string): void {\n error.value = errorMessage;\n isLoading.value = false;\n }\n\n /**\n * Clear error state\n */\n function clearError(): void {\n error.value = null;\n }\n\n /**\n * Set search query\n */\n function setSearchQuery(query: string): void {\n searchQuery.value = query;\n }\n\n /**\n * Toggle method filter\n */\n function toggleMethodFilter(method: HttpMethod): void {\n const index = filter.value.methods.indexOf(method);\n if (index === -1) {\n filter.value.methods.push(method);\n } else {\n filter.value.methods.splice(index, 1);\n }\n }\n\n /**\n * Set handler filter\n */\n function setHandlerFilter(hasHandler: boolean | null): void {\n filter.value.hasHandler = hasHandler;\n }\n\n /**\n * Set seed filter\n */\n function setSeedFilter(hasSeed: boolean | null): void {\n filter.value.hasSeed = hasSeed;\n }\n\n /**\n * Toggle tag filter\n */\n function toggleTagFilter(tag: string): void {\n const index = filter.value.tags.indexOf(tag);\n if (index === -1) {\n filter.value.tags.push(tag);\n } else {\n filter.value.tags.splice(index, 1);\n }\n }\n\n /**\n * Clear all filters\n */\n function clearFilters(): void {\n filter.value = {\n methods: [],\n hasHandler: null,\n hasSeed: null,\n tags: [],\n };\n searchQuery.value = '';\n }\n\n /**\n * Check if any filter is active\n */\n function hasActiveFilters(): boolean {\n return (\n searchQuery.value.trim() !== '' ||\n filter.value.methods.length > 0 ||\n filter.value.hasHandler !== null ||\n filter.value.hasSeed !== null ||\n filter.value.tags.length > 0\n );\n }\n\n /**\n * Select an endpoint by key\n */\n function selectEndpoint(key: string | null): void {\n selectedEndpointKey.value = key;\n }\n\n /**\n * Toggle group expansion\n */\n function toggleGroup(tag: string): void {\n if (expandedTags.value.has(tag)) {\n expandedTags.value.delete(tag);\n } else {\n expandedTags.value.add(tag);\n }\n }\n\n /**\n * Expand all groups\n */\n function expandAllGroups(): void {\n for (const group of groupedEndpoints.value) {\n expandedTags.value.add(group.tag);\n }\n }\n\n /**\n * Collapse all groups\n */\n function collapseAllGroups(): void {\n expandedTags.value.clear();\n }\n\n /**\n * Update handler status for endpoints\n * Called when handlers are reloaded\n */\n function updateHandlerStatus(handlerOperationIds: string[]): void {\n const handlerSet = new Set(handlerOperationIds);\n for (const endpoint of endpoints.value) {\n endpoint.hasHandler = handlerSet.has(endpoint.operationId);\n }\n }\n\n /**\n * Update seed status for endpoints\n * Called when seeds are reloaded\n */\n function updateSeedStatus(seedSchemas: string[]): void {\n const seedSet = new Set(seedSchemas);\n for (const endpoint of endpoints.value) {\n endpoint.hasSeed = endpoint.responseSchema ? seedSet.has(endpoint.responseSchema) : false;\n }\n }\n\n // ==========================================================================\n // Return\n // ==========================================================================\n\n return {\n // State\n endpoints,\n stats,\n isLoading,\n error,\n searchQuery,\n filter,\n selectedEndpointKey,\n expandedTags,\n\n // Getters\n allTags,\n allSchemas,\n filteredEndpoints,\n groupedEndpoints,\n selectedEndpoint,\n handlerCount,\n seedCount,\n\n // Actions\n setRegistryData,\n setLoading,\n setError,\n clearError,\n setSearchQuery,\n toggleMethodFilter,\n setHandlerFilter,\n setSeedFilter,\n toggleTagFilter,\n clearFilters,\n hasActiveFilters,\n selectEndpoint,\n toggleGroup,\n expandAllGroups,\n collapseAllGroups,\n updateHandlerStatus,\n updateSeedStatus,\n };\n});\n","/**\n * Simulation Store\n *\n * What: Pinia store for managing error and delay simulations\n * How: Manages simulation state and communicates with server via WebSocket\n * Why: Enables developers to test error handling and loading states\n *\n * @module stores/simulation\n */\n\nimport { defineStore } from 'pinia';\nimport { computed, ref } from 'vue';\n\n/**\n * Simulation preset type\n */\nexport type SimulationPresetType = 'delay' | 'error' | 'empty';\n\n/**\n * Simulation preset definition\n */\nexport interface SimulationPreset {\n id: string;\n label: string;\n description: string;\n type: SimulationPresetType;\n status: number;\n delay?: number;\n body?: unknown;\n}\n\n/**\n * Active simulation state\n */\nexport interface ActiveSimulation {\n path: string;\n operationId?: string;\n status: number;\n delay?: number;\n body?: unknown;\n presetId?: string;\n}\n\n/**\n * Preset definitions matching PRD FR-104 requirements\n */\nexport const SIMULATION_PRESETS: SimulationPreset[] = [\n {\n id: 'slow-network',\n label: 'Slow Network',\n description: '3000ms delay (3G simulation)',\n type: 'delay',\n status: 200,\n delay: 3000,\n },\n {\n id: 'server-error',\n label: 'Server Error',\n description: 'Returns HTTP 500',\n type: 'error',\n status: 500,\n body: { error: 'Internal Server Error', message: 'Simulated server error' },\n },\n {\n id: 'rate-limit',\n label: 'Rate Limited',\n description: 'Returns HTTP 429',\n type: 'error',\n status: 429,\n body: { error: 'Too Many Requests', message: 'Rate limit exceeded' },\n },\n {\n id: 'not-found',\n label: 'Not Found',\n description: 'Returns HTTP 404',\n type: 'error',\n status: 404,\n body: { error: 'Not Found', message: 'Resource not found' },\n },\n {\n id: 'request-timeout',\n label: 'Request Timeout',\n description: '30000ms delay (simulates timeout)',\n type: 'delay',\n status: 200,\n delay: 30000,\n },\n {\n id: 'empty-response',\n label: 'Empty Response',\n description: 'Returns HTTP 200 with empty body',\n type: 'empty',\n status: 200,\n body: null,\n },\n {\n id: 'unauthorized',\n label: 'Unauthorized',\n description: 'Returns HTTP 401',\n type: 'error',\n status: 401,\n body: { error: 'Unauthorized', message: 'Authentication required' },\n },\n];\n\n/**\n * Simulation store for managing endpoint simulations\n *\n * Provides:\n * - Active simulations storage and retrieval\n * - Preset definitions and lookup\n * - WebSocket command integration\n * - Simulation count and status tracking\n */\nexport const useSimulationStore = defineStore('simulation', () => {\n // ==========================================================================\n // State\n // ==========================================================================\n\n /**\n * Active simulations keyed by path\n * One simulation per path (enforced by Map)\n */\n const simulations = ref<Map<string, ActiveSimulation>>(new Map());\n\n /**\n * Previous simulation state for rollback on failure\n * Keyed by path, stores the simulation before optimistic update\n */\n const previousSimulations = ref<Map<string, ActiveSimulation | null>>(new Map());\n\n /**\n * Loading state for async operations\n */\n const isLoading = ref(false);\n\n /**\n * Error state\n */\n const error = ref<string | null>(null);\n\n // ==========================================================================\n // Getters / Computed\n // ==========================================================================\n\n /**\n * All active simulations as an array\n */\n const activeSimulations = computed(() => {\n return Array.from(simulations.value.values());\n });\n\n /**\n * Count of active simulations\n */\n const count = computed(() => simulations.value.size);\n\n /**\n * Available presets\n */\n const presets = computed(() => SIMULATION_PRESETS);\n\n /**\n * Check if any simulations are active\n */\n const hasActiveSimulations = computed(() => simulations.value.size > 0);\n\n /**\n * Get simulations grouped by type\n */\n const simulationsByType = computed(() => {\n const grouped = {\n delay: [] as ActiveSimulation[],\n error: [] as ActiveSimulation[],\n empty: [] as ActiveSimulation[],\n };\n\n for (const simulation of simulations.value.values()) {\n const type = getSimulationType(simulation);\n grouped[type].push(simulation);\n }\n\n return grouped;\n });\n\n /**\n * Determine simulation type from simulation config\n */\n function getSimulationType(simulation: ActiveSimulation): SimulationPresetType {\n const preset = simulation.presetId\n ? SIMULATION_PRESETS.find((p) => p.id === simulation.presetId)\n : null;\n\n if (preset) {\n return preset.type;\n }\n\n if (simulation.delay && simulation.delay > 0) {\n return 'delay';\n }\n\n if (simulation.body === null) {\n return 'empty';\n }\n\n return 'error';\n }\n\n // ==========================================================================\n // Actions\n // ==========================================================================\n\n /**\n * Set active simulations from server (e.g., on 'simulation:active' event)\n */\n function setSimulations(newSimulations: ActiveSimulation[]): void {\n simulations.value.clear();\n for (const simulation of newSimulations) {\n simulations.value.set(simulation.path, simulation);\n }\n error.value = null;\n }\n\n /**\n * Add a new simulation locally\n * Note: This updates local state only. Use addSimulation() to sync with server.\n * @param storeForRollback - If true, stores previous state for rollback\n */\n function addSimulationLocal(simulation: ActiveSimulation, storeForRollback = false): void {\n if (storeForRollback) {\n // Store previous state (null if didn't exist)\n const previous = simulations.value.get(simulation.path) || null;\n previousSimulations.value.set(simulation.path, previous);\n }\n simulations.value.set(simulation.path, simulation);\n }\n\n /**\n * Remove a simulation locally by path\n * Note: This updates local state only. Use removeSimulation() to sync with server.\n * @param storeForRollback - If true, stores previous state for rollback\n */\n function removeSimulationLocal(path: string, storeForRollback = false): boolean {\n if (storeForRollback) {\n // Store previous state before removing\n const previous = simulations.value.get(path) || null;\n previousSimulations.value.set(path, previous);\n }\n return simulations.value.delete(path);\n }\n\n /**\n * Clear all simulations locally\n * Note: This updates local state only. Use clearSimulations() to sync with server.\n */\n function clearSimulationsLocal(): void {\n simulations.value.clear();\n }\n\n /**\n * Get a simulation by path\n */\n function getSimulation(path: string): ActiveSimulation | undefined {\n return simulations.value.get(path);\n }\n\n /**\n * Check if a simulation exists for a path\n */\n function hasSimulation(path: string): boolean {\n return simulations.value.has(path);\n }\n\n /**\n * Get a preset by ID\n */\n function getPreset(id: string): SimulationPreset | undefined {\n return SIMULATION_PRESETS.find((p) => p.id === id);\n }\n\n /**\n * Create a simulation from a preset\n */\n function createSimulationFromPreset(\n path: string,\n presetId: string,\n operationId?: string,\n ): ActiveSimulation | null {\n const preset = getPreset(presetId);\n if (!preset) {\n error.value = `Preset not found: ${presetId}`;\n return null;\n }\n\n return {\n path,\n operationId,\n status: preset.status,\n delay: preset.delay,\n body: preset.body,\n presetId: preset.id,\n };\n }\n\n /**\n * Set loading state\n */\n function setLoading(loading: boolean): void {\n isLoading.value = loading;\n }\n\n /**\n * Set error state\n */\n function setError(errorMessage: string): void {\n error.value = errorMessage;\n isLoading.value = false;\n }\n\n /**\n * Clear error state\n */\n function clearError(): void {\n error.value = null;\n }\n\n /**\n * Rollback a simulation to its previous state\n * @param path - The path of the simulation to rollback\n */\n function rollbackSimulation(path: string): void {\n if (!previousSimulations.value.has(path)) {\n return;\n }\n\n const previous = previousSimulations.value.get(path);\n if (previous === null || previous === undefined) {\n // Was added optimistically, remove it\n simulations.value.delete(path);\n } else {\n // Restore previous state\n simulations.value.set(path, previous);\n }\n\n // Clear rollback data\n previousSimulations.value.delete(path);\n }\n\n /**\n * Handle simulation:added event from server\n */\n function handleSimulationAdded(data: { path: string }): void {\n // Server will send 'simulation:active' event with full state\n // This event is just a notification\n console.log('[Simulation] Added:', data.path);\n }\n\n /**\n * Handle simulation:removed event from server\n */\n function handleSimulationRemoved(data: { path: string }): void {\n removeSimulationLocal(data.path);\n console.log('[Simulation] Removed:', data.path);\n }\n\n /**\n * Handle simulations:cleared event from server\n */\n function handleSimulationsCleared(data: { count: number }): void {\n clearSimulationsLocal();\n console.log('[Simulation] Cleared all:', data.count);\n }\n\n /**\n * Handle simulation:set response from server\n */\n function handleSimulationSet(data: { path: string; success: boolean }): void {\n if (data.success) {\n // Clear rollback data on success\n previousSimulations.value.delete(data.path);\n console.log('[Simulation] Set successfully:', data.path);\n } else {\n // Rollback optimistic update on failure\n rollbackSimulation(data.path);\n setError(`Failed to set simulation for ${data.path}`);\n }\n setLoading(false);\n }\n\n /**\n * Handle simulation:cleared response from server\n */\n function handleSimulationCleared(data: { path: string; success: boolean }): void {\n if (data.success) {\n // Clear rollback data on success\n previousSimulations.value.delete(data.path);\n console.log('[Simulation] Cleared successfully:', data.path);\n } else {\n // Rollback optimistic removal on failure\n rollbackSimulation(data.path);\n setError(`Failed to clear simulation for ${data.path}`);\n }\n setLoading(false);\n }\n\n // ==========================================================================\n // Return\n // ==========================================================================\n\n return {\n // State\n simulations,\n isLoading,\n error,\n\n // Getters\n activeSimulations,\n count,\n presets,\n hasActiveSimulations,\n simulationsByType,\n\n // Actions\n setSimulations,\n addSimulationLocal,\n removeSimulationLocal,\n clearSimulationsLocal,\n getSimulation,\n hasSimulation,\n getPreset,\n createSimulationFromPreset,\n setLoading,\n setError,\n clearError,\n rollbackSimulation,\n\n // Event handlers\n handleSimulationAdded,\n handleSimulationRemoved,\n handleSimulationsCleared,\n handleSimulationSet,\n handleSimulationCleared,\n };\n});\n","/**\n * Timeline Store\n *\n * What: Pinia store for managing request/response timeline data\n * How: Receives and stores timeline events from the server via WebSocket\n * Why: Provides reactive access to timeline data for the Timeline Page\n *\n * @module stores/timeline\n */\n\nimport { defineStore } from 'pinia';\nimport { computed, ref } from 'vue';\n\n/**\n * HTTP method type for timeline entries\n */\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'TRACE';\n\n/**\n * Request log entry from the server\n */\nexport interface RequestLogEntry {\n id: string;\n method: string;\n path: string;\n operationId: string;\n timestamp: number;\n headers: Record<string, string>;\n query: Record<string, string | string[]>;\n body?: unknown;\n}\n\n/**\n * Response log entry from the server\n */\nexport interface ResponseLogEntry {\n id: string;\n requestId: string;\n status: number;\n duration: number;\n headers: Record<string, string>;\n body: unknown;\n simulated: boolean;\n}\n\n/**\n * Combined timeline entry with request and optional response\n */\nexport interface TimelineEntry {\n id: string;\n request: RequestLogEntry;\n response: ResponseLogEntry | null;\n status: number | null;\n duration: number | null;\n simulated: boolean;\n}\n\n/**\n * Timeline data from server\n */\nexport interface TimelineData {\n entries: Array<{ type: 'request' | 'response'; data: RequestLogEntry | ResponseLogEntry }>;\n count: number;\n total: number;\n}\n\n/**\n * Filter options for timeline entries\n */\nexport interface TimelineFilter {\n methods: HttpMethod[];\n statusCodes: ('1xx' | '2xx' | '3xx' | '4xx' | '5xx')[];\n searchQuery: string;\n simulatedOnly: boolean | null;\n}\n\n/**\n * Timeline store for request/response tracking\n *\n * Provides:\n * - Timeline entry storage and retrieval\n * - Real-time updates via WebSocket events\n * - Search and filter functionality\n * - Selected entry tracking for detail view\n * - Timeline limit management\n */\nexport const useTimelineStore = defineStore('timeline', () => {\n // ==========================================================================\n // State\n // ==========================================================================\n\n /** All timeline entries (request + response pairs) */\n const entries = ref<TimelineEntry[]>([]);\n\n /** Loading state */\n const isLoading = ref(false);\n\n /** Error state */\n const error = ref<string | null>(null);\n\n /** Active filters */\n const filter = ref<TimelineFilter>({\n methods: [],\n statusCodes: [],\n searchQuery: '',\n simulatedOnly: null,\n });\n\n /** Currently selected entry ID */\n const selectedEntryId = ref<string | null>(null);\n\n /** Maximum number of entries to keep */\n const maxEntries = ref(500);\n\n /** Buffer for responses that arrived before their requests */\n const responseBuffer = new Map<string, ResponseLogEntry>();\n\n // ==========================================================================\n // Getters / Computed\n // ==========================================================================\n\n /**\n * Get status category from status code\n */\n function getStatusCategory(status: number): '1xx' | '2xx' | '3xx' | '4xx' | '5xx' {\n if (status < 200) return '1xx';\n if (status < 300) return '2xx';\n if (status < 400) return '3xx';\n if (status < 500) return '4xx';\n return '5xx';\n }\n\n /**\n * Filtered entries based on search and filters\n */\n const filteredEntries = computed(() => {\n let result = entries.value;\n\n // Apply search query (matches path or operationId)\n if (filter.value.searchQuery.trim()) {\n const query = filter.value.searchQuery.toLowerCase().trim();\n result = result.filter((entry) => {\n return (\n entry.request.path.toLowerCase().includes(query) ||\n entry.request.operationId.toLowerCase().includes(query)\n );\n });\n }\n\n // Apply method filter\n if (filter.value.methods.length > 0) {\n result = result.filter((entry) =>\n filter.value.methods.includes(entry.request.method.toUpperCase() as HttpMethod),\n );\n }\n\n // Apply status code filter\n if (filter.value.statusCodes.length > 0) {\n result = result.filter((entry) => {\n if (entry.status === null) return false;\n const category = getStatusCategory(entry.status);\n return filter.value.statusCodes.includes(category);\n });\n }\n\n // Apply simulated filter\n if (filter.value.simulatedOnly !== null) {\n result = result.filter((entry) => entry.simulated === filter.value.simulatedOnly);\n }\n\n return result;\n });\n\n /**\n * Currently selected entry\n */\n const selectedEntry = computed(() => {\n if (!selectedEntryId.value) return null;\n return entries.value.find((e) => e.id === selectedEntryId.value) ?? null;\n });\n\n /**\n * Total number of entries (including pending responses)\n */\n const totalCount = computed(() => entries.value.length);\n\n /**\n * Count of entries with responses\n */\n const completedCount = computed(() => entries.value.filter((e) => e.response !== null).length);\n\n /**\n * Count of pending requests (no response yet)\n */\n const pendingCount = computed(() => entries.value.filter((e) => e.response === null).length);\n\n /**\n * Count of entries by status category\n */\n const statusCounts = computed(() => {\n const counts = {\n '1xx': 0,\n '2xx': 0,\n '3xx': 0,\n '4xx': 0,\n '5xx': 0,\n };\n\n for (const entry of entries.value) {\n if (entry.status !== null) {\n const category = getStatusCategory(entry.status);\n counts[category]++;\n }\n }\n\n return counts;\n });\n\n /**\n * Average response duration in milliseconds\n */\n const averageDuration = computed(() => {\n const completedEntries = entries.value.filter((e) => e.duration !== null);\n if (completedEntries.length === 0) return 0;\n\n const totalDuration = completedEntries.reduce((sum, e) => sum + (e.duration ?? 0), 0);\n return Math.round(totalDuration / completedEntries.length);\n });\n\n // ==========================================================================\n // Actions\n // ==========================================================================\n\n /**\n * Add a request to the timeline\n */\n function addRequest(request: RequestLogEntry): void {\n const entry: TimelineEntry = {\n id: request.id,\n request,\n response: null,\n status: null,\n duration: null,\n simulated: false,\n };\n\n // Check if there's a buffered response for this request\n const bufferedResponse = responseBuffer.get(request.id);\n if (bufferedResponse) {\n mergeResponse(entry, bufferedResponse);\n // Clear consumed buffered response\n responseBuffer.delete(request.id);\n }\n\n // Add to beginning of array (newest first)\n entries.value.unshift(entry);\n\n // Trim to max entries\n if (entries.value.length > maxEntries.value) {\n entries.value = entries.value.slice(0, maxEntries.value);\n }\n }\n\n /**\n * Add a response to an existing request\n */\n function addResponse(response: ResponseLogEntry): void {\n const entry = entries.value.find((e) => e.id === response.requestId);\n if (entry) {\n // Entry exists, merge immediately\n mergeResponse(entry, response);\n // Clear from buffer if it was buffered\n responseBuffer.delete(response.requestId);\n } else {\n // Entry doesn't exist yet, buffer the response\n responseBuffer.set(response.requestId, response);\n\n // Prevent unbounded buffer growth: create stub entry if buffer exceeds threshold\n // This ensures orphaned responses don't cause memory leaks in real-time scenarios\n if (responseBuffer.size > 100) {\n const stubEntry = createStubEntry(response);\n entries.value.unshift(stubEntry);\n responseBuffer.delete(response.requestId);\n\n // Trim to max entries\n if (entries.value.length > maxEntries.value) {\n entries.value = entries.value.slice(0, maxEntries.value);\n }\n }\n }\n }\n\n /**\n * Merge a response into an entry\n */\n function mergeResponse(entry: TimelineEntry, response: ResponseLogEntry): void {\n entry.response = response;\n entry.status = response.status;\n entry.duration = response.duration;\n entry.simulated = response.simulated;\n }\n\n /**\n * Create a stub entry for an orphaned response\n */\n function createStubEntry(response: ResponseLogEntry): TimelineEntry {\n // Create a minimal request stub for the orphaned response\n const stubRequest: RequestLogEntry = {\n id: response.requestId,\n method: 'UNKNOWN',\n path: '/unknown',\n operationId: 'unknown',\n timestamp: Date.now(), // Use current time as fallback\n headers: {},\n query: {},\n body: undefined,\n };\n\n return {\n id: response.requestId,\n request: stubRequest,\n response,\n status: response.status,\n duration: response.duration,\n simulated: response.simulated,\n };\n }\n\n /**\n * Process buffered responses and merge with existing entries or create stubs\n */\n function processBufferedResponses(requestMap: Map<string, TimelineEntry>): void {\n for (const [requestId, response] of responseBuffer) {\n const entry = requestMap.get(requestId);\n if (entry) {\n mergeResponse(entry, response);\n responseBuffer.delete(requestId);\n } else {\n // No matching request found, create stub entry\n requestMap.set(requestId, createStubEntry(response));\n responseBuffer.delete(requestId);\n }\n }\n }\n\n /**\n * Process incoming responses and merge, buffer, or create stub entries\n */\n function processIncomingResponses(\n requestMap: Map<string, TimelineEntry>,\n incomingResponses: Map<string, ResponseLogEntry>,\n ): void {\n for (const [requestId, response] of incomingResponses) {\n const entry = requestMap.get(requestId);\n if (entry) {\n mergeResponse(entry, response);\n } else {\n // Buffer the response for potential future request\n // Note: During initial load, we'll create stubs later\n responseBuffer.set(requestId, response);\n }\n }\n }\n\n /**\n * Create stub entries for any remaining buffered responses\n * This ensures no response is lost even if its request never arrives\n */\n function createStubsForOrphanedResponses(requestMap: Map<string, TimelineEntry>): void {\n for (const [requestId, response] of responseBuffer) {\n if (!requestMap.has(requestId)) {\n requestMap.set(requestId, createStubEntry(response));\n responseBuffer.delete(requestId);\n }\n }\n }\n\n /**\n * Set timeline data from server response\n * Used when fetching initial timeline data\n */\n function setTimelineData(data: TimelineData): void {\n const requestMap = new Map<string, TimelineEntry>();\n const incomingResponses = new Map<string, ResponseLogEntry>();\n\n // First pass: collect all requests and responses\n for (const item of data.entries) {\n if (item.type === 'request') {\n const request = item.data as RequestLogEntry;\n requestMap.set(request.id, {\n id: request.id,\n request,\n response: null,\n status: null,\n duration: null,\n simulated: false,\n });\n } else if (item.type === 'response') {\n const response = item.data as ResponseLogEntry;\n incomingResponses.set(response.requestId, response);\n }\n }\n\n // Second pass: merge responses with requests\n processBufferedResponses(requestMap);\n processIncomingResponses(requestMap, incomingResponses);\n\n // Third pass: create stub entries for any remaining orphaned responses\n // This ensures no response is lost even if its request never arrives\n createStubsForOrphanedResponses(requestMap);\n\n // Convert map to array and sort by timestamp (newest first)\n const sorted = Array.from(requestMap.values()).sort(\n (a, b) => b.request.timestamp - a.request.timestamp,\n );\n\n // Apply maxEntries limit\n entries.value = sorted.slice(0, maxEntries.value);\n\n error.value = null;\n }\n\n /**\n * Clear all timeline entries\n */\n function clearTimeline(): void {\n entries.value = [];\n selectedEntryId.value = null;\n responseBuffer.clear();\n }\n\n /**\n * Set loading state\n */\n function setLoading(loading: boolean): void {\n isLoading.value = loading;\n }\n\n /**\n * Set error state\n */\n function setError(errorMessage: string): void {\n error.value = errorMessage;\n isLoading.value = false;\n }\n\n /**\n * Clear error state\n */\n function clearError(): void {\n error.value = null;\n }\n\n /**\n * Set search query\n */\n function setSearchQuery(query: string): void {\n filter.value.searchQuery = query;\n }\n\n /**\n * Toggle method filter\n */\n function toggleMethodFilter(method: HttpMethod): void {\n const index = filter.value.methods.indexOf(method);\n if (index === -1) {\n filter.value.methods.push(method);\n } else {\n filter.value.methods.splice(index, 1);\n }\n }\n\n /**\n * Toggle status code filter\n */\n function toggleStatusFilter(status: '1xx' | '2xx' | '3xx' | '4xx' | '5xx'): void {\n const index = filter.value.statusCodes.indexOf(status);\n if (index === -1) {\n filter.value.statusCodes.push(status);\n } else {\n filter.value.statusCodes.splice(index, 1);\n }\n }\n\n /**\n * Set simulated filter\n */\n function setSimulatedFilter(simulated: boolean | null): void {\n filter.value.simulatedOnly = simulated;\n }\n\n /**\n * Clear all filters\n */\n function clearFilters(): void {\n filter.value = {\n methods: [],\n statusCodes: [],\n searchQuery: '',\n simulatedOnly: null,\n };\n }\n\n /**\n * Check if any filter is active\n */\n function hasActiveFilters(): boolean {\n return (\n filter.value.searchQuery.trim() !== '' ||\n filter.value.methods.length > 0 ||\n filter.value.statusCodes.length > 0 ||\n filter.value.simulatedOnly !== null\n );\n }\n\n /**\n * Select an entry by ID\n */\n function selectEntry(id: string | null): void {\n selectedEntryId.value = id;\n }\n\n /**\n * Set maximum entries limit\n */\n function setMaxEntries(limit: number): void {\n // Clamp limit to a safe minimum\n const clamped = Math.max(1, limit);\n maxEntries.value = clamped;\n\n // Trim if necessary\n if (entries.value.length > clamped) {\n entries.value = entries.value.slice(0, clamped);\n }\n }\n\n // ==========================================================================\n // Return\n // ==========================================================================\n\n return {\n // State\n entries,\n isLoading,\n error,\n filter,\n selectedEntryId,\n maxEntries,\n\n // Getters\n filteredEntries,\n selectedEntry,\n totalCount,\n completedCount,\n pendingCount,\n statusCounts,\n averageDuration,\n\n // Actions\n addRequest,\n addResponse,\n setTimelineData,\n clearTimeline,\n setLoading,\n setError,\n clearError,\n setSearchQuery,\n toggleMethodFilter,\n toggleStatusFilter,\n setSimulatedFilter,\n clearFilters,\n hasActiveFilters,\n selectEntry,\n setMaxEntries,\n };\n});\n","/**\n * useTheme Composable\n *\n * What: Provides reactive theme management for the DevTools SPA\n * How: Uses CSS class on document root and localStorage for persistence\n * Why: Allows users to switch between dark and light mode, respecting system preference\n */\n\nimport { computed, getCurrentInstance, onMounted, onUnmounted, ref, watch } from 'vue';\n\n/**\n * Theme mode type\n */\nexport type ThemeMode = 'light' | 'dark' | 'system';\n\n/**\n * Valid theme modes for type guard validation\n */\nconst VALID_THEME_MODES: readonly ThemeMode[] = ['light', 'dark', 'system'];\n\n/**\n * Type guard to check if a value is a valid ThemeMode\n */\nfunction isThemeMode(value: unknown): value is ThemeMode {\n return typeof value === 'string' && VALID_THEME_MODES.includes(value as ThemeMode);\n}\n\n/**\n * Storage key for persisting theme preference\n */\nconst STORAGE_KEY = 'openapi-devtools-theme';\n\n/**\n * Singleton state for theme - shared across all component instances\n */\nconst themeMode = ref<ThemeMode>('system');\nconst systemPrefersDark = ref(false);\n\n/**\n * Track the current mediaQuery and handler for cleanup\n */\nlet currentMediaQuery: MediaQueryList | null = null;\nlet currentMediaHandler: ((e: MediaQueryListEvent) => void) | null = null;\n\n/**\n * Check if we're running in a browser environment\n */\nfunction isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Check if we're inside a Vue component context\n * This allows the composable to work both inside and outside components\n */\nfunction hasComponentContext(): boolean {\n return getCurrentInstance() !== null;\n}\n\n/**\n * useTheme composable\n *\n * Provides theme management functionality including:\n * - Reactive theme state\n * - System preference detection\n * - Theme toggling\n * - LocalStorage persistence\n *\n * @returns Theme management utilities\n */\nexport function useTheme() {\n /**\n * Computed property for the effective theme (resolved from system if needed)\n */\n const effectiveTheme = computed<'light' | 'dark'>(() => {\n if (themeMode.value === 'system') {\n return systemPrefersDark.value ? 'dark' : 'light';\n }\n return themeMode.value;\n });\n\n /**\n * Computed property indicating if dark mode is active\n */\n const isDark = computed(() => effectiveTheme.value === 'dark');\n\n /**\n * Apply the current theme to the document\n */\n function applyTheme(): void {\n if (!isBrowser()) return;\n\n const root = document.documentElement;\n\n if (effectiveTheme.value === 'dark') {\n root.classList.add('dark');\n root.classList.remove('light');\n } else {\n root.classList.add('light');\n root.classList.remove('dark');\n }\n }\n\n /**\n * Set the theme mode\n */\n function setTheme(mode: ThemeMode): void {\n if (!isThemeMode(mode)) {\n console.warn(`[DevTools] Invalid theme mode: ${mode}`);\n return;\n }\n\n themeMode.value = mode;\n\n if (isBrowser()) {\n try {\n localStorage.setItem(STORAGE_KEY, mode);\n } catch {\n // Storage unavailable (private browsing, quota exceeded, etc.)\n console.warn('[DevTools] Unable to persist theme preference');\n }\n }\n }\n\n /**\n * Toggle between light and dark mode\n * If currently in system mode, switch to the opposite of system preference\n */\n function toggleTheme(): void {\n if (themeMode.value === 'system') {\n // Switch to explicit mode opposite of system preference\n setTheme(systemPrefersDark.value ? 'light' : 'dark');\n } else {\n // Toggle between light and dark\n setTheme(themeMode.value === 'dark' ? 'light' : 'dark');\n }\n }\n\n /**\n * Reset to system preference\n */\n function resetToSystem(): void {\n setTheme('system');\n }\n\n /**\n * Clean up the media query listener\n */\n function cleanupMediaQuery(): void {\n if (currentMediaQuery && currentMediaHandler) {\n currentMediaQuery.removeEventListener('change', currentMediaHandler);\n currentMediaQuery = null;\n currentMediaHandler = null;\n }\n }\n\n /**\n * Initialize theme from storage and system preference\n */\n function initialize(): void {\n if (!isBrowser()) return;\n\n // Clean up any existing media query listener before adding a new one\n cleanupMediaQuery();\n\n // Check system preference\n const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');\n systemPrefersDark.value = mediaQuery.matches;\n\n // Create and store the handler for cleanup\n const handler = (e: MediaQueryListEvent): void => {\n systemPrefersDark.value = e.matches;\n };\n\n // Listen for system preference changes\n mediaQuery.addEventListener('change', handler);\n\n // Store references for cleanup\n currentMediaQuery = mediaQuery;\n currentMediaHandler = handler;\n\n // Load saved preference from localStorage\n try {\n const saved = localStorage.getItem(STORAGE_KEY);\n if (isThemeMode(saved)) {\n themeMode.value = saved;\n }\n } catch {\n // Storage unavailable (private browsing, etc.)\n }\n\n // Apply initial theme\n applyTheme();\n }\n\n /**\n * Reset theme state to defaults (useful for testing)\n * This resets the singleton state and cleans up listeners\n */\n function resetState(): void {\n cleanupMediaQuery();\n themeMode.value = 'system';\n systemPrefersDark.value = false;\n\n if (isBrowser()) {\n const root = document.documentElement;\n root.classList.remove('dark', 'light');\n\n try {\n localStorage.removeItem(STORAGE_KEY);\n } catch {\n // Storage unavailable\n }\n }\n }\n\n // Watch for theme changes and apply them\n watch([themeMode, systemPrefersDark], () => {\n applyTheme();\n });\n\n // Only register lifecycle hooks when inside a Vue component context\n // This allows the composable to be used in tests without Vue warnings\n if (hasComponentContext()) {\n // Initialize on mount\n onMounted(() => {\n initialize();\n });\n\n // Clean up on unmount\n onUnmounted(() => {\n cleanupMediaQuery();\n });\n }\n\n return {\n /**\n * Current theme mode setting ('light', 'dark', or 'system')\n */\n themeMode: computed(() => themeMode.value),\n\n /**\n * The effective theme after resolving 'system' mode\n */\n effectiveTheme,\n\n /**\n * Whether dark mode is currently active\n */\n isDark,\n\n /**\n * Whether the system prefers dark mode\n */\n systemPrefersDark: computed(() => systemPrefersDark.value),\n\n /**\n * Set the theme mode\n */\n setTheme,\n\n /**\n * Toggle between light and dark mode\n */\n toggleTheme,\n\n /**\n * Reset to system preference\n */\n resetToSystem,\n\n /**\n * Manually initialize theme (useful for SSR hydration)\n */\n initialize,\n\n /**\n * Reset theme state to defaults (useful for testing)\n */\n resetState,\n };\n}\n","/**\n * Main Entry Point for DevTools SPA\n *\n * What: Initializes and mounts the Vue application\n * How: Creates Vue app instance with Pinia and Vue Router\n * Why: Required entry point for the DevTools SPA\n */\n\nimport { createPinia } from 'pinia';\nimport type { App } from 'vue';\nimport { createApp } from 'vue';\n\nimport AppComponent from '@/App.vue';\nimport router from '@/router';\nimport { initializeStores } from '@/stores';\n\n// Import global styles\nimport '@/assets/main.css';\n\n/**\n * Module-scoped guard to ensure bootstrap only runs once\n */\nlet isBootstrapped = false;\nlet appInstance: App | null = null;\n\n/**\n * Create and configure the Vue application\n * This function is idempotent - calling it multiple times has no effect\n * after the first successful call.\n *\n * @returns The Vue app instance, or null if already bootstrapped\n */\nfunction bootstrap(): App | null {\n // Guard against multiple bootstrap calls\n if (isBootstrapped) {\n if (import.meta.env.DEV) {\n console.warn('[OpenAPI DevTools] Application already initialized, skipping bootstrap');\n }\n return appInstance;\n }\n\n // Create Vue app instance\n const app = createApp(AppComponent);\n\n // Create Pinia store instance\n const pinia = createPinia();\n\n // Install plugins\n app.use(pinia);\n app.use(router);\n\n // Initialize stores after Pinia is installed\n initializeStores();\n\n // Mount the app to the DOM\n app.mount('#app');\n\n // Mark as bootstrapped and store the instance\n isBootstrapped = true;\n appInstance = app;\n\n // Log startup info in development\n if (import.meta.env.DEV) {\n console.log('[OpenAPI DevTools] Application initialized');\n }\n\n return app;\n}\n\n// Only auto-bootstrap when running as standalone app (index.html entry)\n// When imported as a library, consumers should call bootstrap() manually\nif (typeof window !== 'undefined' && document.getElementById('app')) {\n bootstrap();\n}\n\n/**\n * Export the bootstrap function for library consumers\n * who may want to manually initialize the DevTools\n */\nexport { bootstrap };\n\nexport type {\n ClientCommand,\n ClientCommandType,\n ConnectedEventData,\n ConnectionState,\n EventHandler,\n ServerEvent,\n ServerEventType,\n ThemeMode,\n UseWebSocketOptions,\n UseWebSocketReturn,\n} from '@/composables';\n// Re-export composables for library consumers\nexport { useTheme, useWebSocket } from '@/composables';\n","/**\n * Format Utilities\n *\n * What: Shared formatting functions for display purposes\n * How: Provides consistent formatting across components\n * Why: Centralizes common formatting logic to avoid duplication (DRY)\n *\n * @module utils/format\n */\n\n/**\n * Get display label for HTTP method\n *\n * Converts an HTTP method to its uppercase display format.\n *\n * @param method - The HTTP method string (e.g., 'get', 'post')\n * @returns The uppercase method label (e.g., 'GET', 'POST')\n *\n * @example\n * getMethodLabel('get') // Returns 'GET'\n * getMethodLabel('post') // Returns 'POST'\n */\nexport function getMethodLabel(method: string): string {\n return method.toUpperCase();\n}\n","<!--\n EndpointDetail.vue - Endpoint Detail Panel Component\n\n What: Displays detailed information about a selected API endpoint\n How: Shows method, path, operation ID, tags, summary, description, and status indicators\n Why: Provides comprehensive endpoint information for developers using the DevTools\n-->\n\n<script setup lang=\"ts\">\nimport { Code, FileJson, Lock, Shield, Sprout, Tag } from 'lucide-vue-next';\nimport { computed } from 'vue';\n\nimport type { EndpointEntry } from '@/stores/registry';\nimport { getMethodLabel } from '@/utils/format';\n\n/**\n * Component props\n */\ninterface Props {\n /** Endpoint to display details for */\n endpoint: EndpointEntry | null;\n}\n\nconst props = defineProps<Props>();\n\n/**\n * Check if endpoint has security requirements\n */\nconst hasSecurity = computed(() => {\n return props.endpoint?.security && props.endpoint.security.length > 0;\n});\n\n/**\n * Format security requirements for display\n */\nconst securityDisplay = computed(() => {\n if (!props.endpoint?.security) return [];\n return props.endpoint.security.map((sec) => ({\n name: sec.name,\n scopes: sec.scopes.length > 0 ? sec.scopes.join(', ') : 'No scopes',\n }));\n});\n</script>\n\n<template>\n <div class=\"endpoint-detail\">\n <!-- Empty state when no endpoint selected -->\n <div v-if=\"!endpoint\" class=\"endpoint-detail__empty\">\n <FileJson :size=\"48\" class=\"endpoint-detail__empty-icon\" />\n <h3 class=\"endpoint-detail__empty-title\">No endpoint selected</h3>\n <p class=\"endpoint-detail__empty-text text-muted\">\n Select an endpoint from the list to view its details\n </p>\n </div>\n\n <!-- Endpoint details -->\n <div v-else class=\"endpoint-detail__content\">\n <!-- Header with method and path -->\n <header class=\"endpoint-detail__header\">\n <span\n :class=\"[\n 'method-badge',\n 'method-badge--large',\n `method-badge--${endpoint.method}`\n ]\"\n >\n {{ getMethodLabel(endpoint.method) }}\n </span>\n <h2 class=\"endpoint-detail__path font-mono\">\n {{ endpoint.path }}\n </h2>\n </header>\n\n <!-- Status indicators -->\n <div class=\"endpoint-detail__status\">\n <div\n v-if=\"endpoint.hasHandler\"\n class=\"endpoint-detail__status-item endpoint-detail__status-item--handler\"\n >\n <Code :size=\"14\" />\n <span>Has custom handler</span>\n </div>\n <div\n v-if=\"endpoint.hasSeed\"\n class=\"endpoint-detail__status-item endpoint-detail__status-item--seed\"\n >\n <Sprout :size=\"14\" />\n <span>Has seed data</span>\n </div>\n <div\n v-if=\"hasSecurity\"\n class=\"endpoint-detail__status-item endpoint-detail__status-item--security\"\n >\n <Lock :size=\"14\" />\n <span>Requires authentication</span>\n </div>\n <div\n v-if=\"!endpoint.hasHandler && !endpoint.hasSeed\"\n class=\"endpoint-detail__status-item endpoint-detail__status-item--auto\"\n >\n <FileJson :size=\"14\" />\n <span>Auto-generated response</span>\n </div>\n </div>\n\n <!-- Info sections -->\n <div class=\"endpoint-detail__sections\">\n <!-- Operation ID -->\n <section class=\"endpoint-detail__section\">\n <h3 class=\"endpoint-detail__section-title\">Operation</h3>\n <p class=\"endpoint-detail__section-content font-mono\">\n {{ endpoint.operationId }}\n </p>\n </section>\n\n <!-- Tags -->\n <section v-if=\"endpoint.tags.length > 0\" class=\"endpoint-detail__section\">\n <h3 class=\"endpoint-detail__section-title\">\n <Tag :size=\"14\" />\n Tags\n </h3>\n <div class=\"endpoint-detail__tags\">\n <span\n v-for=\"tag in endpoint.tags\"\n :key=\"tag\"\n class=\"endpoint-detail__tag\"\n >\n {{ tag }}\n </span>\n </div>\n </section>\n\n <!-- Summary -->\n <section v-if=\"endpoint.summary\" class=\"endpoint-detail__section\">\n <h3 class=\"endpoint-detail__section-title\">Summary</h3>\n <p class=\"endpoint-detail__section-content\">\n {{ endpoint.summary }}\n </p>\n </section>\n\n <!-- Description -->\n <section v-if=\"endpoint.description\" class=\"endpoint-detail__section\">\n <h3 class=\"endpoint-detail__section-title\">Description</h3>\n <p class=\"endpoint-detail__section-content endpoint-detail__description\">\n {{ endpoint.description }}\n </p>\n </section>\n\n <!-- Response Schema -->\n <section v-if=\"endpoint.responseSchema\" class=\"endpoint-detail__section\">\n <h3 class=\"endpoint-detail__section-title\">\n <FileJson :size=\"14\" />\n Response Schema\n </h3>\n <p class=\"endpoint-detail__section-content font-mono\">\n {{ endpoint.responseSchema }}\n </p>\n </section>\n\n <!-- Security -->\n <section v-if=\"hasSecurity\" class=\"endpoint-detail__section\">\n <h3 class=\"endpoint-detail__section-title\">\n <Shield :size=\"14\" />\n Security\n </h3>\n <div class=\"endpoint-detail__security\">\n <div\n v-for=\"sec in securityDisplay\"\n :key=\"sec.name\"\n class=\"endpoint-detail__security-item\"\n >\n <span class=\"endpoint-detail__security-name font-mono\">\n {{ sec.name }}\n </span>\n <span class=\"endpoint-detail__security-scopes text-muted\">\n {{ sec.scopes }}\n </span>\n </div>\n </div>\n </section>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.endpoint-detail {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n\n/* Empty state */\n.endpoint-detail__empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: var(--devtools-space-xl);\n text-align: center;\n}\n\n.endpoint-detail__empty-icon {\n color: var(--devtools-text-muted);\n opacity: 0.5;\n margin-bottom: var(--devtools-space-md);\n}\n\n.endpoint-detail__empty-title {\n font-size: var(--font-size-2);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text);\n margin: 0 0 var(--devtools-space-sm);\n}\n\n.endpoint-detail__empty-text {\n font-size: var(--font-size-1);\n margin: 0;\n}\n\n/* Content */\n.endpoint-detail__content {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow-y: auto;\n padding: var(--devtools-space-md);\n}\n\n/* Header */\n.endpoint-detail__header {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-md);\n margin-bottom: var(--devtools-space-md);\n padding-bottom: var(--devtools-space-md);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.endpoint-detail__path {\n font-size: var(--font-size-2);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text);\n margin: 0;\n word-break: break-all;\n}\n\n/* Large method badge */\n.method-badge--large {\n font-size: var(--font-size-0);\n padding: var(--devtools-space-sm) var(--devtools-space-md);\n min-width: 70px;\n}\n\n/* Status indicators */\n.endpoint-detail__status {\n display: flex;\n flex-wrap: wrap;\n gap: var(--devtools-space-sm);\n margin-bottom: var(--devtools-space-md);\n}\n\n.endpoint-detail__status-item {\n display: inline-flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n border-radius: var(--devtools-radius-sm);\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n}\n\n.endpoint-detail__status-item--handler {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n color: var(--devtools-info);\n}\n\n.endpoint-detail__status-item--seed {\n background-color: color-mix(in srgb, var(--devtools-success) 15%, transparent);\n color: var(--devtools-success);\n}\n\n.endpoint-detail__status-item--security {\n background-color: color-mix(in srgb, var(--devtools-warning) 15%, transparent);\n color: var(--devtools-warning);\n}\n\n.endpoint-detail__status-item--auto {\n background-color: color-mix(in srgb, var(--devtools-text-muted) 15%, transparent);\n color: var(--devtools-text-muted);\n}\n\n/* Sections */\n.endpoint-detail__sections {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-md);\n}\n\n.endpoint-detail__section {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-xs);\n}\n\n.endpoint-detail__section-title {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-6);\n color: var(--devtools-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin: 0;\n}\n\n.endpoint-detail__section-content {\n font-size: var(--font-size-1);\n color: var(--devtools-text);\n margin: 0;\n line-height: var(--font-lineheight-3);\n}\n\n.endpoint-detail__description {\n white-space: pre-wrap;\n}\n\n/* Tags */\n.endpoint-detail__tags {\n display: flex;\n flex-wrap: wrap;\n gap: var(--devtools-space-xs);\n}\n\n.endpoint-detail__tag {\n display: inline-flex;\n align-items: center;\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n background-color: var(--devtools-surface-elevated);\n border-radius: var(--devtools-radius-sm);\n font-size: var(--font-size-0);\n color: var(--devtools-text);\n}\n\n/* Security */\n.endpoint-detail__security {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-xs);\n}\n\n.endpoint-detail__security-item {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: var(--devtools-space-sm);\n background-color: var(--devtools-surface-elevated);\n border-radius: var(--devtools-radius-sm);\n}\n\n.endpoint-detail__security-name {\n font-size: var(--font-size-1);\n font-weight: var(--font-weight-5);\n}\n\n.endpoint-detail__security-scopes {\n font-size: var(--font-size-0);\n}\n</style>\n","<!--\n EndpointList.vue - Grouped Endpoint Listing Component\n\n What: Displays a list of API endpoints grouped by tags with collapsible sections\n How: Renders endpoint groups from registry store with method badges and selection support\n Why: Provides organized navigation through available mock endpoints\n-->\n\n<script setup lang=\"ts\">\nimport { ChevronDown, ChevronRight, Code, Sprout } from 'lucide-vue-next';\n\nimport type { EndpointEntry, EndpointGroup } from '@/stores/registry';\nimport { getMethodLabel } from '@/utils/format';\n\n/**\n * Component props\n */\ninterface Props {\n /** Grouped endpoints to display */\n groups: EndpointGroup[];\n /** Currently selected endpoint key */\n selectedKey: string | null;\n}\n\nconst props = defineProps<Props>();\n\n/**\n * Component events\n */\nconst emit = defineEmits<{\n /** Emitted when an endpoint is selected */\n (e: 'select', key: string): void;\n /** Emitted when a group is toggled */\n (e: 'toggle-group', tag: string): void;\n}>();\n\n/**\n * Handle endpoint click\n */\nfunction handleEndpointClick(endpoint: EndpointEntry): void {\n emit('select', endpoint.key);\n}\n\n/**\n * Handle group toggle\n */\nfunction handleGroupToggle(tag: string): void {\n emit('toggle-group', tag);\n}\n\n/**\n * Check if endpoint is selected\n */\nfunction isSelected(endpoint: EndpointEntry): boolean {\n return props.selectedKey === endpoint.key;\n}\n</script>\n\n<template>\n <div class=\"endpoint-list\">\n <!-- Empty state -->\n <div v-if=\"groups.length === 0\" class=\"endpoint-list__empty\">\n <p class=\"text-muted\">No endpoints found</p>\n </div>\n\n <!-- Endpoint groups -->\n <div v-else class=\"endpoint-list__groups\">\n <div\n v-for=\"group in groups\"\n :key=\"group.tag\"\n class=\"endpoint-group\"\n >\n <!-- Group header -->\n <button\n type=\"button\"\n class=\"endpoint-group__header\"\n :aria-expanded=\"group.isExpanded\"\n :aria-controls=\"`group-${group.tag}`\"\n @click=\"handleGroupToggle(group.tag)\"\n >\n <component\n :is=\"group.isExpanded ? ChevronDown : ChevronRight\"\n :size=\"16\"\n class=\"endpoint-group__chevron\"\n />\n <span class=\"endpoint-group__tag\">{{ group.tag }}</span>\n <span class=\"endpoint-group__count text-muted\">\n ({{ group.endpoints.length }})\n </span>\n </button>\n\n <!-- Group endpoints -->\n <div\n v-show=\"group.isExpanded\"\n :id=\"`group-${group.tag}`\"\n class=\"endpoint-group__items\"\n role=\"group\"\n :aria-label=\"`${group.tag} endpoints`\"\n >\n <button\n v-for=\"endpoint in group.endpoints\"\n :key=\"endpoint.key\"\n type=\"button\"\n :class=\"[\n 'endpoint-item',\n { 'endpoint-item--selected': isSelected(endpoint) }\n ]\"\n :aria-selected=\"isSelected(endpoint)\"\n @click=\"handleEndpointClick(endpoint)\"\n >\n <!-- Method badge -->\n <span\n :class=\"[\n 'method-badge',\n `method-badge--${endpoint.method}`\n ]\"\n >\n {{ getMethodLabel(endpoint.method) }}\n </span>\n\n <!-- Path -->\n <span class=\"endpoint-item__path font-mono\">\n {{ endpoint.path }}\n </span>\n\n <!-- Status indicators -->\n <div class=\"endpoint-item__indicators\">\n <span\n v-if=\"endpoint.hasHandler\"\n class=\"endpoint-item__indicator endpoint-item__indicator--handler\"\n title=\"Has custom handler\"\n >\n <Code :size=\"12\" />\n </span>\n <span\n v-if=\"endpoint.hasSeed\"\n class=\"endpoint-item__indicator endpoint-item__indicator--seed\"\n title=\"Has seed data\"\n >\n <Sprout :size=\"12\" />\n </span>\n </div>\n </button>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.endpoint-list {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n\n.endpoint-list__empty {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--devtools-space-lg);\n}\n\n.endpoint-list__groups {\n flex: 1;\n overflow-y: auto;\n padding: var(--devtools-space-xs);\n}\n\n/* Group styles */\n.endpoint-group {\n margin-bottom: var(--devtools-space-xs);\n}\n\n.endpoint-group__header {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n width: 100%;\n padding: var(--devtools-space-sm) var(--devtools-space-sm);\n background: none;\n border: none;\n border-radius: var(--devtools-radius-sm);\n font-family: var(--devtools-font-sans);\n font-size: var(--font-size-1);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text);\n text-align: left;\n cursor: pointer;\n transition: background-color var(--devtools-transition-fast);\n}\n\n.endpoint-group__header:hover {\n background-color: var(--devtools-surface-elevated);\n}\n\n.endpoint-group__header:focus {\n outline: none;\n}\n\n.endpoint-group__header:focus-visible {\n outline: 2px solid var(--devtools-primary);\n outline-offset: -2px;\n}\n\n.endpoint-group__chevron {\n flex-shrink: 0;\n color: var(--devtools-text-muted);\n}\n\n.endpoint-group__tag {\n flex: 1;\n text-transform: capitalize;\n}\n\n.endpoint-group__count {\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-4);\n}\n\n.endpoint-group__items {\n padding-left: var(--devtools-space-md);\n}\n\n/* Endpoint item styles */\n.endpoint-item {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n width: 100%;\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n background: none;\n border: none;\n border-radius: var(--devtools-radius-sm);\n font-family: var(--devtools-font-sans);\n text-align: left;\n cursor: pointer;\n transition: background-color var(--devtools-transition-fast);\n}\n\n.endpoint-item:hover {\n background-color: var(--devtools-surface-elevated);\n}\n\n.endpoint-item:focus {\n outline: none;\n}\n\n.endpoint-item:focus-visible {\n outline: 2px solid var(--devtools-primary);\n outline-offset: -2px;\n}\n\n.endpoint-item--selected {\n background-color: color-mix(in srgb, var(--devtools-primary) 15%, transparent);\n}\n\n.endpoint-item--selected:hover {\n background-color: color-mix(in srgb, var(--devtools-primary) 20%, transparent);\n}\n\n.endpoint-item__path {\n flex: 1;\n font-size: var(--font-size-0);\n color: var(--devtools-text);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.endpoint-item__indicators {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n}\n\n.endpoint-item__indicator {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n border-radius: var(--devtools-radius-sm);\n}\n\n.endpoint-item__indicator--handler {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n color: var(--devtools-info);\n}\n\n.endpoint-item__indicator--seed {\n background-color: color-mix(in srgb, var(--devtools-success) 15%, transparent);\n color: var(--devtools-success);\n}\n</style>\n","<!--\n RoutesPage.vue - Endpoint Listing Page\n\n What: Displays a list of all available API endpoints from the OpenAPI spec\n How: Fetches endpoint data via WebSocket and displays in a searchable/filterable list\n Why: Allows developers to quickly browse and inspect available mock endpoints\n-->\n\n<script setup lang=\"ts\">\nimport { ChevronDown, ChevronUp, Code, Filter, Route, Search, Sprout, X } from 'lucide-vue-next';\nimport { computed, onMounted, onUnmounted, ref, watch } from 'vue';\n\nimport EndpointDetail from '@/components/EndpointDetail.vue';\nimport EndpointList from '@/components/EndpointList.vue';\nimport { useWebSocket } from '@/composables/useWebSocket';\nimport { type HttpMethod, type RegistryData, useRegistryStore } from '@/stores/registry';\n\n// Store and WebSocket\nconst registryStore = useRegistryStore();\nconst { send, on, connected } = useWebSocket();\n\n// Local UI state\nconst showFilters = ref(false);\nconst searchInputRef = ref<HTMLInputElement | null>(null);\n\n// HTTP methods for filter (matches HttpMethod type from registry store)\nconst httpMethods: HttpMethod[] = [\n 'get',\n 'post',\n 'put',\n 'patch',\n 'delete',\n 'options',\n 'head',\n 'trace',\n];\n\n/**\n * Fetch registry data when connected\n */\nfunction fetchRegistry(): void {\n if (connected.value) {\n registryStore.setLoading(true);\n send({ type: 'get:registry' });\n }\n}\n\n/**\n * Handle registry data from server\n */\nfunction handleRegistryData(data: RegistryData): void {\n registryStore.setRegistryData(data);\n registryStore.setLoading(false);\n}\n\n/**\n * Handle endpoint selection\n */\nfunction handleSelectEndpoint(key: string): void {\n registryStore.selectEndpoint(key);\n}\n\n/**\n * Handle group toggle\n */\nfunction handleToggleGroup(tag: string): void {\n registryStore.toggleGroup(tag);\n}\n\n/**\n * Handle search input\n */\nfunction handleSearchInput(event: Event): void {\n const target = event.target as HTMLInputElement;\n registryStore.setSearchQuery(target.value);\n}\n\n/**\n * Clear search\n */\nfunction clearSearch(): void {\n registryStore.setSearchQuery('');\n searchInputRef.value?.focus();\n}\n\n/**\n * Toggle method filter\n */\nfunction toggleMethod(method: HttpMethod): void {\n registryStore.toggleMethodFilter(method);\n}\n\n/**\n * Check if method is active in filter\n */\nfunction isMethodActive(method: HttpMethod): boolean {\n return registryStore.filter.methods.includes(method);\n}\n\n/**\n * Toggle handler filter\n */\nfunction toggleHandlerFilter(): void {\n const current = registryStore.filter.hasHandler;\n registryStore.setHandlerFilter(current === true ? null : true);\n}\n\n/**\n * Toggle seed filter\n */\nfunction toggleSeedFilter(): void {\n const current = registryStore.filter.hasSeed;\n registryStore.setSeedFilter(current === true ? null : true);\n}\n\n/**\n * Clear all filters\n */\nfunction clearAllFilters(): void {\n registryStore.clearFilters();\n}\n\n/**\n * Toggle filter panel visibility\n */\nfunction toggleFilters(): void {\n showFilters.value = !showFilters.value;\n}\n\n/**\n * Computed: Has active filters\n */\nconst hasActiveFilters = computed(() => registryStore.hasActiveFilters());\n\n// Event cleanup functions for WebSocket subscriptions\nlet unsubRegistry: (() => void) | null = null;\nlet unsubHandlers: (() => void) | null = null;\nlet unsubSeeds: (() => void) | null = null;\n\n// Subscribe to registry events and setup cleanup\nonMounted(() => {\n // Subscribe to WebSocket events (on() returns unsubscribe function)\n unsubRegistry = on<RegistryData>('registry', handleRegistryData);\n unsubHandlers = on('handlers:updated', () => fetchRegistry());\n unsubSeeds = on('seeds:updated', () => fetchRegistry());\n\n // Fetch registry when already connected\n if (connected.value) {\n fetchRegistry();\n }\n});\n\n// Cleanup event subscriptions on unmount to prevent memory leaks\nonUnmounted(() => {\n unsubRegistry?.();\n unsubHandlers?.();\n unsubSeeds?.();\n});\n\n// Re-fetch when connection is established\nwatch(connected, (isConnected) => {\n if (isConnected) {\n fetchRegistry();\n }\n});\n</script>\n\n<template>\n <div class=\"routes-page\">\n <!-- Toolbar -->\n <div class=\"routes-toolbar\">\n <!-- Search -->\n <div class=\"routes-search\">\n <Search :size=\"16\" class=\"routes-search__icon\" />\n <input\n ref=\"searchInputRef\"\n type=\"text\"\n class=\"routes-search__input input\"\n placeholder=\"Search endpoints...\"\n :value=\"registryStore.searchQuery\"\n @input=\"handleSearchInput\"\n />\n <button\n v-if=\"registryStore.searchQuery\"\n type=\"button\"\n class=\"routes-search__clear btn btn--ghost btn--icon\"\n title=\"Clear search\"\n @click=\"clearSearch\"\n >\n <X :size=\"14\" />\n </button>\n </div>\n\n <!-- Filter toggle -->\n <button\n type=\"button\"\n :class=\"[\n 'routes-filter-toggle btn btn--secondary',\n { 'routes-filter-toggle--active': hasActiveFilters }\n ]\"\n :aria-expanded=\"showFilters\"\n @click=\"toggleFilters\"\n >\n <Filter :size=\"16\" />\n <span>Filters</span>\n <span v-if=\"hasActiveFilters\" class=\"routes-filter-toggle__badge\">\n {{ registryStore.filter.methods.length +\n (registryStore.filter.hasHandler ? 1 : 0) +\n (registryStore.filter.hasSeed ? 1 : 0) }}\n </span>\n <component :is=\"showFilters ? ChevronUp : ChevronDown\" :size=\"14\" />\n </button>\n\n <!-- Stats -->\n <div class=\"routes-stats\">\n <span class=\"routes-stats__item\">\n {{ registryStore.filteredEndpoints.length }} endpoints\n </span>\n <span class=\"routes-stats__separator\">|</span>\n <span class=\"routes-stats__item\">\n {{ registryStore.allTags.length }} tags\n </span>\n </div>\n </div>\n\n <!-- Filter panel -->\n <div v-if=\"showFilters\" class=\"routes-filters\">\n <!-- Method filters -->\n <div class=\"routes-filters__section\">\n <h4 class=\"routes-filters__title\">Methods</h4>\n <div class=\"routes-filters__methods\">\n <button\n v-for=\"method in httpMethods\"\n :key=\"method\"\n type=\"button\"\n :class=\"[\n 'method-badge',\n `method-badge--${method}`,\n { 'method-badge--inactive': !isMethodActive(method) && registryStore.filter.methods.length > 0 }\n ]\"\n @click=\"toggleMethod(method)\"\n >\n {{ method.toUpperCase() }}\n </button>\n </div>\n </div>\n\n <!-- Status filters -->\n <div class=\"routes-filters__section\">\n <h4 class=\"routes-filters__title\">Status</h4>\n <div class=\"routes-filters__status\">\n <button\n type=\"button\"\n :class=\"[\n 'routes-filters__status-btn',\n { 'routes-filters__status-btn--active': registryStore.filter.hasHandler }\n ]\"\n @click=\"toggleHandlerFilter\"\n >\n <Code :size=\"14\" />\n <span>Has Handler</span>\n </button>\n <button\n type=\"button\"\n :class=\"[\n 'routes-filters__status-btn',\n { 'routes-filters__status-btn--active': registryStore.filter.hasSeed }\n ]\"\n @click=\"toggleSeedFilter\"\n >\n <Sprout :size=\"14\" />\n <span>Has Seed</span>\n </button>\n </div>\n </div>\n\n <!-- Clear filters -->\n <div v-if=\"hasActiveFilters\" class=\"routes-filters__actions\">\n <button\n type=\"button\"\n class=\"btn btn--ghost\"\n @click=\"clearAllFilters\"\n >\n <X :size=\"14\" />\n Clear all filters\n </button>\n </div>\n </div>\n\n <!-- Main content: split panel -->\n <div class=\"routes-content\">\n <!-- Loading state -->\n <div v-if=\"registryStore.isLoading\" class=\"routes-loading\">\n <div class=\"routes-loading__spinner\" />\n <span class=\"text-muted\">Loading endpoints...</span>\n </div>\n\n <!-- Error state -->\n <div v-else-if=\"registryStore.error\" class=\"routes-error\">\n <p class=\"routes-error__message\">{{ registryStore.error }}</p>\n <button type=\"button\" class=\"btn btn--primary\" @click=\"fetchRegistry\">\n Retry\n </button>\n </div>\n\n <!-- Empty state -->\n <div v-else-if=\"registryStore.endpoints.length === 0\" class=\"routes-empty empty-state\">\n <Route :size=\"48\" class=\"empty-state__icon\" />\n <h3 class=\"empty-state__title\">No endpoints found</h3>\n <p class=\"empty-state__description\">\n No API endpoints are available. Make sure your OpenAPI spec is loaded.\n </p>\n </div>\n\n <!-- No results state -->\n <div v-else-if=\"registryStore.filteredEndpoints.length === 0\" class=\"routes-empty empty-state\">\n <Search :size=\"48\" class=\"empty-state__icon\" />\n <h3 class=\"empty-state__title\">No matching endpoints</h3>\n <p class=\"empty-state__description\">\n Try adjusting your search or filters.\n </p>\n <button\n v-if=\"hasActiveFilters\"\n type=\"button\"\n class=\"btn btn--secondary\"\n @click=\"clearAllFilters\"\n >\n Clear filters\n </button>\n </div>\n\n <!-- Split panel layout -->\n <template v-else>\n <!-- Endpoint list panel -->\n <div class=\"routes-list-panel\">\n <EndpointList\n :groups=\"registryStore.groupedEndpoints\"\n :selected-key=\"registryStore.selectedEndpointKey\"\n @select=\"handleSelectEndpoint\"\n @toggle-group=\"handleToggleGroup\"\n />\n </div>\n\n <!-- Endpoint detail panel -->\n <div class=\"routes-detail-panel\">\n <EndpointDetail :endpoint=\"registryStore.selectedEndpoint\" />\n </div>\n </template>\n </div>\n </div>\n</template>\n\n<style scoped>\n.routes-page {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n\n/* Toolbar */\n.routes-toolbar {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-md);\n background-color: var(--devtools-surface);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.routes-search {\n position: relative;\n flex: 1;\n max-width: 400px;\n}\n\n.routes-search__icon {\n position: absolute;\n left: var(--devtools-space-sm);\n top: 50%;\n transform: translateY(-50%);\n color: var(--devtools-text-muted);\n pointer-events: none;\n}\n\n.routes-search__input {\n padding-left: calc(var(--devtools-space-sm) + 24px);\n padding-right: calc(var(--devtools-space-sm) + 24px);\n}\n\n.routes-search__clear {\n position: absolute;\n right: var(--devtools-space-xs);\n top: 50%;\n transform: translateY(-50%);\n padding: var(--devtools-space-xs);\n}\n\n.routes-filter-toggle {\n flex-shrink: 0;\n}\n\n.routes-filter-toggle--active {\n background-color: color-mix(in srgb, var(--devtools-primary) 15%, transparent);\n border-color: var(--devtools-primary);\n color: var(--devtools-primary);\n}\n\n.routes-filter-toggle__badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 var(--devtools-space-xs);\n background-color: var(--devtools-primary);\n color: var(--devtools-text-inverted);\n border-radius: 9px;\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-6);\n}\n\n.routes-stats {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n margin-left: auto;\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n}\n\n.routes-stats__separator {\n opacity: 0.5;\n}\n\n/* Filter panel */\n.routes-filters {\n display: flex;\n flex-wrap: wrap;\n align-items: flex-start;\n gap: var(--devtools-space-lg);\n padding: var(--devtools-space-md);\n background-color: var(--devtools-surface-elevated);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.routes-filters__section {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-sm);\n}\n\n.routes-filters__title {\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-6);\n color: var(--devtools-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin: 0;\n}\n\n.routes-filters__methods {\n display: flex;\n flex-wrap: wrap;\n gap: var(--devtools-space-xs);\n}\n\n.routes-filters__methods .method-badge {\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.routes-filters__methods .method-badge--inactive {\n opacity: 0.4;\n}\n\n.routes-filters__status {\n display: flex;\n gap: var(--devtools-space-sm);\n}\n\n.routes-filters__status-btn {\n display: inline-flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n background-color: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-sm);\n font-family: var(--devtools-font-sans);\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.routes-filters__status-btn:hover {\n background-color: var(--devtools-surface-elevated);\n color: var(--devtools-text);\n}\n\n.routes-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-primary) 15%, transparent);\n border-color: var(--devtools-primary);\n color: var(--devtools-primary);\n}\n\n.routes-filters__actions {\n display: flex;\n align-items: flex-end;\n margin-left: auto;\n}\n\n/* Main content */\n.routes-content {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n/* Loading state */\n.routes-loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 100%;\n gap: var(--devtools-space-md);\n}\n\n.routes-loading__spinner {\n width: 32px;\n height: 32px;\n border: 3px solid var(--devtools-border);\n border-top-color: var(--devtools-primary);\n border-radius: 50%;\n animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n/* Error state */\n.routes-error {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 100%;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-xl);\n}\n\n.routes-error__message {\n color: var(--devtools-error);\n margin: 0;\n}\n\n/* Empty state */\n.routes-empty {\n width: 100%;\n}\n\n/* Split panels */\n.routes-list-panel {\n width: var(--devtools-sidebar-width);\n min-width: 200px;\n max-width: 400px;\n border-right: 1px solid var(--devtools-border);\n background-color: var(--devtools-surface);\n overflow: hidden;\n}\n\n.routes-detail-panel {\n flex: 1;\n overflow: hidden;\n background-color: var(--devtools-bg);\n}\n</style>\n","<!--\n TimelineDetail.vue - Timeline Entry Detail Panel\n\n What: Displays full request and response details for a selected timeline entry\n How: Shows headers, query params, body content in organized collapsible sections\n Why: Allows developers to inspect API traffic in detail for debugging\n-->\n\n<script setup lang=\"ts\">\nimport { Check, ChevronDown, ChevronRight, Clock, Copy, Zap } from 'lucide-vue-next';\n\nimport { computed, ref } from 'vue';\n\nimport type { TimelineEntry } from '@/stores/timeline';\n\nimport { getMethodLabel } from '@/utils/format';\n\n/**\n * Component props\n */\ninterface Props {\n /** The timeline entry to display */\n entry: TimelineEntry | null;\n}\n\nconst props = defineProps<Props>();\n\n/**\n * Section expansion state\n */\nconst expandedSections = ref({\n requestHeaders: true,\n requestQuery: true,\n requestBody: true,\n responseHeaders: true,\n responseBody: true,\n});\n\n/**\n * Copy feedback state\n */\nconst copiedField = ref<string | null>(null);\n\n/**\n * Format timestamp for display\n */\nconst formattedTimestamp = computed(() => {\n if (!props.entry) return '';\n const date = new Date(props.entry.request.timestamp);\n return date.toLocaleString('en-US', {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n fractionalSecondDigits: 3,\n hour12: false,\n });\n});\n\n/**\n * Format duration for display\n */\nconst formattedDuration = computed(() => {\n if (props.entry?.duration == null) return 'pending...';\n if (props.entry.duration < 1000) {\n return `${props.entry.duration}ms`;\n }\n return `${(props.entry.duration / 1000).toFixed(2)}s`;\n});\n\n/**\n * Get status badge class based on status code\n */\nconst statusClass = computed(() => {\n if (!props.entry?.status) return 'status-badge--pending';\n if (props.entry.status < 200) return 'status-badge--1xx';\n if (props.entry.status < 300) return 'status-badge--2xx';\n if (props.entry.status < 400) return 'status-badge--3xx';\n if (props.entry.status < 500) return 'status-badge--4xx';\n return 'status-badge--5xx';\n});\n\n/**\n * Check if request has query parameters\n */\nconst hasQueryParams = computed(() => {\n if (!props.entry?.request.query) return false;\n return Object.keys(props.entry.request.query).length > 0;\n});\n\n/**\n * Check if request has headers\n */\nconst hasRequestHeaders = computed(() => {\n if (!props.entry?.request.headers) return false;\n return Object.keys(props.entry.request.headers).length > 0;\n});\n\n/**\n * Check if request has body\n */\nconst hasRequestBody = computed(() => {\n return props.entry?.request.body !== undefined && props.entry?.request.body !== null;\n});\n\n/**\n * Check if response has headers\n */\nconst hasResponseHeaders = computed(() => {\n if (!props.entry?.response?.headers) return false;\n return Object.keys(props.entry.response.headers).length > 0;\n});\n\n/**\n * Check if response has body\n */\nconst hasResponseBody = computed(() => {\n return props.entry?.response?.body !== undefined && props.entry?.response?.body !== null;\n});\n\n/**\n * Format JSON for display\n */\nfunction formatJson(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Toggle section expansion\n */\nfunction toggleSection(section: keyof typeof expandedSections.value): void {\n expandedSections.value[section] = !expandedSections.value[section];\n}\n\n/**\n * Copy text to clipboard\n */\nasync function copyToClipboard(text: string, fieldId: string): Promise<void> {\n try {\n await navigator.clipboard.writeText(text);\n copiedField.value = fieldId;\n setTimeout(() => {\n copiedField.value = null;\n }, 2000);\n } catch (err) {\n console.error('Failed to copy:', err);\n }\n}\n\n/**\n * Copy full entry as JSON\n */\nasync function copyFullEntry(): Promise<void> {\n if (!props.entry) return;\n const data = {\n request: props.entry.request,\n response: props.entry.response,\n };\n await copyToClipboard(JSON.stringify(data, null, 2), 'full');\n}\n</script>\n\n<template>\n <div class=\"timeline-detail\">\n <!-- Empty state -->\n <div v-if=\"!entry\" class=\"timeline-detail__empty\">\n <Clock :size=\"48\" class=\"timeline-detail__empty-icon\" />\n <h3 class=\"timeline-detail__empty-title\">Select an entry</h3>\n <p class=\"timeline-detail__empty-description\">\n Click on a timeline entry to view its details.\n </p>\n </div>\n\n <!-- Entry details -->\n <div v-else class=\"timeline-detail__content\">\n <!-- Header with summary -->\n <div class=\"timeline-detail__header\">\n <div class=\"timeline-detail__summary\">\n <span :class=\"['method-badge', `method-badge--${entry.request.method.toLowerCase()}`]\">\n {{ getMethodLabel(entry.request.method) }}\n </span>\n <span class=\"timeline-detail__path font-mono\">{{ entry.request.path }}</span>\n </div>\n\n <div class=\"timeline-detail__meta\">\n <span v-if=\"entry.status !== null\" :class=\"['status-badge', statusClass]\">\n {{ entry.status }}\n </span>\n <span v-else class=\"status-badge status-badge--pending\">pending</span>\n\n <span class=\"timeline-detail__duration\">\n <Clock :size=\"14\" />\n {{ formattedDuration }}\n </span>\n\n <span v-if=\"entry.simulated\" class=\"timeline-detail__simulated\" title=\"Simulated response\">\n <Zap :size=\"14\" />\n Simulated\n </span>\n </div>\n\n <div class=\"timeline-detail__actions\">\n <button\n type=\"button\"\n class=\"btn btn--ghost btn--sm\"\n title=\"Copy as JSON\"\n @click=\"copyFullEntry\"\n >\n <component :is=\"copiedField === 'full' ? Check : Copy\" :size=\"14\" />\n {{ copiedField === 'full' ? 'Copied!' : 'Copy JSON' }}\n </button>\n </div>\n </div>\n\n <!-- Info section -->\n <div class=\"timeline-detail__info\">\n <div class=\"timeline-detail__info-item\">\n <span class=\"timeline-detail__info-label\">Timestamp</span>\n <span class=\"timeline-detail__info-value font-mono\">{{ formattedTimestamp }}</span>\n </div>\n <div class=\"timeline-detail__info-item\">\n <span class=\"timeline-detail__info-label\">Operation ID</span>\n <span class=\"timeline-detail__info-value font-mono\">{{ entry.request.operationId }}</span>\n </div>\n <div class=\"timeline-detail__info-item\">\n <span class=\"timeline-detail__info-label\">Request ID</span>\n <span class=\"timeline-detail__info-value font-mono\">{{ entry.id }}</span>\n </div>\n </div>\n\n <!-- Request section -->\n <div class=\"timeline-detail__section\">\n <h3 class=\"timeline-detail__section-title\">Request</h3>\n\n <!-- Query Parameters -->\n <div v-if=\"hasQueryParams\" class=\"timeline-detail__subsection\">\n <button\n type=\"button\"\n class=\"timeline-detail__subsection-header\"\n :aria-expanded=\"expandedSections.requestQuery\"\n aria-controls=\"requestQuery-panel\"\n @click=\"toggleSection('requestQuery')\"\n >\n <component\n :is=\"expandedSections.requestQuery ? ChevronDown : ChevronRight\"\n :size=\"16\"\n />\n <span>Query Parameters</span>\n <span class=\"text-muted\">({{ Object.keys(entry.request.query).length }})</span>\n </button>\n <div\n id=\"requestQuery-panel\"\n v-show=\"expandedSections.requestQuery\"\n class=\"timeline-detail__subsection-content\"\n >\n <div\n v-for=\"(value, key) in entry.request.query\"\n :key=\"key\"\n class=\"timeline-detail__kv-row\"\n >\n <span class=\"timeline-detail__kv-key font-mono\">{{ key }}</span>\n <span class=\"timeline-detail__kv-value font-mono\">\n {{ Array.isArray(value) ? value.join(', ') : value }}\n </span>\n </div>\n </div>\n </div>\n\n <!-- Request Headers -->\n <div v-if=\"hasRequestHeaders\" class=\"timeline-detail__subsection\">\n <button\n type=\"button\"\n class=\"timeline-detail__subsection-header\"\n :aria-expanded=\"expandedSections.requestHeaders\"\n aria-controls=\"requestHeaders-panel\"\n @click=\"toggleSection('requestHeaders')\"\n >\n <component\n :is=\"expandedSections.requestHeaders ? ChevronDown : ChevronRight\"\n :size=\"16\"\n />\n <span>Headers</span>\n <span class=\"text-muted\">({{ Object.keys(entry.request.headers).length }})</span>\n </button>\n <div\n id=\"requestHeaders-panel\"\n v-show=\"expandedSections.requestHeaders\"\n class=\"timeline-detail__subsection-content\"\n >\n <div\n v-for=\"(value, key) in entry.request.headers\"\n :key=\"key\"\n class=\"timeline-detail__kv-row\"\n >\n <span class=\"timeline-detail__kv-key font-mono\">{{ key }}</span>\n <span class=\"timeline-detail__kv-value font-mono\">{{ value }}</span>\n </div>\n </div>\n </div>\n\n <!-- Request Body -->\n <div v-if=\"hasRequestBody\" class=\"timeline-detail__subsection\">\n <div class=\"timeline-detail__subsection-header\" role=\"group\">\n <button\n type=\"button\"\n class=\"timeline-detail__subsection-toggle\"\n :aria-expanded=\"expandedSections.requestBody\"\n aria-controls=\"requestBody-panel\"\n @click=\"toggleSection('requestBody')\"\n >\n <component\n :is=\"expandedSections.requestBody ? ChevronDown : ChevronRight\"\n :size=\"16\"\n />\n <span>Body</span>\n </button>\n <button\n type=\"button\"\n class=\"btn btn--ghost btn--icon btn--sm\"\n title=\"Copy body\"\n @click.stop=\"copyToClipboard(formatJson(entry.request.body), 'reqBody')\"\n >\n <component :is=\"copiedField === 'reqBody' ? Check : Copy\" :size=\"12\" />\n </button>\n </div>\n <div\n id=\"requestBody-panel\"\n v-show=\"expandedSections.requestBody\"\n class=\"timeline-detail__subsection-content\"\n >\n <pre class=\"timeline-detail__json\">{{ formatJson(entry.request.body) }}</pre>\n </div>\n </div>\n </div>\n\n <!-- Response section -->\n <div v-if=\"entry.response\" class=\"timeline-detail__section\">\n <h3 class=\"timeline-detail__section-title\">Response</h3>\n\n <!-- Response Headers -->\n <div v-if=\"hasResponseHeaders\" class=\"timeline-detail__subsection\">\n <button\n type=\"button\"\n class=\"timeline-detail__subsection-header\"\n :aria-expanded=\"expandedSections.responseHeaders\"\n aria-controls=\"responseHeaders-panel\"\n @click=\"toggleSection('responseHeaders')\"\n >\n <component\n :is=\"expandedSections.responseHeaders ? ChevronDown : ChevronRight\"\n :size=\"16\"\n />\n <span>Headers</span>\n <span class=\"text-muted\">({{ Object.keys(entry.response.headers).length }})</span>\n </button>\n <div\n id=\"responseHeaders-panel\"\n v-show=\"expandedSections.responseHeaders\"\n class=\"timeline-detail__subsection-content\"\n >\n <div\n v-for=\"(value, key) in entry.response.headers\"\n :key=\"key\"\n class=\"timeline-detail__kv-row\"\n >\n <span class=\"timeline-detail__kv-key font-mono\">{{ key }}</span>\n <span class=\"timeline-detail__kv-value font-mono\">{{ value }}</span>\n </div>\n </div>\n </div>\n\n <!-- Response Body -->\n <div v-if=\"hasResponseBody\" class=\"timeline-detail__subsection\">\n <div class=\"timeline-detail__subsection-header\" role=\"group\">\n <button\n type=\"button\"\n class=\"timeline-detail__subsection-toggle\"\n :aria-expanded=\"expandedSections.responseBody\"\n aria-controls=\"responseBody-panel\"\n @click=\"toggleSection('responseBody')\"\n >\n <component\n :is=\"expandedSections.responseBody ? ChevronDown : ChevronRight\"\n :size=\"16\"\n />\n <span>Body</span>\n </button>\n <button\n type=\"button\"\n class=\"btn btn--ghost btn--icon btn--sm\"\n title=\"Copy body\"\n @click.stop=\"copyToClipboard(formatJson(entry.response.body), 'resBody')\"\n >\n <component :is=\"copiedField === 'resBody' ? Check : Copy\" :size=\"12\" />\n </button>\n </div>\n <div\n id=\"responseBody-panel\"\n v-show=\"expandedSections.responseBody\"\n class=\"timeline-detail__subsection-content\"\n >\n <pre class=\"timeline-detail__json\">{{ formatJson(entry.response.body) }}</pre>\n </div>\n </div>\n </div>\n\n <!-- Pending response state -->\n <div v-else class=\"timeline-detail__section timeline-detail__section--pending\">\n <h3 class=\"timeline-detail__section-title\">Response</h3>\n <div class=\"timeline-detail__pending\">\n <Clock :size=\"24\" class=\"timeline-detail__pending-icon\" />\n <span class=\"text-muted\">Waiting for response...</span>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.timeline-detail {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n\n/* Empty state */\n.timeline-detail__empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: var(--devtools-space-xl);\n text-align: center;\n}\n\n.timeline-detail__empty-icon {\n color: var(--devtools-text-muted);\n opacity: 0.5;\n margin-bottom: var(--devtools-space-md);\n}\n\n.timeline-detail__empty-title {\n font-size: var(--font-size-3);\n font-weight: var(--font-weight-6);\n color: var(--devtools-text);\n margin: 0 0 var(--devtools-space-sm) 0;\n}\n\n.timeline-detail__empty-description {\n font-size: var(--font-size-1);\n color: var(--devtools-text-muted);\n margin: 0;\n}\n\n/* Content */\n.timeline-detail__content {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow-y: auto;\n}\n\n/* Header */\n.timeline-detail__header {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-sm);\n padding: var(--devtools-space-md);\n background-color: var(--devtools-surface);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-detail__summary {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n}\n\n.timeline-detail__path {\n font-size: var(--font-size-2);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text);\n word-break: break-all;\n}\n\n.timeline-detail__meta {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-md);\n}\n\n.timeline-detail__duration {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n}\n\n.timeline-detail__simulated {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n font-size: var(--font-size-0);\n color: var(--devtools-warning);\n}\n\n.timeline-detail__actions {\n display: flex;\n gap: var(--devtools-space-sm);\n}\n\n/* Info section */\n.timeline-detail__info {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-md);\n background-color: var(--devtools-surface-elevated);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-detail__info-item {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-xs);\n}\n\n.timeline-detail__info-label {\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.timeline-detail__info-value {\n font-size: var(--font-size-1);\n color: var(--devtools-text);\n}\n\n/* Section */\n.timeline-detail__section {\n padding: var(--devtools-space-md);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-detail__section:last-child {\n border-bottom: none;\n}\n\n.timeline-detail__section-title {\n font-size: var(--font-size-1);\n font-weight: var(--font-weight-6);\n color: var(--devtools-text);\n margin: 0 0 var(--devtools-space-md) 0;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n/* Subsection */\n.timeline-detail__subsection {\n margin-bottom: var(--devtools-space-sm);\n}\n\n.timeline-detail__subsection:last-child {\n margin-bottom: 0;\n}\n\n.timeline-detail__subsection-header {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n width: 100%;\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n background-color: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-sm);\n}\n\n.timeline-detail__subsection-toggle {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n flex: 1;\n padding: 0;\n background: none;\n border: none;\n font-family: var(--devtools-font-sans);\n font-size: var(--font-size-1);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text);\n text-align: left;\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.timeline-detail__subsection-toggle:hover {\n color: var(--devtools-text-hover);\n}\n\n.timeline-detail__subsection-content {\n margin-top: var(--devtools-space-xs);\n padding: var(--devtools-space-sm);\n background-color: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-sm);\n}\n\n/* Key-value rows */\n.timeline-detail__kv-row {\n display: grid;\n grid-template-columns: minmax(120px, auto) 1fr;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-xs) 0;\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-detail__kv-row:last-child {\n border-bottom: none;\n}\n\n.timeline-detail__kv-key {\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text-muted);\n word-break: break-all;\n}\n\n.timeline-detail__kv-value {\n font-size: var(--font-size-0);\n color: var(--devtools-text);\n word-break: break-all;\n}\n\n/* JSON display */\n.timeline-detail__json {\n margin: 0;\n padding: var(--devtools-space-sm);\n background-color: var(--devtools-bg);\n border-radius: var(--devtools-radius-sm);\n font-family: var(--devtools-font-mono);\n font-size: var(--font-size-0);\n color: var(--devtools-text);\n white-space: pre-wrap;\n word-break: break-all;\n overflow-x: auto;\n}\n\n/* Status badges */\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n padding: 2px var(--devtools-space-sm);\n border-radius: var(--devtools-radius-sm);\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n font-family: var(--devtools-font-mono);\n}\n\n.status-badge--pending {\n background-color: color-mix(in srgb, var(--devtools-text-muted) 15%, transparent);\n color: var(--devtools-text-muted);\n}\n\n.status-badge--1xx {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n color: var(--devtools-info);\n}\n\n.status-badge--2xx {\n background-color: color-mix(in srgb, var(--devtools-success) 15%, transparent);\n color: var(--devtools-success);\n}\n\n.status-badge--3xx {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n color: var(--devtools-info);\n}\n\n.status-badge--4xx {\n background-color: color-mix(in srgb, var(--devtools-warning) 15%, transparent);\n color: var(--devtools-warning);\n}\n\n.status-badge--5xx {\n background-color: color-mix(in srgb, var(--devtools-error) 15%, transparent);\n color: var(--devtools-error);\n}\n\n/* Pending response */\n.timeline-detail__pending {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--devtools-space-sm);\n padding: var(--devtools-space-lg);\n}\n\n.timeline-detail__pending-icon {\n color: var(--devtools-text-muted);\n animation: pulse 2s ease-in-out infinite;\n}\n\n@keyframes pulse {\n 0%, 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.5;\n }\n}\n</style>\n","<!--\n TimelineEntry.vue - Timeline Entry Component\n\n What: Displays a single request/response entry in the timeline\n How: Shows method, path, status, duration with color-coded badges\n Why: Provides consistent visualization of API traffic in the timeline list\n-->\n\n<script setup lang=\"ts\">\nimport { AlertTriangle, CheckCircle, Clock, Zap } from 'lucide-vue-next';\nimport { computed } from 'vue';\n\nimport type { TimelineEntry } from '@/stores/timeline';\n\nimport { getMethodLabel } from '@/utils/format';\n\n/**\n * Component props\n */\ninterface Props {\n /** The timeline entry to display */\n entry: TimelineEntry;\n /** Whether this entry is currently selected */\n isSelected?: boolean;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n isSelected: false,\n});\n\n/**\n * Component events\n */\nconst emit = defineEmits<{\n /** Emitted when the entry is clicked */\n (e: 'select', id: string): void;\n}>();\n\n/**\n * Format timestamp for display\n */\nconst formattedTime = computed(() => {\n const date = new Date(props.entry.request.timestamp);\n return date.toLocaleTimeString('en-US', {\n hour12: false,\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n fractionalSecondDigits: 3,\n });\n});\n\n/**\n * Format duration for display\n */\nconst formattedDuration = computed(() => {\n if (props.entry.duration === null) {\n return 'pending...';\n }\n if (props.entry.duration < 1000) {\n return `${props.entry.duration}ms`;\n }\n return `${(props.entry.duration / 1000).toFixed(2)}s`;\n});\n\n/**\n * Get status badge class based on status code\n */\nconst statusClass = computed(() => {\n if (props.entry.status === null) return 'status-badge--pending';\n if (props.entry.status < 200) return 'status-badge--1xx';\n if (props.entry.status < 300) return 'status-badge--2xx';\n if (props.entry.status < 400) return 'status-badge--3xx';\n if (props.entry.status < 500) return 'status-badge--4xx';\n return 'status-badge--5xx';\n});\n\n/**\n * Status icon component based on status code\n */\nconst statusIcon = computed(() => {\n if (props.entry.status === null) return Clock;\n if (props.entry.status < 400) return CheckCircle;\n return AlertTriangle;\n});\n\n/**\n * Whether the response is pending\n */\nconst isPending = computed(() => props.entry.response === null);\n\n/**\n * Handle entry click\n */\nfunction handleClick(): void {\n emit('select', props.entry.id);\n}\n</script>\n\n<template>\n <button\n type=\"button\"\n :class=\"[\n 'timeline-entry',\n { 'timeline-entry--selected': isSelected },\n { 'timeline-entry--pending': isPending },\n { 'timeline-entry--simulated': entry.simulated }\n ]\"\n @click=\"handleClick\"\n >\n <!-- Timestamp -->\n <div class=\"timeline-entry__time font-mono text-muted\">\n {{ formattedTime }}\n </div>\n\n <!-- Method badge -->\n <div class=\"timeline-entry__method\">\n <span :class=\"['method-badge', `method-badge--${entry.request.method.toLowerCase()}`]\">\n {{ getMethodLabel(entry.request.method) }}\n </span>\n </div>\n\n <!-- Path -->\n <div class=\"timeline-entry__path font-mono\">\n {{ entry.request.path }}\n </div>\n\n <!-- Status badge -->\n <div class=\"timeline-entry__status\">\n <span v-if=\"entry.status !== null\" :class=\"['status-badge', statusClass]\">\n <component :is=\"statusIcon\" :size=\"12\" />\n {{ entry.status }}\n </span>\n <span v-else class=\"status-badge status-badge--pending\">\n <Clock :size=\"12\" />\n pending\n </span>\n </div>\n\n <!-- Duration -->\n <div class=\"timeline-entry__duration font-mono text-muted\">\n {{ formattedDuration }}\n </div>\n\n <!-- Simulated indicator -->\n <div v-if=\"entry.simulated\" class=\"timeline-entry__simulated\" title=\"Simulated response\">\n <Zap :size=\"14\" />\n </div>\n </button>\n</template>\n\n<style scoped>\n.timeline-entry {\n display: grid;\n grid-template-columns: 100px 80px 1fr auto 80px auto;\n align-items: center;\n gap: var(--devtools-space-md);\n width: 100%;\n padding: var(--devtools-space-sm) var(--devtools-space-md);\n background: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-sm);\n font-family: var(--devtools-font-sans);\n text-align: left;\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.timeline-entry:hover {\n background-color: var(--devtools-surface-elevated);\n border-color: var(--devtools-border-hover);\n}\n\n.timeline-entry:focus {\n outline: none;\n}\n\n.timeline-entry:focus-visible {\n outline: 2px solid var(--devtools-primary);\n outline-offset: -2px;\n}\n\n.timeline-entry--selected {\n background-color: color-mix(in srgb, var(--devtools-primary) 10%, transparent);\n border-color: var(--devtools-primary);\n}\n\n.timeline-entry--selected:hover {\n background-color: color-mix(in srgb, var(--devtools-primary) 15%, transparent);\n}\n\n.timeline-entry--pending {\n opacity: 0.7;\n}\n\n.timeline-entry--simulated {\n border-left: 3px solid var(--devtools-warning);\n}\n\n/* Time column */\n.timeline-entry__time {\n font-size: var(--font-size-0);\n}\n\n/* Path column */\n.timeline-entry__path {\n font-size: var(--font-size-1);\n color: var(--devtools-text);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Status column */\n.timeline-entry__status {\n display: flex;\n align-items: center;\n}\n\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n padding: 2px var(--devtools-space-sm);\n border-radius: var(--devtools-radius-sm);\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n font-family: var(--devtools-font-mono);\n}\n\n.status-badge--pending {\n background-color: color-mix(in srgb, var(--devtools-text-muted) 15%, transparent);\n color: var(--devtools-text-muted);\n}\n\n.status-badge--1xx {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n color: var(--devtools-info);\n}\n\n.status-badge--2xx {\n background-color: color-mix(in srgb, var(--devtools-success) 15%, transparent);\n color: var(--devtools-success);\n}\n\n.status-badge--3xx {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n color: var(--devtools-info);\n}\n\n.status-badge--4xx {\n background-color: color-mix(in srgb, var(--devtools-warning) 15%, transparent);\n color: var(--devtools-warning);\n}\n\n.status-badge--5xx {\n background-color: color-mix(in srgb, var(--devtools-error) 15%, transparent);\n color: var(--devtools-error);\n}\n\n/* Duration column */\n.timeline-entry__duration {\n font-size: var(--font-size-0);\n text-align: right;\n}\n\n/* Simulated indicator */\n.timeline-entry__simulated {\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--devtools-warning);\n}\n</style>\n","<!--\n TimelinePage.vue - Request/Response Timeline Page\n\n What: Displays a real-time timeline of API requests and responses\n How: Subscribes to WebSocket events and displays request/response logs with filtering\n Why: Allows developers to monitor and debug API traffic in real-time\n-->\n\n<script setup lang=\"ts\">\nimport { ChevronDown, ChevronUp, Clock, Filter, Search, Trash2, X } from 'lucide-vue-next';\nimport { computed, onMounted, onUnmounted, ref, watch } from 'vue';\n\nimport TimelineDetail from '@/components/TimelineDetail.vue';\nimport TimelineEntryComponent from '@/components/TimelineEntry.vue';\nimport { useWebSocket } from '@/composables/useWebSocket';\nimport {\n type HttpMethod,\n type RequestLogEntry,\n type ResponseLogEntry,\n type TimelineData,\n useTimelineStore,\n} from '@/stores/timeline';\n\n// Store and WebSocket\nconst timelineStore = useTimelineStore();\nconst { send, on, connected } = useWebSocket();\n\n// Local UI state\nconst showFilters = ref(false);\nconst searchInputRef = ref<HTMLInputElement | null>(null);\n\n// HTTP methods for filter\nconst httpMethods: HttpMethod[] = [\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'OPTIONS',\n 'HEAD',\n 'TRACE',\n];\n\n// Status categories for filter\nconst statusCategories = ['2xx', '3xx', '4xx', '5xx'] as const;\n\n/**\n * Fetch timeline data when connected\n */\nfunction fetchTimeline(): void {\n if (connected.value) {\n timelineStore.setLoading(true);\n send({ type: 'get:timeline' });\n }\n}\n\n/**\n * Handle timeline data from server\n */\nfunction handleTimelineData(data: TimelineData): void {\n timelineStore.setTimelineData(data);\n timelineStore.setLoading(false);\n}\n\n/**\n * Handle incoming request event\n */\nfunction handleRequest(data: RequestLogEntry): void {\n timelineStore.addRequest(data);\n}\n\n/**\n * Handle incoming response event\n */\nfunction handleResponse(data: ResponseLogEntry): void {\n timelineStore.addResponse(data);\n}\n\n/**\n * Handle timeline cleared event\n */\nfunction handleTimelineCleared(): void {\n timelineStore.clearTimeline();\n}\n\n/**\n * Clear timeline on server and locally\n */\nfunction clearTimeline(): void {\n send({ type: 'clear:timeline' });\n timelineStore.clearTimeline();\n}\n\n/**\n * Handle entry selection\n */\nfunction handleSelectEntry(id: string): void {\n timelineStore.selectEntry(id);\n}\n\n/**\n * Handle search input\n */\nfunction handleSearchInput(event: Event): void {\n const target = event.target as HTMLInputElement;\n timelineStore.setSearchQuery(target.value);\n}\n\n/**\n * Clear search\n */\nfunction clearSearch(): void {\n timelineStore.setSearchQuery('');\n searchInputRef.value?.focus();\n}\n\n/**\n * Toggle method filter\n */\nfunction toggleMethod(method: HttpMethod): void {\n timelineStore.toggleMethodFilter(method);\n}\n\n/**\n * Check if method is active in filter\n */\nfunction isMethodActive(method: HttpMethod): boolean {\n return timelineStore.filter.methods.includes(method);\n}\n\n/**\n * Toggle status filter\n */\nfunction toggleStatus(status: '1xx' | '2xx' | '3xx' | '4xx' | '5xx'): void {\n timelineStore.toggleStatusFilter(status);\n}\n\n/**\n * Check if status is active in filter\n */\nfunction isStatusActive(status: '1xx' | '2xx' | '3xx' | '4xx' | '5xx'): boolean {\n return timelineStore.filter.statusCodes.includes(status);\n}\n\n/**\n * Toggle simulated filter\n */\nfunction toggleSimulatedFilter(): void {\n const current = timelineStore.filter.simulatedOnly;\n timelineStore.setSimulatedFilter(current === true ? null : true);\n}\n\n/**\n * Clear all filters\n */\nfunction clearAllFilters(): void {\n timelineStore.clearFilters();\n}\n\n/**\n * Toggle filter panel visibility\n */\nfunction toggleFilters(): void {\n showFilters.value = !showFilters.value;\n}\n\n/**\n * Computed: Has active filters\n */\nconst hasActiveFilters = computed(() => timelineStore.hasActiveFilters());\n\n/**\n * Computed: Filter badge count\n */\nconst filterBadgeCount = computed(() => {\n return (\n timelineStore.filter.methods.length +\n timelineStore.filter.statusCodes.length +\n (timelineStore.filter.simulatedOnly !== null ? 1 : 0)\n );\n});\n\n// Event cleanup functions for WebSocket subscriptions\nlet unsubTimeline: (() => void) | null = null;\nlet unsubRequest: (() => void) | null = null;\nlet unsubResponse: (() => void) | null = null;\nlet unsubCleared: (() => void) | null = null;\n\n// Subscribe to timeline events and setup cleanup\nonMounted(() => {\n // Subscribe to WebSocket events\n unsubTimeline = on<TimelineData>('timeline', handleTimelineData);\n unsubRequest = on<RequestLogEntry>('request', handleRequest);\n unsubResponse = on<ResponseLogEntry>('response', handleResponse);\n unsubCleared = on('timeline:cleared', handleTimelineCleared);\n\n // Fetch timeline when already connected\n if (connected.value) {\n fetchTimeline();\n }\n});\n\n// Cleanup event subscriptions on unmount\nonUnmounted(() => {\n unsubTimeline?.();\n unsubRequest?.();\n unsubResponse?.();\n unsubCleared?.();\n});\n\n// Re-fetch when connection is established\nwatch(connected, (isConnected) => {\n if (isConnected) {\n fetchTimeline();\n }\n});\n</script>\n\n<template>\n <div class=\"timeline-page\">\n <!-- Toolbar -->\n <div class=\"timeline-toolbar\">\n <!-- Search -->\n <div class=\"timeline-search\">\n <Search :size=\"16\" class=\"timeline-search__icon\" />\n <input\n ref=\"searchInputRef\"\n type=\"text\"\n class=\"timeline-search__input input\"\n placeholder=\"Search by path or operation...\"\n :value=\"timelineStore.filter.searchQuery\"\n @input=\"handleSearchInput\"\n />\n <button\n v-if=\"timelineStore.filter.searchQuery\"\n type=\"button\"\n class=\"timeline-search__clear btn btn--ghost btn--icon\"\n title=\"Clear search\"\n @click=\"clearSearch\"\n >\n <X :size=\"14\" />\n </button>\n </div>\n\n <!-- Filter toggle -->\n <button\n type=\"button\"\n :class=\"[\n 'timeline-filter-toggle btn btn--secondary',\n { 'timeline-filter-toggle--active': hasActiveFilters }\n ]\"\n :aria-expanded=\"showFilters\"\n @click=\"toggleFilters\"\n >\n <Filter :size=\"16\" />\n <span>Filters</span>\n <span v-if=\"filterBadgeCount > 0\" class=\"timeline-filter-toggle__badge\">\n {{ filterBadgeCount }}\n </span>\n <component :is=\"showFilters ? ChevronUp : ChevronDown\" :size=\"14\" />\n </button>\n\n <!-- Stats -->\n <div class=\"timeline-stats\">\n <span class=\"timeline-stats__item\">\n {{ timelineStore.filteredEntries.length }} requests\n </span>\n <span v-if=\"timelineStore.averageDuration > 0\" class=\"timeline-stats__separator\">|</span>\n <span v-if=\"timelineStore.averageDuration > 0\" class=\"timeline-stats__item\">\n avg {{ timelineStore.averageDuration }}ms\n </span>\n </div>\n\n <!-- Clear button -->\n <button\n type=\"button\"\n class=\"btn btn--secondary btn--icon\"\n title=\"Clear timeline\"\n :disabled=\"timelineStore.entries.length === 0\"\n @click=\"clearTimeline\"\n >\n <Trash2 :size=\"16\" />\n </button>\n </div>\n\n <!-- Filter panel -->\n <div v-if=\"showFilters\" class=\"timeline-filters\">\n <!-- Method filters -->\n <div class=\"timeline-filters__section\">\n <h4 class=\"timeline-filters__title\">Methods</h4>\n <div class=\"timeline-filters__methods\">\n <button\n v-for=\"method in httpMethods\"\n :key=\"method\"\n type=\"button\"\n :class=\"[\n 'method-badge',\n `method-badge--${method.toLowerCase()}`,\n { 'method-badge--inactive': !isMethodActive(method) && timelineStore.filter.methods.length > 0 }\n ]\"\n @click=\"toggleMethod(method)\"\n >\n {{ method }}\n </button>\n </div>\n </div>\n\n <!-- Status filters -->\n <div class=\"timeline-filters__section\">\n <h4 class=\"timeline-filters__title\">Status</h4>\n <div class=\"timeline-filters__status\">\n <button\n v-for=\"status in statusCategories\"\n :key=\"status\"\n type=\"button\"\n :class=\"[\n 'timeline-filters__status-btn',\n `timeline-filters__status-btn--${status}`,\n { 'timeline-filters__status-btn--active': isStatusActive(status) }\n ]\"\n @click=\"toggleStatus(status)\"\n >\n {{ status }}\n <span class=\"timeline-filters__status-count\">\n ({{ timelineStore.statusCounts[status] }})\n </span>\n </button>\n </div>\n </div>\n\n <!-- Simulated filter -->\n <div class=\"timeline-filters__section\">\n <h4 class=\"timeline-filters__title\">Type</h4>\n <div class=\"timeline-filters__type\">\n <button\n type=\"button\"\n :class=\"[\n 'timeline-filters__status-btn',\n { 'timeline-filters__status-btn--active': timelineStore.filter.simulatedOnly }\n ]\"\n @click=\"toggleSimulatedFilter\"\n >\n Simulated only\n </button>\n </div>\n </div>\n\n <!-- Clear filters -->\n <div v-if=\"hasActiveFilters\" class=\"timeline-filters__actions\">\n <button\n type=\"button\"\n class=\"btn btn--ghost\"\n @click=\"clearAllFilters\"\n >\n <X :size=\"14\" />\n Clear all filters\n </button>\n </div>\n </div>\n\n <!-- Main content -->\n <div class=\"timeline-content\">\n <!-- Loading state -->\n <div v-if=\"timelineStore.isLoading\" class=\"timeline-loading\">\n <div class=\"timeline-loading__spinner\" />\n <span class=\"text-muted\">Loading timeline...</span>\n </div>\n\n <!-- Error state -->\n <div v-else-if=\"timelineStore.error\" class=\"timeline-error\">\n <p class=\"timeline-error__message\">{{ timelineStore.error }}</p>\n <button type=\"button\" class=\"btn btn--primary\" @click=\"fetchTimeline\">\n Retry\n </button>\n </div>\n\n <!-- Empty state -->\n <div v-else-if=\"timelineStore.entries.length === 0\" class=\"timeline-empty empty-state\">\n <Clock :size=\"48\" class=\"empty-state__icon\" />\n <h3 class=\"empty-state__title\">No requests yet</h3>\n <p class=\"empty-state__description\">\n API requests will appear here in real-time as they are made.\n </p>\n </div>\n\n <!-- No results state -->\n <div v-else-if=\"timelineStore.filteredEntries.length === 0\" class=\"timeline-empty empty-state\">\n <Search :size=\"48\" class=\"empty-state__icon\" />\n <h3 class=\"empty-state__title\">No matching requests</h3>\n <p class=\"empty-state__description\">\n Try adjusting your search or filters.\n </p>\n <button\n v-if=\"hasActiveFilters\"\n type=\"button\"\n class=\"btn btn--secondary\"\n @click=\"clearAllFilters\"\n >\n Clear filters\n </button>\n </div>\n\n <!-- Split panel layout -->\n <template v-else>\n <!-- Timeline list panel -->\n <div class=\"timeline-list-panel\">\n <div class=\"timeline-list\">\n <TimelineEntryComponent\n v-for=\"entry in timelineStore.filteredEntries\"\n :key=\"entry.id\"\n :entry=\"entry\"\n :is-selected=\"timelineStore.selectedEntryId === entry.id\"\n @select=\"handleSelectEntry\"\n />\n </div>\n </div>\n\n <!-- Timeline detail panel -->\n <div class=\"timeline-detail-panel\">\n <TimelineDetail :entry=\"timelineStore.selectedEntry\" />\n </div>\n </template>\n </div>\n </div>\n</template>\n\n<style scoped>\n.timeline-page {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n\n/* Toolbar */\n.timeline-toolbar {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-md);\n background-color: var(--devtools-surface);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-search {\n position: relative;\n flex: 1;\n max-width: 400px;\n}\n\n.timeline-search__icon {\n position: absolute;\n left: var(--devtools-space-sm);\n top: 50%;\n transform: translateY(-50%);\n color: var(--devtools-text-muted);\n pointer-events: none;\n}\n\n.timeline-search__input {\n padding-left: calc(var(--devtools-space-sm) + 24px);\n padding-right: calc(var(--devtools-space-sm) + 24px);\n}\n\n.timeline-search__clear {\n position: absolute;\n right: var(--devtools-space-xs);\n top: 50%;\n transform: translateY(-50%);\n padding: var(--devtools-space-xs);\n}\n\n.timeline-filter-toggle {\n flex-shrink: 0;\n}\n\n.timeline-filter-toggle--active {\n background-color: color-mix(in srgb, var(--devtools-primary) 15%, transparent);\n border-color: var(--devtools-primary);\n color: var(--devtools-primary);\n}\n\n.timeline-filter-toggle__badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 var(--devtools-space-xs);\n background-color: var(--devtools-primary);\n color: var(--devtools-text-inverted);\n border-radius: 9px;\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-6);\n}\n\n.timeline-stats {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n margin-left: auto;\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n}\n\n.timeline-stats__separator {\n opacity: 0.5;\n}\n\n/* Filter panel */\n.timeline-filters {\n display: flex;\n flex-wrap: wrap;\n align-items: flex-start;\n gap: var(--devtools-space-lg);\n padding: var(--devtools-space-md);\n background-color: var(--devtools-surface-elevated);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.timeline-filters__section {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-sm);\n}\n\n.timeline-filters__title {\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-6);\n color: var(--devtools-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin: 0;\n}\n\n.timeline-filters__methods {\n display: flex;\n flex-wrap: wrap;\n gap: var(--devtools-space-xs);\n}\n\n.timeline-filters__methods .method-badge {\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.timeline-filters__methods .method-badge--inactive {\n opacity: 0.4;\n}\n\n.timeline-filters__status {\n display: flex;\n gap: var(--devtools-space-sm);\n}\n\n.timeline-filters__type {\n display: flex;\n gap: var(--devtools-space-sm);\n}\n\n.timeline-filters__status-btn {\n display: inline-flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n background-color: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-sm);\n font-family: var(--devtools-font-sans);\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.timeline-filters__status-btn:hover {\n background-color: var(--devtools-surface-elevated);\n color: var(--devtools-text);\n}\n\n.timeline-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-primary) 15%, transparent);\n border-color: var(--devtools-primary);\n color: var(--devtools-primary);\n}\n\n.timeline-filters__status-btn--2xx.timeline-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-success) 15%, transparent);\n border-color: var(--devtools-success);\n color: var(--devtools-success);\n}\n\n.timeline-filters__status-btn--3xx.timeline-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-info) 15%, transparent);\n border-color: var(--devtools-info);\n color: var(--devtools-info);\n}\n\n.timeline-filters__status-btn--4xx.timeline-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-warning) 15%, transparent);\n border-color: var(--devtools-warning);\n color: var(--devtools-warning);\n}\n\n.timeline-filters__status-btn--5xx.timeline-filters__status-btn--active {\n background-color: color-mix(in srgb, var(--devtools-error) 15%, transparent);\n border-color: var(--devtools-error);\n color: var(--devtools-error);\n}\n\n.timeline-filters__status-count {\n font-size: var(--font-size-00);\n opacity: 0.7;\n}\n\n.timeline-filters__actions {\n display: flex;\n align-items: flex-end;\n margin-left: auto;\n}\n\n/* Main content */\n.timeline-content {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n/* Loading state */\n.timeline-loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 100%;\n gap: var(--devtools-space-md);\n}\n\n.timeline-loading__spinner {\n width: 32px;\n height: 32px;\n border: 3px solid var(--devtools-border);\n border-top-color: var(--devtools-primary);\n border-radius: 50%;\n animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n/* Error state */\n.timeline-error {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 100%;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-xl);\n}\n\n.timeline-error__message {\n color: var(--devtools-error);\n margin: 0;\n}\n\n/* Empty state */\n.timeline-empty {\n width: 100%;\n}\n\n/* Split panels */\n.timeline-list-panel {\n width: 50%;\n min-width: 300px;\n max-width: 600px;\n border-right: 1px solid var(--devtools-border);\n background-color: var(--devtools-bg);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.timeline-list {\n flex: 1;\n overflow-y: auto;\n padding: var(--devtools-space-sm);\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-xs);\n}\n\n.timeline-detail-panel {\n flex: 1;\n overflow: hidden;\n background-color: var(--devtools-bg);\n}\n</style>\n","/**\n * Data Table Utilities\n *\n * What: Pure helper functions for the DataTable component\n * How: Provides column discovery, cell formatting, and row key logic\n * Why: Extracted from DataTable.vue for testability and reuse\n *\n * @module utils/data-table\n */\n\n/**\n * Truncate a string to maxLen characters, appending an ellipsis if truncated.\n */\nexport function truncate(str: string, maxLen: number): string {\n if (str.length <= maxLen) return str;\n return `${str.slice(0, maxLen)}…`;\n}\n\n/**\n * Format a cell value for display.\n * Returns a human-readable string representation suitable for table cells.\n */\nexport function formatCell(value: unknown): string {\n if (value === null || value === undefined) return '--';\n if (typeof value === 'string') return truncate(value, 50);\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n if (Array.isArray(value)) return truncate(JSON.stringify(value), 50);\n if (typeof value === 'object') return truncate(JSON.stringify(value), 50);\n return String(value);\n}\n\n/**\n * Get a cell value from an item by column name.\n * Returns undefined for non-object items.\n */\nexport function getCellValue(item: unknown, column: string): unknown {\n if (typeof item !== 'object' || item === null) return undefined;\n return (item as Record<string, unknown>)[column];\n}\n\n/**\n * Get a stable key for a row, using the item's ID field value if it is\n * a string or number. Falls back to the row index otherwise.\n */\nexport function getRowKey(item: unknown, idField: string, index: number): string | number {\n const id = getCellValue(item, idField);\n if (typeof id === 'string' || typeof id === 'number') return id;\n return index;\n}\n\n/**\n * Discover columns from all items' keys.\n * Iterates over every item to accumulate all unique keys,\n * then places idField first if present.\n */\nexport function discoverColumns(items: unknown[], idField: string): string[] {\n if (items.length === 0) return [];\n\n const keySet = new Set<string>();\n for (const item of items) {\n if (typeof item === 'object' && item !== null) {\n for (const key of Object.keys(item as Record<string, unknown>)) {\n keySet.add(key);\n }\n }\n }\n\n if (keySet.size === 0) return [];\n\n const keys = Array.from(keySet);\n\n // Put idField first if it exists\n if (keys.includes(idField)) {\n return [idField, ...keys.filter((k) => k !== idField)];\n }\n\n return keys;\n}\n","<!--\n DataTable.vue - Dynamic Data Table Component\n\n What: Displays an array of objects as a scrollable table with dynamic columns\n How: Discovers columns from all items' keys, places idField first, formats cells\n Why: Shows store data in tabular form alongside the JSON editor on the Models page\n-->\n\n<script setup lang=\"ts\">\nimport { Database } from 'lucide-vue-next';\nimport { computed } from 'vue';\nimport { discoverColumns, formatCell, getCellValue, getRowKey } from '@/utils/data-table';\n\n/**\n * Component props\n */\ninterface Props {\n /** Array of items to display */\n items: unknown[];\n /** Name of the ID field (placed first in columns) */\n idField: string;\n /** Index of the currently selected row (-1 for none) */\n selectedIndex?: number;\n}\n\n/**\n * Component emits\n */\ninterface Emits {\n (e: 'select', index: number): void;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n selectedIndex: -1,\n});\n\nconst emit = defineEmits<Emits>();\n\n// ==========================================================================\n// Computed\n// ==========================================================================\n\n/**\n * Columns discovered from all items' keys, with idField placed first.\n */\nconst columns = computed<string[]>(() => discoverColumns(props.items, props.idField));\n\n// ==========================================================================\n// Methods\n// ==========================================================================\n\n/**\n * Handle row click\n */\nfunction onRowClick(index: number): void {\n emit('select', index);\n}\n\n/**\n * Get a stable key for a row, delegating to the utility function\n */\nfunction rowKey(item: unknown, index: number): string | number {\n return getRowKey(item, props.idField, index);\n}\n</script>\n\n<template>\n <div class=\"data-table\">\n <!-- Empty State -->\n <div v-if=\"items.length === 0\" class=\"data-table__empty\">\n <Database :size=\"32\" class=\"data-table__empty-icon\" />\n <span>No items</span>\n </div>\n\n <!-- Table -->\n <div v-else class=\"data-table__container\">\n <table class=\"data-table__table\">\n <thead>\n <tr>\n <th class=\"data-table__row-num\">#</th>\n <th\n v-for=\"col in columns\"\n :key=\"col\"\n :class=\"['data-table__header', { 'data-table__header--id': col === idField }]\"\n >\n {{ col }}\n </th>\n </tr>\n </thead>\n <tbody>\n <tr\n v-for=\"(item, index) in items\"\n :key=\"rowKey(item, index)\"\n :class=\"['data-table__row', { 'data-table__row--selected': index === selectedIndex }]\"\n @click=\"onRowClick(index)\"\n >\n <td class=\"data-table__row-num\">{{ index + 1 }}</td>\n <td\n v-for=\"col in columns\"\n :key=\"col\"\n :class=\"['data-table__cell', { 'data-table__cell--id': col === idField }]\"\n >\n {{ formatCell(getCellValue(item, col)) }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n\n <!-- Footer -->\n <div v-if=\"items.length > 0\" class=\"data-table__footer\">\n <span class=\"data-table__info\">{{ items.length }} items</span>\n <span class=\"data-table__info\">{{ columns.length }} columns</span>\n </div>\n </div>\n</template>\n\n<style scoped>\n.data-table {\n display: flex;\n flex-direction: column;\n background-color: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-md);\n overflow: hidden;\n height: 100%;\n}\n\n/* Empty State */\n.data-table__empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--devtools-space-sm);\n flex: 1;\n color: var(--devtools-text-muted);\n font-size: var(--font-size-1);\n}\n\n.data-table__empty-icon {\n opacity: 0.4;\n}\n\n/* Table Container */\n.data-table__container {\n flex: 1;\n overflow: auto;\n}\n\n.data-table__table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--font-size-0);\n font-family: var(--devtools-font-mono);\n}\n\n/* Header */\n.data-table__table thead {\n position: sticky;\n top: 0;\n z-index: 1;\n}\n\n.data-table__header {\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n text-align: left;\n font-weight: var(--font-weight-6);\n font-family: var(--devtools-font-sans);\n font-size: var(--font-size-0);\n background-color: var(--devtools-surface-elevated);\n border-bottom: 1px solid var(--devtools-border);\n white-space: nowrap;\n color: var(--devtools-text);\n}\n\n.data-table__header--id {\n color: var(--devtools-primary);\n}\n\n/* Row Numbers */\n.data-table__row-num {\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n text-align: right;\n color: var(--devtools-text-muted);\n font-size: var(--font-size-0);\n font-family: var(--devtools-font-mono);\n background-color: var(--devtools-surface-elevated);\n border-right: 1px solid var(--devtools-border);\n border-bottom: 1px solid var(--devtools-border);\n white-space: nowrap;\n min-width: 2ch;\n user-select: none;\n}\n\n/* Rows */\n.data-table__row {\n cursor: pointer;\n transition: background-color var(--devtools-transition-fast);\n}\n\n.data-table__row:hover {\n background-color: var(--devtools-surface-elevated);\n}\n\n.data-table__row--selected {\n background-color: color-mix(in srgb, var(--devtools-primary) 15%, transparent);\n}\n\n/* Cells */\n.data-table__cell {\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n border-bottom: 1px solid var(--devtools-border);\n white-space: nowrap;\n max-width: 300px;\n overflow: hidden;\n text-overflow: ellipsis;\n color: var(--devtools-text);\n}\n\n.data-table__cell--id {\n color: var(--devtools-primary);\n font-weight: var(--font-weight-5);\n}\n\n/* Footer */\n.data-table__footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n background-color: var(--devtools-surface-elevated);\n border-top: 1px solid var(--devtools-border);\n font-size: var(--font-size-0);\n}\n\n.data-table__info {\n color: var(--devtools-text-muted);\n}\n</style>\n","<!--\n JsonEditor.vue - JSON Editor Component\n\n What: Editable JSON textarea with syntax highlighting and validation\n How: Uses a textarea with syntax validation and formatting utilities\n Why: Allows developers to edit mock data in a user-friendly interface\n\n Features:\n - Real-time JSON validation\n - Syntax error display\n - Format/prettify button\n - Line numbers\n - Monospace font\n-->\n\n<script setup lang=\"ts\">\nimport { AlertCircle, Check } from 'lucide-vue-next';\nimport { computed, ref, watch } from 'vue';\n\n/**\n * Component props\n */\ninterface Props {\n /** JSON data to edit (will be stringified) */\n modelValue: unknown;\n /** Whether the editor is read-only */\n readonly?: boolean;\n /** Placeholder text when empty */\n placeholder?: string;\n /** Minimum height in pixels */\n minHeight?: number;\n}\n\n/**\n * Component emits\n */\ninterface Emits {\n (e: 'update:modelValue', value: unknown): void;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n readonly: false,\n placeholder: 'Enter JSON data...',\n minHeight: 200,\n});\n\nconst emit = defineEmits<Emits>();\n\n// ==========================================================================\n// State\n// ==========================================================================\n\n/** Current text content */\nconst text = ref<string>('');\n\n/** JSON validation error */\nconst validationError = ref<string | null>(null);\n\n/** Whether JSON is valid */\nconst isValid = computed(() => validationError.value === null);\n\n/** Line count for line numbers */\nconst lineCount = computed(() => {\n return text.value.split('\\n').length;\n});\n\n/** Line numbers array */\nconst lineNumbers = computed(() => {\n return Array.from({ length: lineCount.value }, (_, i) => i + 1);\n});\n\n// ==========================================================================\n// Initialization\n// ==========================================================================\n\n/**\n * Initialize text from modelValue\n */\nfunction initializeText(): void {\n try {\n text.value = JSON.stringify(props.modelValue, null, 2);\n validationError.value = null;\n } catch (err) {\n text.value = '';\n validationError.value = 'Invalid initial value';\n }\n}\n\n// Initialize on mount\ninitializeText();\n\n// Watch for external changes to modelValue\nwatch(\n () => props.modelValue,\n () => {\n // Only update if the parsed value differs (avoid cursor jumps during typing)\n try {\n const currentParsed = JSON.parse(text.value);\n if (JSON.stringify(currentParsed) !== JSON.stringify(props.modelValue)) {\n initializeText();\n }\n } catch {\n // If current text is invalid, always update\n initializeText();\n }\n },\n);\n\n// ==========================================================================\n// Actions\n// ==========================================================================\n\n/**\n * Handle text input\n */\nfunction handleInput(event: Event): void {\n const target = event.target as HTMLTextAreaElement;\n text.value = target.value;\n validateAndEmit();\n}\n\n/**\n * Validate JSON and emit update\n */\nfunction validateAndEmit(): void {\n if (text.value.trim() === '') {\n validationError.value = null;\n emit('update:modelValue', []);\n return;\n }\n\n try {\n const parsed = JSON.parse(text.value);\n validationError.value = null;\n emit('update:modelValue', parsed);\n } catch (err) {\n if (err instanceof Error) {\n // Extract line/column info from error message\n const match = err.message.match(/position (\\d+)/);\n if (match) {\n const position = Number.parseInt(match[1], 10);\n const lines = text.value.substring(0, position).split('\\n');\n const line = lines.length;\n const column = lines[lines.length - 1].length + 1;\n validationError.value = `Line ${line}, Column ${column}: ${err.message}`;\n } else {\n validationError.value = err.message;\n }\n } else {\n validationError.value = 'Invalid JSON';\n }\n }\n}\n\n/**\n * Format/prettify the JSON\n */\nfunction formatJson(): void {\n try {\n const parsed = JSON.parse(text.value);\n text.value = JSON.stringify(parsed, null, 2);\n validationError.value = null;\n emit('update:modelValue', parsed);\n } catch {\n // If invalid, do nothing\n }\n}\n\n/**\n * Handle Tab key for indentation\n */\nfunction handleKeyDown(event: KeyboardEvent): void {\n if (event.key === 'Tab') {\n event.preventDefault();\n const target = event.target as HTMLTextAreaElement;\n const start = target.selectionStart;\n const end = target.selectionEnd;\n\n // Insert 2 spaces\n const newText = `${text.value.substring(0, start)} ${text.value.substring(end)}`;\n text.value = newText;\n\n // Move cursor\n setTimeout(() => {\n target.selectionStart = target.selectionEnd = start + 2;\n }, 0);\n\n validateAndEmit();\n }\n}\n\n// ==========================================================================\n// Expose methods\n// ==========================================================================\n\ndefineExpose({\n formatJson,\n isValid,\n});\n</script>\n\n<template>\n <div class=\"json-editor\">\n <!-- Editor Container -->\n <div class=\"json-editor__container\">\n <!-- Line Numbers -->\n <div class=\"json-editor__lines\" aria-hidden=\"true\">\n <div\n v-for=\"lineNum in lineNumbers\"\n :key=\"lineNum\"\n class=\"json-editor__line-number\"\n >\n {{ lineNum }}\n </div>\n </div>\n\n <!-- Textarea -->\n <textarea\n :value=\"text\"\n :readonly=\"readonly\"\n :placeholder=\"placeholder\"\n :style=\"{ minHeight: `${minHeight}px` }\"\n class=\"json-editor__textarea\"\n spellcheck=\"false\"\n @input=\"handleInput\"\n @keydown=\"handleKeyDown\"\n />\n </div>\n\n <!-- Status Bar -->\n <div class=\"json-editor__status\">\n <div class=\"json-editor__status-left\">\n <!-- Validation Status -->\n <div v-if=\"isValid\" class=\"json-editor__valid\">\n <Check :size=\"14\" />\n <span>Valid JSON</span>\n </div>\n <div v-else-if=\"validationError\" class=\"json-editor__error\">\n <AlertCircle :size=\"14\" />\n <span>{{ validationError }}</span>\n </div>\n </div>\n\n <div class=\"json-editor__status-right\">\n <!-- Line Count -->\n <span class=\"json-editor__info\">{{ lineCount }} lines</span>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.json-editor {\n display: flex;\n flex-direction: column;\n background-color: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-md);\n overflow: hidden;\n}\n\n/* Editor Container */\n.json-editor__container {\n display: flex;\n overflow: auto;\n flex: 1;\n}\n\n/* Line Numbers */\n.json-editor__lines {\n display: flex;\n flex-direction: column;\n padding: var(--devtools-space-sm) var(--devtools-space-xs);\n background-color: var(--devtools-surface-elevated);\n border-right: 1px solid var(--devtools-border);\n user-select: none;\n flex-shrink: 0;\n}\n\n.json-editor__line-number {\n height: 1.5em;\n line-height: 1.5;\n text-align: right;\n font-family: var(--devtools-font-mono);\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n min-width: 2ch;\n padding-right: var(--devtools-space-xs);\n}\n\n/* Textarea */\n.json-editor__textarea {\n flex: 1;\n padding: var(--devtools-space-sm);\n background-color: var(--devtools-surface);\n color: var(--devtools-text);\n border: none;\n outline: none;\n resize: vertical;\n font-family: var(--devtools-font-mono);\n font-size: var(--font-size-0);\n line-height: 1.5;\n tab-size: 2;\n white-space: pre;\n overflow-wrap: normal;\n overflow-x: auto;\n}\n\n.json-editor__textarea::placeholder {\n color: var(--devtools-text-muted);\n opacity: 0.6;\n}\n\n.json-editor__textarea:focus {\n outline: 2px solid var(--devtools-primary);\n outline-offset: -2px;\n}\n\n.json-editor__textarea[readonly] {\n background-color: var(--devtools-surface-elevated);\n cursor: not-allowed;\n opacity: 0.7;\n}\n\n/* Status Bar */\n.json-editor__status {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n background-color: var(--devtools-surface-elevated);\n border-top: 1px solid var(--devtools-border);\n font-size: var(--font-size-0);\n}\n\n.json-editor__status-left,\n.json-editor__status-right {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n}\n\n/* Validation Indicators */\n.json-editor__valid {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n color: var(--devtools-success);\n}\n\n.json-editor__error {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n color: var(--devtools-error);\n}\n\n.json-editor__info {\n color: var(--devtools-text-muted);\n}\n\n/* Dark mode adjustments */\n@media (prefers-color-scheme: dark) {\n .json-editor__textarea {\n color: #e2e8f0;\n }\n\n .json-editor__textarea::placeholder {\n color: #64748b;\n }\n}\n</style>\n","/**\n * Notifications Composable\n *\n * What: Provides consistent user feedback mechanism for the DevTools\n * How: Manages toast notifications and confirmation modals\n * Why: Replaces inconsistent alert()/confirm()/console.log() usage\n *\n * Features:\n * - Toast notifications for success/error/info messages\n * - Confirmation modals with custom messages\n * - Auto-dismiss for toast notifications\n * - Centralized state management\n */\n\nimport { reactive, ref } from 'vue';\n\n/**\n * Toast notification types\n */\nexport type ToastType = 'success' | 'error' | 'info' | 'warning';\n\n/**\n * Toast notification\n */\nexport interface Toast {\n id: string;\n type: ToastType;\n message: string;\n duration: number;\n timestamp: number;\n}\n\n/**\n * Confirmation dialog state\n */\nexport interface ConfirmDialog {\n visible: boolean;\n title: string;\n message: string;\n confirmText: string;\n cancelText: string;\n onConfirm: (() => void) | null;\n onCancel: (() => void) | null;\n}\n\n// ==========================================================================\n// Global State\n// ==========================================================================\n\nconst toasts = ref<Toast[]>([]);\nconst confirmDialog = reactive<ConfirmDialog>({\n visible: false,\n title: '',\n message: '',\n confirmText: 'Confirm',\n cancelText: 'Cancel',\n onConfirm: null,\n onCancel: null,\n});\n\n// Track active timeout IDs to prevent orphaned timers\nconst timeouts = new Map<string, ReturnType<typeof setTimeout>>();\n\n// Track pending confirm dialog promise resolver\nlet pendingResolve: ((value: boolean) => void) | null = null;\n\n// ==========================================================================\n// Helper Functions\n// ==========================================================================\n\nlet toastIdCounter = 0;\n\nfunction generateToastId(): string {\n return `toast-${Date.now()}-${toastIdCounter++}`;\n}\n\nfunction addToast(type: ToastType, message: string, duration = 3000): string {\n const id = generateToastId();\n const toast: Toast = {\n id,\n type,\n message,\n duration,\n timestamp: Date.now(),\n };\n\n toasts.value.push(toast);\n\n // Auto-dismiss\n if (duration > 0) {\n const timeoutId = setTimeout(() => {\n removeToast(id);\n timeouts.delete(id);\n }, duration);\n timeouts.set(id, timeoutId);\n }\n\n return id;\n}\n\nfunction removeToast(id: string): void {\n // Clear the timeout if it exists\n const timeoutId = timeouts.get(id);\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId);\n timeouts.delete(id);\n }\n\n // Remove the toast from the array\n const index = toasts.value.findIndex((t) => t.id === id);\n if (index !== -1) {\n toasts.value.splice(index, 1);\n }\n}\n\n// ==========================================================================\n// Composable\n// ==========================================================================\n\n/**\n * Notifications composable\n *\n * Provides methods for showing toast notifications and confirmation dialogs\n */\nexport function useNotifications() {\n /**\n * Show a success toast notification\n */\n function success(message: string, duration?: number): string {\n return addToast('success', message, duration);\n }\n\n /**\n * Show an error toast notification\n */\n function error(message: string, duration?: number): string {\n return addToast('error', message, duration);\n }\n\n /**\n * Show an info toast notification\n */\n function info(message: string, duration?: number): string {\n return addToast('info', message, duration);\n }\n\n /**\n * Show a warning toast notification\n */\n function warning(message: string, duration?: number): string {\n return addToast('warning', message, duration);\n }\n\n /**\n * Show a confirmation dialog\n *\n * @returns Promise that resolves to true if confirmed, false if cancelled\n */\n function confirm(\n message: string,\n options?: {\n title?: string;\n confirmText?: string;\n cancelText?: string;\n },\n ): Promise<boolean> {\n return new Promise((resolve) => {\n // Resolve any pending dialog with false (cancelled) before opening new one\n if (pendingResolve) {\n pendingResolve(false);\n pendingResolve = null;\n }\n\n // Store the new resolve reference\n pendingResolve = resolve;\n\n confirmDialog.visible = true;\n confirmDialog.title = options?.title || 'Confirm';\n confirmDialog.message = message;\n confirmDialog.confirmText = options?.confirmText || 'Confirm';\n confirmDialog.cancelText = options?.cancelText || 'Cancel';\n\n confirmDialog.onConfirm = () => {\n confirmDialog.visible = false;\n if (pendingResolve) {\n pendingResolve(true);\n pendingResolve = null;\n }\n };\n\n confirmDialog.onCancel = () => {\n confirmDialog.visible = false;\n if (pendingResolve) {\n pendingResolve(false);\n pendingResolve = null;\n }\n };\n });\n }\n\n /**\n * Close the confirmation dialog\n */\n function closeConfirm(): void {\n confirmDialog.visible = false;\n if (pendingResolve) {\n pendingResolve(false);\n pendingResolve = null;\n }\n }\n\n /**\n * Manually dismiss a toast by ID\n */\n function dismiss(id: string): void {\n removeToast(id);\n }\n\n /**\n * Clear all toasts\n */\n function clearAll(): void {\n // Clear all active timeouts\n for (const timeoutId of timeouts.values()) {\n clearTimeout(timeoutId);\n }\n timeouts.clear();\n toasts.value = [];\n }\n\n return {\n // State\n toasts,\n confirmDialog,\n\n // Toast methods\n success,\n error,\n info,\n warning,\n dismiss,\n clearAll,\n\n // Confirm methods\n confirm,\n closeConfirm,\n };\n}\n","<!--\n ModelsPage.vue - Store Data Editor Page\n\n What: Displays and allows editing of in-memory store data organized by schema\n How: Fetches store data from models store and displays in an editable JSON view\n Why: Allows developers to inspect and modify mock data during development\n\n Features:\n - Schema listing sidebar with item counts\n - JSON editor with syntax validation\n - Save, discard, clear, and reseed actions\n - Real-time updates via WebSocket\n - Dirty state tracking\n-->\n<script setup lang=\"ts\">\nimport { Database, RefreshCw, Save, Trash2, X } from 'lucide-vue-next';\nimport { nextTick, onMounted, ref, watch } from 'vue';\nimport DataTable from '@/components/DataTable.vue';\n// biome-ignore lint/style/useImportType: Component needs to be available at runtime\nimport JsonEditor from '@/components/JsonEditor.vue';\nimport { useNotifications } from '@/composables/useNotifications';\nimport { useWebSocket } from '@/composables/useWebSocket';\nimport { useModelsStore } from '@/stores';\n\n// ==========================================================================\n// Store & Composables\n// ==========================================================================\n\nconst modelsStore = useModelsStore();\nconst { send, on, connected } = useWebSocket();\nconst { success, error: notifyError, confirm } = useNotifications();\n\n// ==========================================================================\n// State\n// ==========================================================================\n\n/** Reference to the JSON editor component */\nconst jsonEditorRef = ref<InstanceType<typeof JsonEditor> | null>(null);\n\n/** Confirmation dialog state */\nconst showClearConfirm = ref(false);\n\n/** Currently selected row index in the data table */\nconst selectedItemIndex = ref(-1);\n\n// ==========================================================================\n// Lifecycle\n// ==========================================================================\n\nonMounted(async () => {\n // Load schemas on mount\n try {\n await modelsStore.fetchSchemas();\n\n // Select first schema if available\n if (modelsStore.schemas.length > 0 && !modelsStore.selectedSchema) {\n await modelsStore.selectSchemaByName(modelsStore.schemas[0].name);\n }\n } catch (err) {\n // Error is already set in the store, but ensure it's visible\n if (!modelsStore.error) {\n modelsStore.error = err instanceof Error ? err.message : 'Failed to load schemas';\n }\n }\n});\n\n// ==========================================================================\n// WebSocket Event Handlers\n// ==========================================================================\n\n// Handle store updates from WebSocket\non('store:updated', (data) => {\n // Validate payload structure\n const payload = data as any;\n if (\n typeof data !== 'object' ||\n data === null ||\n typeof payload.schema !== 'string' ||\n typeof payload.action !== 'string' ||\n typeof payload.count !== 'number'\n ) {\n console.warn('[ModelsPage] Invalid store:updated payload:', data);\n return;\n }\n\n modelsStore.handleStoreUpdate(data as { schema: string; action: string; count: number });\n selectedItemIndex.value = -1;\n});\n\n// Handle reseed completion\non('reseeded', (data) => {\n // Validate payload structure\n const payload = data as any;\n if (\n typeof data !== 'object' ||\n data === null ||\n typeof payload.success !== 'boolean' ||\n !Array.isArray(payload.schemas)\n ) {\n console.warn('[ModelsPage] Invalid reseeded payload:', data);\n return;\n }\n\n modelsStore.handleReseedComplete(data as { success: boolean; schemas: string[] });\n selectedItemIndex.value = -1;\n});\n\n// ==========================================================================\n// Watchers\n// ==========================================================================\n\n// Format JSON when schema changes\nwatch(\n () => modelsStore.selectedSchema,\n async () => {\n selectedItemIndex.value = -1;\n if (jsonEditorRef.value && modelsStore.currentItems.length > 0) {\n // Wait for next tick to ensure editor is updated\n await nextTick();\n jsonEditorRef.value?.formatJson();\n }\n },\n);\n\n// Reset selection when items array changes and the selected item no longer matches\nwatch(\n () => modelsStore.currentItems,\n (newItems, oldItems) => {\n const idx = selectedItemIndex.value;\n if (idx < 0) return;\n\n // Out of range\n if (idx >= newItems.length) {\n selectedItemIndex.value = -1;\n return;\n }\n\n // Compare by ID field identity\n const idField = modelsStore.currentSchema?.idField ?? 'id';\n const oldItem = oldItems?.[idx];\n const newItem = newItems[idx];\n\n // Same object reference — keep selection\n if (oldItem === newItem) return;\n\n // Compare by ID value if both are objects\n if (\n typeof oldItem === 'object' &&\n oldItem !== null &&\n typeof newItem === 'object' &&\n newItem !== null\n ) {\n const oldId = (oldItem as Record<string, unknown>)[idField];\n const newId = (newItem as Record<string, unknown>)[idField];\n if (oldId !== undefined && oldId === newId) return;\n }\n\n selectedItemIndex.value = -1;\n },\n);\n\n// ==========================================================================\n// Actions\n// ==========================================================================\n\n/**\n * Select a schema and fetch its data\n */\nasync function selectSchema(schemaName: string): Promise<void> {\n if (modelsStore.isDirty) {\n const confirmed = await confirm(\n 'You have unsaved changes. Are you sure you want to switch schemas?',\n {\n title: 'Unsaved Changes',\n confirmText: 'Switch Schema',\n cancelText: 'Cancel',\n },\n );\n if (!confirmed) return;\n }\n\n await modelsStore.selectSchemaByName(schemaName);\n}\n\n/**\n * Save the current items to the server\n */\nasync function saveItems(): Promise<void> {\n if (!jsonEditorRef.value?.isValid) {\n notifyError('Cannot save invalid JSON. Please fix the errors first.');\n return;\n }\n\n const saved = await modelsStore.saveItems();\n if (saved) {\n success('Items saved successfully');\n } else {\n // Show error to user if save failed\n const errorMessage = modelsStore.error || 'Failed to save items';\n notifyError(errorMessage);\n }\n}\n\n/**\n * Discard changes and revert to original\n */\nasync function discardChanges(): Promise<void> {\n if (!modelsStore.isDirty) return;\n\n const confirmed = await confirm('Discard all changes and revert to saved data?', {\n title: 'Discard Changes',\n confirmText: 'Discard',\n cancelText: 'Cancel',\n });\n if (confirmed) {\n modelsStore.discardChanges();\n success('Changes discarded');\n }\n}\n\n/**\n * Clear all items for the current schema\n */\nasync function clearSchema(): Promise<void> {\n showClearConfirm.value = false;\n\n try {\n const cleared = await modelsStore.clearSchema();\n if (cleared) {\n success('Schema cleared successfully');\n } else {\n // Show error to user if clear failed\n const errorMessage = modelsStore.error || 'Failed to clear schema';\n notifyError(errorMessage);\n }\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to clear schema';\n notifyError(errorMessage);\n }\n}\n\n/**\n * Trigger reseed via WebSocket\n */\nasync function reseedAll(): Promise<void> {\n if (!connected.value) {\n notifyError('WebSocket not connected. Cannot trigger reseed.');\n return;\n }\n\n const confirmed = await confirm(\n 'This will regenerate all seed data and replace existing items. Continue?',\n {\n title: 'Reseed All Schemas',\n confirmText: 'Reseed',\n cancelText: 'Cancel',\n },\n );\n if (!confirmed) return;\n\n send({ type: 'reseed' });\n success('Reseed command sent');\n}\n\n/**\n * Handle JSON editor value updates\n */\nfunction onJsonEditorUpdate(value: unknown): void {\n modelsStore.updateItems(value);\n}\n\n/**\n * Handle data table row selection (toggle)\n */\nfunction onTableRowSelect(index: number): void {\n selectedItemIndex.value = selectedItemIndex.value === index ? -1 : index;\n}\n</script>\n\n<template>\n <div class=\"models-page\">\n <!-- Schema Sidebar -->\n <aside class=\"models-sidebar\">\n <div class=\"models-sidebar__header\">\n <Database :size=\"18\" />\n <span>Schemas</span>\n <span class=\"models-sidebar__badge\">{{ modelsStore.schemaCount }}</span>\n </div>\n\n <!-- Loading State -->\n <div v-if=\"modelsStore.loading && modelsStore.schemas.length === 0\" class=\"models-sidebar__loading\">\n <div class=\"spinner\" />\n <span>Loading...</span>\n </div>\n\n <!-- Schema List -->\n <div v-else class=\"models-sidebar__list\">\n <button\n v-for=\"schema in modelsStore.schemas\"\n :key=\"schema.name\"\n :class=\"[\n 'models-sidebar__item',\n { 'models-sidebar__item--active': modelsStore.selectedSchema === schema.name },\n ]\"\n @click=\"selectSchema(schema.name)\"\n >\n <span class=\"models-sidebar__name\">{{ schema.name }}</span>\n <span class=\"models-sidebar__count\">{{ schema.count }}</span>\n </button>\n </div>\n\n <!-- Footer Stats -->\n <div class=\"models-sidebar__footer\">\n <div class=\"models-sidebar__stat\">\n <span class=\"text-muted\">Total Items:</span>\n <span class=\"font-mono\">{{ modelsStore.totalItems }}</span>\n </div>\n </div>\n </aside>\n\n <!-- Data Panel -->\n <main class=\"models-content\">\n <template v-if=\"modelsStore.selectedSchema\">\n <!-- Toolbar -->\n <div class=\"models-toolbar\">\n <div class=\"models-toolbar__title\">\n <span class=\"font-mono\">{{ modelsStore.selectedSchema }}</span>\n <span class=\"text-muted\">({{ modelsStore.currentItems.length }} items)</span>\n <span\n v-if=\"modelsStore.isDirty\"\n class=\"models-toolbar__badge models-toolbar__badge--warning\"\n >\n Unsaved\n </span>\n </div>\n\n <div class=\"models-toolbar__actions\">\n <!-- Discard Button -->\n <button\n v-if=\"modelsStore.isDirty\"\n class=\"btn btn--ghost\"\n title=\"Discard changes\"\n @click=\"discardChanges\"\n >\n <X :size=\"16\" />\n <span>Discard</span>\n </button>\n\n <!-- Save Button -->\n <button\n :disabled=\"!modelsStore.isDirty || modelsStore.loading\"\n class=\"btn btn--primary\"\n title=\"Save changes\"\n @click=\"saveItems\"\n >\n <Save :size=\"16\" />\n <span>Save</span>\n </button>\n\n <!-- Clear Button -->\n <button\n class=\"btn btn--danger\"\n title=\"Clear all items\"\n @click=\"showClearConfirm = true\"\n >\n <Trash2 :size=\"16\" />\n <span>Clear</span>\n </button>\n\n <!-- Reseed Button -->\n <button\n :disabled=\"!connected\"\n class=\"btn btn--secondary\"\n title=\"Reseed all schemas with generated data\"\n @click=\"reseedAll\"\n >\n <RefreshCw :size=\"16\" />\n <span>Reseed All</span>\n </button>\n </div>\n </div>\n\n <!-- Error Display -->\n <div v-if=\"modelsStore.error\" class=\"models-error\">\n <span>⚠️ {{ modelsStore.error }}</span>\n </div>\n\n <!-- Split Panels: Editor + Data Table -->\n <div class=\"models-panels\">\n <div class=\"models-panel\">\n <JsonEditor\n ref=\"jsonEditorRef\"\n :model-value=\"modelsStore.currentItems\"\n :readonly=\"modelsStore.loading\"\n :min-height=\"400\"\n @update:model-value=\"onJsonEditorUpdate\"\n />\n </div>\n <div class=\"models-panel\">\n <DataTable\n :items=\"modelsStore.currentItems\"\n :id-field=\"modelsStore.currentSchema?.idField ?? 'id'\"\n :selected-index=\"selectedItemIndex\"\n @select=\"onTableRowSelect\"\n />\n </div>\n </div>\n\n <!-- Loading Overlay -->\n <div v-if=\"modelsStore.loading\" class=\"models-loading-overlay\">\n <div class=\"spinner\" />\n <span>Loading...</span>\n </div>\n </template>\n\n <!-- Empty State or Error -->\n <div v-else class=\"empty-state\">\n <!-- Show error if present and no schema selected -->\n <div v-if=\"modelsStore.error\" class=\"models-error\">\n <span>⚠️ {{ modelsStore.error }}</span>\n </div>\n <template v-else>\n <Database :size=\"48\" class=\"empty-state__icon\" />\n <h3 class=\"empty-state__title\">Select a schema</h3>\n <p class=\"empty-state__description\">\n Choose a schema from the sidebar to view and edit its data.\n </p>\n </template>\n </div>\n </main>\n\n <!-- Clear Confirmation Modal -->\n <Teleport to=\"body\">\n <div v-if=\"showClearConfirm\" class=\"modal-overlay\" @click=\"showClearConfirm = false\">\n <div class=\"modal\" @click.stop>\n <div class=\"modal__header\">\n <h3>Clear Schema Data</h3>\n </div>\n <div class=\"modal__body\">\n <p>\n Are you sure you want to clear all items for\n <strong>{{ modelsStore.selectedSchema }}</strong>?\n </p>\n <p class=\"text-muted\">This action cannot be undone.</p>\n </div>\n <div class=\"modal__footer\">\n <button class=\"btn btn--ghost\" @click=\"showClearConfirm = false\">\n Cancel\n </button>\n <button class=\"btn btn--danger\" @click=\"clearSchema\">\n Clear Schema\n </button>\n </div>\n </div>\n </div>\n </Teleport>\n </div>\n</template>\n\n<style scoped>\n.models-page {\n display: grid;\n grid-template-columns: 240px 1fr;\n height: 100%;\n overflow: hidden;\n}\n\n/* Sidebar */\n.models-sidebar {\n display: flex;\n flex-direction: column;\n background-color: var(--devtools-surface);\n border-right: 1px solid var(--devtools-border);\n overflow: hidden;\n}\n\n.models-sidebar__header {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n padding: var(--devtools-space-md);\n font-weight: var(--font-weight-6);\n font-size: var(--font-size-1);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.models-sidebar__badge {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 20px;\n height: 20px;\n padding: 0 var(--devtools-space-xs);\n background-color: var(--devtools-primary);\n color: white;\n border-radius: var(--devtools-radius-sm);\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-6);\n}\n\n.models-sidebar__loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-xl);\n color: var(--devtools-text-muted);\n}\n\n.models-sidebar__list {\n flex: 1;\n overflow-y: auto;\n padding: var(--devtools-space-xs);\n}\n\n.models-sidebar__item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n padding: var(--devtools-space-sm) var(--devtools-space-md);\n background: none;\n border: none;\n border-radius: var(--devtools-radius-sm);\n color: var(--devtools-text);\n font-family: var(--devtools-font-sans);\n font-size: var(--font-size-1);\n cursor: pointer;\n transition: background-color var(--devtools-transition-fast);\n}\n\n.models-sidebar__item:hover {\n background-color: var(--devtools-surface-elevated);\n}\n\n.models-sidebar__item--active {\n background-color: color-mix(in srgb, var(--devtools-primary) 15%, transparent);\n color: var(--devtools-primary);\n}\n\n.models-sidebar__name {\n font-family: var(--devtools-font-mono);\n}\n\n.models-sidebar__count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 24px;\n height: 20px;\n padding: 0 var(--devtools-space-xs);\n background-color: var(--devtools-surface-elevated);\n border-radius: var(--devtools-radius-sm);\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n}\n\n.models-sidebar__footer {\n padding: var(--devtools-space-md);\n border-top: 1px solid var(--devtools-border);\n}\n\n.models-sidebar__stat {\n display: flex;\n justify-content: space-between;\n font-size: var(--font-size-0);\n}\n\n/* Content Area */\n.models-content {\n position: relative;\n display: flex;\n flex-direction: column;\n padding: var(--devtools-space-md);\n overflow: hidden;\n}\n\n/* Toolbar */\n.models-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--devtools-space-md);\n margin-bottom: var(--devtools-space-md);\n}\n\n.models-toolbar__title {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n font-size: var(--font-size-2);\n font-weight: var(--font-weight-6);\n}\n\n.models-toolbar__badge {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n border-radius: var(--devtools-radius-sm);\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n}\n\n.models-toolbar__badge--warning {\n background-color: color-mix(in srgb, #f59e0b 20%, transparent);\n color: #f59e0b;\n}\n\n.models-toolbar__actions {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n}\n\n/* Error Display */\n.models-error {\n padding: var(--devtools-space-sm) var(--devtools-space-md);\n margin-bottom: var(--devtools-space-md);\n background-color: color-mix(in srgb, var(--devtools-error) 10%, transparent);\n border: 1px solid var(--devtools-error);\n border-radius: var(--devtools-radius-sm);\n color: var(--devtools-error);\n font-size: var(--font-size-0);\n}\n\n/* Split Panels */\n.models-panels {\n display: flex;\n flex: 1;\n gap: 1px;\n overflow: hidden;\n background-color: var(--devtools-border);\n}\n\n.models-panel {\n flex: 1;\n min-width: 300px;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n background-color: var(--devtools-bg);\n}\n\n/* Responsive: stack panels vertically on narrow viewports */\n@media (max-width: 840px) {\n .models-panels {\n flex-direction: column;\n }\n\n .models-panel {\n min-width: 0;\n min-height: 200px;\n }\n}\n\n/* Loading Overlay */\n.models-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--devtools-space-md);\n background-color: color-mix(in srgb, var(--devtools-bg) 80%, transparent);\n backdrop-filter: blur(2px);\n z-index: 10;\n}\n\n/* Modal */\n.modal-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: rgba(0, 0, 0, 0.5);\n z-index: 1000;\n}\n\n.modal {\n min-width: 400px;\n background-color: var(--devtools-surface);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-md);\n box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);\n}\n\n.modal__header {\n padding: var(--devtools-space-md);\n border-bottom: 1px solid var(--devtools-border);\n}\n\n.modal__header h3 {\n margin: 0;\n font-size: var(--font-size-2);\n font-weight: var(--font-weight-6);\n}\n\n.modal__body {\n padding: var(--devtools-space-md);\n}\n\n.modal__body p {\n margin: 0 0 var(--devtools-space-sm) 0;\n}\n\n.modal__body p:last-child {\n margin-bottom: 0;\n}\n\n.modal__footer {\n display: flex;\n justify-content: flex-end;\n gap: var(--devtools-space-sm);\n padding: var(--devtools-space-md);\n border-top: 1px solid var(--devtools-border);\n}\n\n/* Spinner */\n.spinner {\n width: 24px;\n height: 24px;\n border: 3px solid var(--devtools-border);\n border-top-color: var(--devtools-primary);\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n</style>\n","<!--\n SimulatorPage.vue - Error Simulation Controls Page\n\n What: Provides controls for simulating various API error conditions\n How: Manages simulation state via simulation store and WebSocket commands\n Why: Allows developers to test error handling without modifying backend code\n-->\n\n<script setup lang=\"ts\">\nimport { AlertTriangle, Clock, Plus, Trash2, Zap } from 'lucide-vue-next';\nimport { computed, onMounted, onUnmounted, ref, watch } from 'vue';\nimport { useWebSocket } from '../composables/useWebSocket';\nimport { useRegistryStore } from '../stores/registry';\nimport type { ActiveSimulation } from '../stores/simulation';\nimport { useSimulationStore } from '../stores/simulation';\n\n// ==========================================================================\n// Types\n// ==========================================================================\n\ninterface SimulationActiveEvent {\n simulations: ActiveSimulation[];\n}\n\ninterface SimulationPathEvent {\n path: string;\n}\n\ninterface SimulationsClearedEvent {\n count: number;\n}\n\ninterface SimulationSetEvent {\n path: string;\n success: boolean;\n}\n\ninterface SimulationClearedEvent {\n path: string;\n success: boolean;\n}\n\n// ==========================================================================\n// Composables\n// ==========================================================================\n\nconst simulationStore = useSimulationStore();\nconst registryStore = useRegistryStore();\nconst { send, on, connected } = useWebSocket();\n\n// ==========================================================================\n// State\n// ==========================================================================\n\n/** Path input for new simulation */\nconst newSimulationPath = ref('');\n\n/** Method input for new simulation */\nconst newSimulationMethod = ref('GET');\n\n/** Selected preset ID */\nconst selectedPresetId = ref<string | null>(null);\n\n/** Selected endpoint key (for dropdown selection) */\nconst selectedEndpointKey = ref<string | null>(null);\n\n/** Available HTTP methods */\nconst httpMethods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'];\n\n/** WebSocket event unsubscribe functions (populated in onMounted) */\nlet unsubscribers: Array<() => void> = [];\n\n/** Simulations pending clear (for rollback on partial failures) */\nconst pendingClears = ref<Set<string>>(new Set());\n\n// ==========================================================================\n// Computed\n// ==========================================================================\n\n/**\n * Available endpoints for selection\n */\nconst availableEndpoints = computed(() => {\n return registryStore.endpoints.map((e) => ({\n key: e.key,\n label: `${e.method.toUpperCase()} ${e.path}`,\n method: e.method.toUpperCase(),\n path: e.path,\n operationId: e.operationId,\n }));\n});\n\n/**\n * Check if we can add a new simulation\n */\nconst canAddSimulation = computed(() => {\n const hasPath = newSimulationPath.value.trim() !== '';\n const hasPreset = selectedPresetId.value !== null;\n return hasPath && hasPreset;\n});\n\n/**\n * Active simulations for display\n */\nconst activeSimulations = computed(() => {\n return simulationStore.activeSimulations.map((sim) => {\n const preset = sim.presetId ? simulationStore.getPreset(sim.presetId) : null;\n return {\n ...sim,\n preset,\n };\n });\n});\n\n/**\n * Simulation count\n */\nconst simulationCount = computed(() => simulationStore.count);\n\n// ==========================================================================\n// Methods\n// ==========================================================================\n\n/**\n * Add a new simulation\n */\nfunction addSimulation(): void {\n if (!canAddSimulation.value || !selectedPresetId.value) return;\n\n const preset = simulationStore.getPreset(selectedPresetId.value);\n if (!preset) return;\n\n // Validate path input\n const trimmedPath = newSimulationPath.value.trim();\n\n // Path must start with /\n if (!trimmedPath.startsWith('/')) {\n simulationStore.setError('Path must start with /');\n return;\n }\n\n // Path must not be too long (reasonable limit)\n if (trimmedPath.length > 500) {\n simulationStore.setError('Path is too long (max 500 characters)');\n return;\n }\n\n // Path should only contain valid URL path characters\n if (!/^\\/[\\w\\-/{}:.]*$/.test(trimmedPath)) {\n simulationStore.setError('Path contains invalid characters');\n return;\n }\n\n // Combine method and path to create endpoint key (e.g., \"get:/pets\")\n const pathWithMethod = `${newSimulationMethod.value.toLowerCase()}:${trimmedPath}`;\n const simulation = simulationStore.createSimulationFromPreset(\n pathWithMethod,\n selectedPresetId.value,\n undefined,\n );\n\n if (!simulation) return;\n\n // Optimistically add to local state (store previous state for rollback)\n simulationStore.addSimulationLocal(simulation, true);\n simulationStore.setLoading(true);\n\n // Send command to server\n send({\n type: 'set:simulation',\n data: {\n path: simulation.path,\n status: simulation.status,\n delay: simulation.delay,\n body: simulation.body,\n },\n });\n\n // Reset form\n newSimulationPath.value = '';\n selectedPresetId.value = null;\n selectedEndpointKey.value = null;\n}\n\n/**\n * Remove an active simulation\n */\nfunction removeSimulation(path: string): void {\n // Optimistically remove from local state (store previous state for rollback)\n simulationStore.removeSimulationLocal(path, true);\n simulationStore.setLoading(true);\n\n // Send command to server\n send({\n type: 'clear:simulation',\n data: { path },\n });\n}\n\n/**\n * Clear all simulations\n */\nfunction clearAllSimulations(): void {\n if (simulationCount.value === 0) return;\n\n // Mark each simulation as pending clear and store for rollback\n for (const simulation of simulationStore.activeSimulations) {\n pendingClears.value.add(simulation.path);\n\n // Store previous state for rollback\n simulationStore.removeSimulationLocal(simulation.path, true);\n\n // Send clear command to server\n send({\n type: 'clear:simulation',\n data: { path: simulation.path },\n });\n }\n\n simulationStore.setLoading(true);\n\n // Note: Individual simulations will be removed from local state\n // only when we receive the corresponding \"simulation:cleared\" event\n // with success: true. Failed clears will be rolled back automatically.\n}\n\n/**\n * Handle endpoint selection from dropdown\n */\nfunction handleEndpointSelect(): void {\n if (!selectedEndpointKey.value) return;\n\n const endpoint = registryStore.endpoints.find((e) => e.key === selectedEndpointKey.value);\n if (!endpoint) return;\n\n newSimulationMethod.value = endpoint.method.toUpperCase();\n newSimulationPath.value = endpoint.path;\n}\n\n/**\n * Handle manual path/method input\n */\nfunction handleManualInput(): void {\n // Clear endpoint selection when user types manually\n selectedEndpointKey.value = null;\n}\n\n// ==========================================================================\n// Data Fetching\n// ==========================================================================\n\n/**\n * Fetch current simulations from server via get:registry command\n * (server responds with simulation:active event containing current simulations)\n */\nfunction fetchSimulations(): void {\n if (connected.value) {\n simulationStore.setLoading(true);\n send({ type: 'get:registry' });\n }\n}\n\n// ==========================================================================\n// Lifecycle\n// ==========================================================================\n\nonMounted(() => {\n // Subscribe to simulation events and collect unsubscribe functions\n unsubscribers = [\n on('simulation:active', (data: SimulationActiveEvent) => {\n simulationStore.setSimulations(data.simulations);\n simulationStore.setLoading(false);\n }),\n\n on('simulation:added', (data: SimulationPathEvent) => {\n simulationStore.handleSimulationAdded(data);\n }),\n\n on('simulation:removed', (data: SimulationPathEvent) => {\n simulationStore.handleSimulationRemoved(data);\n }),\n\n on('simulations:cleared', (data: SimulationsClearedEvent) => {\n simulationStore.handleSimulationsCleared(data);\n }),\n\n on('simulation:set', (data: SimulationSetEvent) => {\n simulationStore.handleSimulationSet(data);\n }),\n\n on('simulation:cleared', (data: SimulationClearedEvent) => {\n // Remove from pending clears if it was part of clearAll\n if (pendingClears.value.has(data.path)) {\n pendingClears.value.delete(data.path);\n }\n\n // Delegate to store handler (handles success/failure and rollback)\n simulationStore.handleSimulationCleared(data);\n }),\n ];\n\n // Fetch current simulations if already connected\n if (connected.value) {\n fetchSimulations();\n }\n});\n\n// Cleanup on unmount to prevent memory leaks\nonUnmounted(() => {\n for (const unsub of unsubscribers) {\n unsub();\n }\n});\n\n// Re-fetch simulations when connection is (re)established, clear loading on disconnect\nwatch(connected, (isConnected) => {\n if (isConnected) {\n fetchSimulations();\n } else {\n simulationStore.setLoading(false);\n }\n});\n</script>\n\n<template>\n <div class=\"simulator-page\">\n <!-- Add Simulation Form -->\n <div class=\"simulator-form card\">\n <div class=\"simulator-form__header\">\n <Zap :size=\"18\" />\n <span>Add Simulation</span>\n </div>\n\n <div class=\"simulator-form__body\">\n <!-- Endpoint Selector (optional) -->\n <div v-if=\"availableEndpoints.length > 0\" class=\"simulator-form__row\">\n <label class=\"simulator-form__label\">Select Endpoint (optional):</label>\n <select\n v-model=\"selectedEndpointKey\"\n class=\"input\"\n @change=\"handleEndpointSelect\"\n >\n <option :value=\"null\">Manual entry...</option>\n <option\n v-for=\"endpoint in availableEndpoints\"\n :key=\"endpoint.key\"\n :value=\"endpoint.key\"\n >\n {{ endpoint.label }}\n </option>\n </select>\n </div>\n\n <!-- Method and Path -->\n <div class=\"simulator-form__row\">\n <select\n v-model=\"newSimulationMethod\"\n class=\"simulator-form__method input\"\n @change=\"handleManualInput\"\n >\n <option v-for=\"method in httpMethods\" :key=\"method\" :value=\"method\">\n {{ method }}\n </option>\n </select>\n <input\n v-model=\"newSimulationPath\"\n type=\"text\"\n class=\"simulator-form__path input\"\n placeholder=\"/api/path\"\n @input=\"handleManualInput\"\n />\n </div>\n\n <!-- Preset Selection -->\n <div class=\"simulator-presets\">\n <button\n v-for=\"preset in simulationStore.presets\"\n :key=\"preset.id\"\n :class=\"[\n 'simulator-preset',\n { 'simulator-preset--selected': selectedPresetId === preset.id },\n `simulator-preset--${preset.type}`,\n ]\"\n :title=\"preset.description\"\n @click=\"selectedPresetId = preset.id\"\n >\n <component\n :is=\"preset.type === 'delay' ? Clock : AlertTriangle\"\n :size=\"14\"\n />\n <span class=\"simulator-preset__label\">{{ preset.label }}</span>\n </button>\n </div>\n\n <!-- Add Button -->\n <button\n class=\"btn btn--primary\"\n :disabled=\"!canAddSimulation || simulationStore.isLoading\"\n @click=\"addSimulation\"\n >\n <Plus :size=\"16\" />\n <span>Add Simulation</span>\n </button>\n </div>\n </div>\n\n <!-- Active Simulations -->\n <div class=\"simulator-active\">\n <div class=\"simulator-active__header\">\n <span class=\"simulator-active__title\">\n Active Simulations ({{ simulationCount }})\n </span>\n <button\n v-if=\"simulationCount > 0\"\n class=\"btn btn--ghost\"\n :disabled=\"simulationStore.isLoading\"\n @click=\"clearAllSimulations\"\n >\n <Trash2 :size=\"14\" />\n <span>Clear All</span>\n </button>\n </div>\n\n <div class=\"simulator-active__list\">\n <div\n v-for=\"simulation in activeSimulations\"\n :key=\"simulation.path\"\n class=\"simulator-simulation card\"\n >\n <div class=\"simulator-simulation__info\">\n <span class=\"simulator-simulation__path font-mono\">\n {{ simulation.path }}\n </span>\n </div>\n <div class=\"simulator-simulation__preset\">\n <component\n :is=\"simulation.preset?.type === 'delay' ? Clock : AlertTriangle\"\n :size=\"14\"\n :class=\"{\n 'text-warning': simulation.preset?.type === 'delay',\n 'text-error': simulation.preset?.type === 'error',\n 'text-muted': simulation.preset?.type === 'empty',\n }\"\n />\n <span>\n {{ simulation.preset?.label || `HTTP ${simulation.status}` }}\n </span>\n <span v-if=\"simulation.delay\" class=\"text-muted\">\n ({{ simulation.delay }}ms)\n </span>\n </div>\n <button\n class=\"btn btn--ghost btn--icon\"\n title=\"Remove simulation\"\n :disabled=\"simulationStore.isLoading\"\n @click=\"removeSimulation(simulation.path)\"\n >\n <Trash2 :size=\"14\" />\n </button>\n </div>\n\n <!-- Empty State -->\n <div v-if=\"simulationCount === 0\" class=\"empty-state\">\n <Zap :size=\"48\" class=\"empty-state__icon\" />\n <h3 class=\"empty-state__title\">No active simulations</h3>\n <p class=\"empty-state__description\">\n Add a simulation above to test error handling and slow responses.\n </p>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.simulator-page {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-lg);\n height: 100%;\n padding: var(--devtools-space-md);\n overflow-y: auto;\n}\n\n/* Form */\n.simulator-form {\n flex-shrink: 0;\n}\n\n.simulator-form__header {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n padding-bottom: var(--devtools-space-md);\n margin-bottom: var(--devtools-space-md);\n border-bottom: 1px solid var(--devtools-border);\n font-weight: var(--font-weight-6);\n font-size: var(--font-size-1);\n}\n\n.simulator-form__body {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-md);\n}\n\n.simulator-form__row {\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-xs);\n}\n\n.simulator-form__row:has(.simulator-form__method) {\n flex-direction: row;\n gap: var(--devtools-space-sm);\n}\n\n.simulator-form__label {\n font-size: var(--font-size-0);\n font-weight: var(--font-weight-5);\n color: var(--devtools-text);\n}\n\n.simulator-form__method {\n width: 100px;\n flex-shrink: 0;\n}\n\n.simulator-form__path {\n flex: 1;\n}\n\n/* Presets */\n.simulator-presets {\n display: flex;\n flex-wrap: wrap;\n gap: var(--devtools-space-xs);\n}\n\n.simulator-preset {\n display: inline-flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n padding: var(--devtools-space-xs) var(--devtools-space-sm);\n background-color: var(--devtools-surface-elevated);\n border: 1px solid var(--devtools-border);\n border-radius: var(--devtools-radius-sm);\n font-family: var(--devtools-font-sans);\n font-size: var(--font-size-0);\n cursor: pointer;\n transition: all var(--devtools-transition-fast);\n}\n\n.simulator-preset:hover {\n background-color: var(--devtools-border);\n}\n\n.simulator-preset--selected {\n border-color: var(--devtools-primary);\n background-color: color-mix(\n in srgb,\n var(--devtools-primary) 15%,\n transparent\n );\n}\n\n.simulator-preset--delay {\n color: var(--devtools-warning);\n}\n\n.simulator-preset--error {\n color: var(--devtools-error);\n}\n\n.simulator-preset--empty {\n color: var(--devtools-text-muted);\n}\n\n.simulator-preset__label {\n color: var(--devtools-text);\n}\n\n/* Active Simulations */\n.simulator-active {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n.simulator-active__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: var(--devtools-space-md);\n}\n\n.simulator-active__title {\n font-weight: var(--font-weight-6);\n font-size: var(--font-size-1);\n}\n\n.simulator-active__list {\n flex: 1;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: var(--devtools-space-xs);\n}\n\n/* Simulation Item */\n.simulator-simulation {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-md);\n padding: var(--devtools-space-sm) var(--devtools-space-md);\n}\n\n.simulator-simulation__info {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-sm);\n flex: 1;\n}\n\n.simulator-simulation__path {\n font-size: var(--font-size-1);\n color: var(--devtools-text);\n}\n\n.simulator-simulation__preset {\n display: flex;\n align-items: center;\n gap: var(--devtools-space-xs);\n font-size: var(--font-size-0);\n color: var(--devtools-text-muted);\n}\n\n/* Color utilities */\n.text-warning {\n color: var(--devtools-warning);\n}\n\n.text-error {\n color: var(--devtools-error);\n}\n\n.text-muted {\n color: var(--devtools-text-muted);\n}\n</style>\n"],"names":["toKebabCase","string","toCamelCase","match","p1","p2","toPascalCase","camelCase","mergeClasses","classes","className","index","array","defaultAttributes","Icon","size","strokeWidth","absoluteStrokeWidth","color","iconNode","name","props","slots","h","child","createLucideIcon","iconName","Check","ChevronDown","ChevronRight","ChevronUp","CircleAlert","CircleCheckBig","Clock","Code","Copy","Database","FileJson","Funnel","Lock","Plus","RefreshCw","Route","Save","Search","Shield","Sprout","Tag","Trash2","TriangleAlert","WifiOff","Wifi","X","Zap","DEFAULT_OPTIONS","connectionState","ref","serverVersion","reconnectAttempts","ws","reconnectTimer","currentOptions","optionsInitialized","eventHandlers","isBrowser","hasComponentContext","getCurrentInstance","buildWebSocketUrl","path","clearReconnectTimer","dispatchEvent","type","data","handlers","handler","error","wildcardHandlers","handleOpen","handleMessage","event","message","connectedData","handleClose","connect","handleError","cleanupConnection","url","disconnect","send","command","on","currentHandlers","off","once","wrappedHandler","onUntil","resetState","useWebSocket","options","connected","computed","isReconnecting","onMounted","routes","RoutesPage$1","TimelinePage$1","ModelsPage$1","SimulatorPage$1","router","createRouter","createWebHashHistory","route","useRoute","useRouter","tabs","r","activeTab","navigateTo","iconMap","getIcon","isConnected","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_createVNode","_unref","_cache","_hoisted_4","_Fragment","_renderList","tab","_normalizeClass","$event","_createBlock","_resolveDynamicComponent","_hoisted_6","_toDisplayString","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_component_router_view","_withCtx","Component","_Transition","safeClone","value","toRaw","useModelsStore","defineStore","schemas","selectedSchema","currentItems","originalItems","loading","currentSchema","s","isDirtyFlag","isDirty","schemaCount","totalItems","sum","schema","fetchSchemas","response","err","selectSchemaByName","schemaName","fetchSchemaData","items","schemaIndex","updateItems","saveItems","errorData","result","clearSchema","discardChanges","refresh","reset","handleStoreUpdate","handleReseedComplete","useRegistryStore","endpoints","stats","isLoading","searchQuery","filter","selectedEndpointKey","expandedTags","allTags","tagSet","endpoint","tag","allSchemas","schemaSet","filteredEndpoints","query","groupedEndpoints","groups","groupKey","eps","a","b","selectedEndpoint","e","handlerCount","seedCount","setRegistryData","setLoading","setError","errorMessage","clearError","setSearchQuery","toggleMethodFilter","method","setHandlerFilter","hasHandler","setSeedFilter","hasSeed","toggleTagFilter","clearFilters","hasActiveFilters","selectEndpoint","key","toggleGroup","expandAllGroups","group","collapseAllGroups","updateHandlerStatus","handlerOperationIds","handlerSet","updateSeedStatus","seedSchemas","seedSet","SIMULATION_PRESETS","useSimulationStore","simulations","previousSimulations","activeSimulations","count","presets","hasActiveSimulations","simulationsByType","grouped","simulation","getSimulationType","preset","p","setSimulations","newSimulations","addSimulationLocal","storeForRollback","previous","removeSimulationLocal","clearSimulationsLocal","getSimulation","hasSimulation","getPreset","id","createSimulationFromPreset","presetId","operationId","rollbackSimulation","handleSimulationAdded","handleSimulationRemoved","handleSimulationsCleared","handleSimulationSet","handleSimulationCleared","useTimelineStore","entries","selectedEntryId","maxEntries","responseBuffer","getStatusCategory","status","filteredEntries","entry","category","selectedEntry","totalCount","completedCount","pendingCount","statusCounts","counts","averageDuration","completedEntries","totalDuration","addRequest","request","bufferedResponse","mergeResponse","addResponse","stubEntry","createStubEntry","stubRequest","processBufferedResponses","requestMap","requestId","processIncomingResponses","incomingResponses","createStubsForOrphanedResponses","setTimelineData","item","sorted","clearTimeline","toggleStatusFilter","setSimulatedFilter","simulated","selectEntry","setMaxEntries","limit","clamped","VALID_THEME_MODES","isThemeMode","STORAGE_KEY","themeMode","systemPrefersDark","currentMediaQuery","currentMediaHandler","useTheme","effectiveTheme","isDark","applyTheme","root","setTheme","mode","toggleTheme","resetToSystem","cleanupMediaQuery","initialize","mediaQuery","saved","watch","onUnmounted","isBootstrapped","appInstance","bootstrap","app","createApp","AppComponent","pinia","createPinia","getMethodLabel","__props","hasSecurity","securityDisplay","sec","_hoisted_5","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","_hoisted_25","_hoisted_26","_hoisted_27","_hoisted_28","emit","__emit","handleEndpointClick","handleGroupToggle","isSelected","_vShow","registryStore","showFilters","searchInputRef","httpMethods","fetchRegistry","handleRegistryData","handleSelectEndpoint","handleToggleGroup","handleSearchInput","target","clearSearch","toggleMethod","isMethodActive","toggleHandlerFilter","current","toggleSeedFilter","clearAllFilters","toggleFilters","unsubRegistry","unsubHandlers","unsubSeeds","Filter","EndpointList","EndpointDetail","expandedSections","copiedField","formattedTimestamp","formattedDuration","statusClass","hasQueryParams","hasRequestHeaders","hasRequestBody","hasResponseHeaders","hasResponseBody","formatJson","toggleSection","section","copyToClipboard","text","fieldId","copyFullEntry","_createTextVNode","_withDirectives","_hoisted_29","_hoisted_30","_hoisted_31","_hoisted_32","_hoisted_33","_withModifiers","_hoisted_35","_hoisted_36","_hoisted_37","_hoisted_38","_hoisted_40","_hoisted_41","_hoisted_42","_hoisted_43","_hoisted_44","_hoisted_45","_hoisted_47","_hoisted_48","_hoisted_49","_hoisted_50","formattedTime","statusIcon","CheckCircle","AlertTriangle","isPending","handleClick","timelineStore","statusCategories","fetchTimeline","handleTimelineData","handleRequest","handleResponse","handleTimelineCleared","handleSelectEntry","toggleStatus","isStatusActive","toggleSimulatedFilter","filterBadgeCount","unsubTimeline","unsubRequest","unsubResponse","unsubCleared","TimelineEntryComponent","TimelineDetail","truncate","str","maxLen","formatCell","getCellValue","column","getRowKey","idField","discoverColumns","keySet","keys","k","columns","onRowClick","rowKey","col","validationError","isValid","lineCount","lineNumbers","_","i","initializeText","currentParsed","handleInput","validateAndEmit","parsed","position","lines","line","handleKeyDown","start","end","newText","__expose","lineNum","AlertCircle","toasts","confirmDialog","reactive","timeouts","pendingResolve","toastIdCounter","generateToastId","addToast","duration","toast","timeoutId","removeToast","t","useNotifications","success","info","warning","confirm","resolve","closeConfirm","dismiss","clearAll","modelsStore","notifyError","jsonEditorRef","showClearConfirm","selectedItemIndex","payload","nextTick","newItems","oldItems","idx","oldItem","newItem","oldId","newId","selectSchema","reseedAll","onJsonEditorUpdate","onTableRowSelect","JsonEditor","DataTable","_Teleport","simulationStore","newSimulationPath","newSimulationMethod","selectedPresetId","unsubscribers","pendingClears","availableEndpoints","canAddSimulation","hasPath","hasPreset","sim","simulationCount","addSimulation","trimmedPath","pathWithMethod","removeSimulation","clearAllSimulations","handleEndpointSelect","handleManualInput","fetchSimulations","unsub"],"mappings":"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","x_google_ignoreList":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]}
|