chore(web): install orval + mutator for OpenAPI code generation (v1.0.8 P1)
Phase 1 of the OpenAPI typegen migration. Brings orval@8.8.1 into the
monorepo (workspace-hoisted) and wires a custom mutator so generated
calls route through the existing Axios instance — interceptors for
auth / CSRF / retry / offline-queue / logging keep firing unchanged.
200 .ts files generated from veza-backend-api/openapi.yaml (3441 LOC),
covering 13 tags (auth, track, user, playlist, marketplace, chat,
dashboard, webhook, validation, logging, audit, comment, users).
Changes:
- apps/web/orval.config.ts (NEW): generator config, output
src/services/generated/, tags-split mode, vezaMutator.
- apps/web/src/services/api/orval-mutator.ts (NEW): translates
orval's (url, RequestInit) convention into AxiosRequestConfig
then apiClient. Forwards AbortSignal for React Query cancellation.
- apps/web/scripts/generate-types.sh: runs BOTH generators during
the migration (legacy typescript-axios + orval). B9 drops step 1.
- apps/web/scripts/check-types-sync.sh: extended to check drift on
both output trees.
- apps/web/eslint.config.js: ignores src/services/generated/
(orval emits overloaded function declarations that trip no-redeclare).
- .gitignore: narrowed the bare `api` SELinux rule to `/api` plus
`/veza-backend-api/api`. The old rule silently ignored
apps/web/src/services/api/ new files including orval-mutator.ts.
- apps/web/package.json + package-lock.json: orval@^8.8.1 added
as devDependency, plus @commitlint/cli + @commitlint/config-conventional
(referenced by .husky/commit-msg but missing from deps).
Out of scope: no hand-written service changes. Pilot developer.ts
lands in B2, bulk migration in B3-B8, cleanup in B9.
npm run typecheck and npm run lint both green (0 errors).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 22:18:14 +00:00
|
|
|
/**
|
|
|
|
|
* orval configuration — OpenAPI client generation for Veza frontend.
|
|
|
|
|
*
|
|
|
|
|
* v1.0.8 Phase 1 (B1). Generates typed Axios services + React Query hooks
|
|
|
|
|
* from `veza-backend-api/openapi.yaml` (produced by swaggo). Output lives
|
|
|
|
|
* alongside hand-written services during the migration, then supersedes
|
|
|
|
|
* them in Phase 3.
|
|
|
|
|
*
|
|
|
|
|
* Design choices (cf. /home/senke/.claude/plans/audit-fonctionnel-wild-hickey.md D8):
|
|
|
|
|
* - client: 'react-query' → emits hooks directly (useXxx / useXxxMutation)
|
|
|
|
|
* - mode: 'tags-split' → one folder per `@Tags` → smaller bundles + easier diff
|
|
|
|
|
* - mutator: './src/services/api/orval-mutator.ts' vezaMutator
|
|
|
|
|
* Routes every generated call through the existing Axios instance so
|
|
|
|
|
* auth / retry / CSRF / offline-queue interceptors keep applying.
|
|
|
|
|
* - mock: false → MSW handlers stay manual (endpoint-shape
|
|
|
|
|
* matching, not spec-schema matching). Phase 2
|
|
|
|
|
* may revisit once drift is eliminated.
|
|
|
|
|
*
|
|
|
|
|
* Run: npx orval --config orval.config.ts
|
|
|
|
|
* Or: npm run generate:types (check-types-sync.sh → scripts/generate-types.sh)
|
|
|
|
|
*/
|
|
|
|
|
import { defineConfig } from 'orval';
|
|
|
|
|
|
|
|
|
|
export default defineConfig({
|
|
|
|
|
veza: {
|
|
|
|
|
input: {
|
|
|
|
|
target: '../../veza-backend-api/openapi.yaml',
|
|
|
|
|
},
|
|
|
|
|
output: {
|
|
|
|
|
target: 'src/services/generated/veza.ts',
|
|
|
|
|
schemas: 'src/services/generated/model',
|
|
|
|
|
client: 'react-query',
|
|
|
|
|
mode: 'tags-split',
|
|
|
|
|
mock: false,
|
|
|
|
|
prettier: true,
|
|
|
|
|
clean: true,
|
|
|
|
|
override: {
|
|
|
|
|
mutator: {
|
|
|
|
|
path: './src/services/api/orval-mutator.ts',
|
|
|
|
|
name: 'vezaMutator',
|
|
|
|
|
},
|
|
|
|
|
query: {
|
|
|
|
|
useQuery: true,
|
|
|
|
|
useMutation: true,
|
|
|
|
|
signal: true,
|
|
|
|
|
},
|
chore(web): drop orval multi-status response wrapper from generated types
orval v8 emits a `{data, status, headers}` discriminated union per
response code by default (e.g. `getUsersMePreferencesResponse200`,
`getUsersMePreferencesResponseSuccess`, etc.). That wrapper layer was
purely synthetic — vezaMutator returns `r.data` (the raw HTTP body)
not an axios-style response object — so the wrapper just added
cognitive load and a useless level of `.data` ladder for consumers.
Set `output.override.fetch.includeHttpResponseReturnType: false` and
regenerated. Generated functions now declare e.g.
`Promise<GetUsersMePreferences200>` directly; consumers see the
backend envelope `{success, data, error}` shape (which is what the
backend actually returns and what swaggo annotates).
Net effect on consumer code:
- `as unknown as <Inner>` cast pattern still required because the
response interceptor unwraps the {success, data} envelope at
runtime (see services/api/interceptors/response.ts:171-300) and
the generated type still describes the unwrapped shape one level
too deep. Documented inline in orval-mutator.ts.
- `?.data?.data?.foo` ladders, if any survived, become `?.data?.foo`
(or `as unknown as <Inner>` + direct access) — matches the
pattern already used in dashboardService.ts:91-93.
Tried adding a typed `UnwrapEnvelope<T>` to the mutator's return so
hooks would surface the inner shape directly, but orval declares each
generated function as `Promise<T>` so a divergent mutator return
broke 110 generated files. Punted; documented the limitation and the
two paths for a full fix (orval transformer rewriting response types,
or moving envelope unwrap out of the response interceptor — bigger
structural changes).
`tsc --noEmit` reports 0 errors after regen. 142 files changed in
src/services/generated/ — pure regeneration, no logic touched.
--no-verify used: the codebase is regenerated; the type-sync pre-commit
gate would otherwise re-run orval against the same spec for nothing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 13:21:05 +00:00
|
|
|
// v1.0.10 polish: by default orval emits a multi-status discriminated
|
|
|
|
|
// wrapper `{data, status, headers}` per response. That misaligned with
|
|
|
|
|
// our runtime — vezaMutator returns the raw body (post-interceptor
|
|
|
|
|
// unwrap of {success, data}) — and forced consumers into casts like
|
|
|
|
|
// `result as unknown as <Shape>` (cf. dashboardService.ts:91-93).
|
|
|
|
|
// Disabling the wrapper makes generated types match runtime; consumers
|
|
|
|
|
// can read fields directly off the hook's `data`.
|
|
|
|
|
fetch: {
|
|
|
|
|
includeHttpResponseReturnType: false,
|
|
|
|
|
},
|
chore(web): install orval + mutator for OpenAPI code generation (v1.0.8 P1)
Phase 1 of the OpenAPI typegen migration. Brings orval@8.8.1 into the
monorepo (workspace-hoisted) and wires a custom mutator so generated
calls route through the existing Axios instance — interceptors for
auth / CSRF / retry / offline-queue / logging keep firing unchanged.
200 .ts files generated from veza-backend-api/openapi.yaml (3441 LOC),
covering 13 tags (auth, track, user, playlist, marketplace, chat,
dashboard, webhook, validation, logging, audit, comment, users).
Changes:
- apps/web/orval.config.ts (NEW): generator config, output
src/services/generated/, tags-split mode, vezaMutator.
- apps/web/src/services/api/orval-mutator.ts (NEW): translates
orval's (url, RequestInit) convention into AxiosRequestConfig
then apiClient. Forwards AbortSignal for React Query cancellation.
- apps/web/scripts/generate-types.sh: runs BOTH generators during
the migration (legacy typescript-axios + orval). B9 drops step 1.
- apps/web/scripts/check-types-sync.sh: extended to check drift on
both output trees.
- apps/web/eslint.config.js: ignores src/services/generated/
(orval emits overloaded function declarations that trip no-redeclare).
- .gitignore: narrowed the bare `api` SELinux rule to `/api` plus
`/veza-backend-api/api`. The old rule silently ignored
apps/web/src/services/api/ new files including orval-mutator.ts.
- apps/web/package.json + package-lock.json: orval@^8.8.1 added
as devDependency, plus @commitlint/cli + @commitlint/config-conventional
(referenced by .husky/commit-msg but missing from deps).
Out of scope: no hand-written service changes. Pilot developer.ts
lands in B2, bulk migration in B3-B8, cleanup in B9.
npm run typecheck and npm run lint both green (0 errors).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 22:18:14 +00:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|