Skip to the content.

Task 115 — Web-UI: openapi-typescript + Orval setup

Phase: 8 Status: superseded (deprecated target — src/hercules-web, ADR-0009) Owner: — Slug: webui-openapi-codegen-setup Studio Stage: N/A (hercules-web, не Studio)

Status note (2026-10-07, 2.0.0 release prep). Not outstanding work — do not start. This task targets src/hercules-web (Astro), which ADR-0009 deprecated and which is not ported; its panels were superseded by Hercules Studio. Generating a client for an application that is intentionally frozen would be wasted effort, and the equivalent Studio-side pipeline already ships under task_113 / task_114.md. Panel-by-panel replacement map: src/hercules-web/DEPRECATED.md. Kept on disk (not deleted) so the superseded scope is recorded rather than rediscovered later.

Goal

Настроить тот же pipeline генерации TypeScript API клиента в hercules-web (Astro) из OpenAPI документа агента. Использовать openapi-typescript (types) + Orval (Vue Query hooks для Astro islands + Zod + MSW mocks). Generated files коммитятся в git. Regen — ручной.

Acceptance criteria

orval.config.ts (hercules-web)

import { defineConfig } from "orval";

export default defineConfig({
  hercules: {
    // Source: build-time generated openapi.json (committed to git by task_109)
    // Alternative for dev: http://localhost:8421/openapi/v1.json (running agent)
    input: { target: "../../agent/Hercules.WebApi/openapi.json" },
    output: {
      mode: "tags-split",
      target: "src/api/generated",
      schemas: "src/api/models",
      client: "vue-query",
      mock: true,
      zod: true,
    },
    hooks: {
      mutator: "src/api/mutator.ts",
    },
  },
});

mutator.ts (hercules-web — Astro env vars)

const API_BASE = import.meta.env.PUBLIC_API_BASE || "http://localhost:8421";
const API_KEY = import.meta.env.PUBLIC_API_KEY || "dev-local-key";

export const customMutator = async (config) => {
  const res = await fetch(`${API_BASE}${config.url}`, {
    method: config.method,
    headers: { "X-Api-Key": API_KEY, "Content-Type": "application/json", ...config.headers },
    body: config.body ? JSON.stringify(config.body) : undefined,
  });
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return { data: await res.json(), status: res.status };
};

Astro Vue islands integration

Astro islands с client:load / client:visible поддерживают Vue Query:

---
import SkillsList from '../components/SkillsList.vue';
---
<SkillsList client:load />
<!-- SkillsList.vue -->
<script setup lang="ts">
import { useListSkillsQuery } from "../api/generated/skills/skills";
const { data: skills, isLoading } = useListSkillsQuery();
</script>

Dependencies (backend)

Scope / Likely files