chore(api): rely on sibling backend or committed OpenAPI for codegen

Drop live Swagger fetch so clients stay aligned through backend OpenAPI sync PRs.
This commit is contained in:
alisaza 2026-09-07 14:17:33 +03:30
parent 8721190502
commit 15beeb5897
3 changed files with 54 additions and 24 deletions

View File

@ -11,4 +11,12 @@ pnpm dev
The development server uses port **3009**. The development server uses port **3009**.
API client generation:
```bash
pnpm generate:api
```
Uses sibling `../ghabilee-backend` when present, otherwise the committed `openapi.json`. Cross-repo sync is handled by the backend `sync-openapi-clients` workflow.
This admin application is intentionally excluded from search-engine indexing and does not include Microsoft Clarity. Deployment secrets and environment-specific credentials will be added later by the repository owner. This admin application is intentionally excluded from search-engine indexing and does not include Microsoft Clarity. Deployment secrets and environment-specific credentials will be added later by the repository owner.

View File

@ -3,8 +3,7 @@ import { defineConfig } from 'orval'
export default defineConfig({ export default defineConfig({
api: { api: {
input: { input: {
// Committed mirror of backend/openapi.json so ghabilee-frontend // Sibling backend export or committed mirror (kept in sync by backend OpenAPI PRs).
// (satellite) can generate without a Nest sibling.
target: './openapi.json', target: './openapi.json',
}, },
output: { output: {

View File

@ -2,23 +2,29 @@
/** /**
* Generate Orval client into api/generated/. * Generate Orval client into api/generated/.
* *
* Monorepo: refresh OpenAPI from Nest when ../backend exists, then orval. * OpenAPI source priority:
* Satellite (ghabilee-frontend): orval only from committed ./openapi.json. * 1. Sibling Nest package (`../ghabilee-backend` or `../backend`) via `generate:openapi`
* 2. Committed `./openapi.json` (CI, satellite clones, OpenAPI sync PRs)
*
* Live Swagger fetch is intentionally not used clients stay in sync via
* ghabilee-backend's `sync-openapi-clients` workflow.
*/ */
import { spawnSync } from 'node:child_process' import { spawnSync } from 'node:child_process'
import { copyFileSync, existsSync } from 'node:fs' import { copyFileSync, existsSync } from 'node:fs'
import { dirname, join } from 'node:path' import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url' import { fileURLToPath } from 'node:url'
const frontendRoot = join(dirname(fileURLToPath(import.meta.url)), '..') const projectRoot = join(dirname(fileURLToPath(import.meta.url)), '..')
const backendOpenapi = join(frontendRoot, '../backend/openapi.json') const localOpenapi = join(projectRoot, 'openapi.json')
const localOpenapi = join(frontendRoot, 'openapi.json') const siblingBackendDirs = [
const backendDir = join(frontendRoot, '../backend') join(projectRoot, '../ghabilee-backend'),
join(projectRoot, '../backend'),
]
function run(command, args, opts = {}) { function run(command, args, opts = {}) {
const result = spawnSync(command, args, { const result = spawnSync(command, args, {
stdio: 'inherit', stdio: 'inherit',
cwd: frontendRoot, cwd: projectRoot,
shell: process.platform === 'win32', shell: process.platform === 'win32',
...opts, ...opts,
}) })
@ -27,23 +33,40 @@ function run(command, args, opts = {}) {
} }
} }
if (existsSync(backendDir) && existsSync(join(backendDir, 'package.json'))) { function trySiblingBackend() {
console.log('==> Exporting OpenAPI from backend...') for (const backendDir of siblingBackendDirs) {
if (!existsSync(backendDir) || !existsSync(join(backendDir, 'package.json'))) {
continue
}
const backendOpenapi = join(backendDir, 'openapi.json')
console.log(`==> Exporting OpenAPI from sibling backend (${backendDir})...`)
run('pnpm', ['--dir', backendDir, 'generate:openapi']) run('pnpm', ['--dir', backendDir, 'generate:openapi'])
if (!existsSync(backendOpenapi)) { if (!existsSync(backendOpenapi)) {
console.error(`Missing ${backendOpenapi} after export`) console.error(`Missing ${backendOpenapi} after export`)
process.exit(1) process.exit(1)
} }
copyFileSync(backendOpenapi, localOpenapi) copyFileSync(backendOpenapi, localOpenapi)
console.log('==> Copied backend/openapi.json → frontend/openapi.json') console.log('==> Copied sibling openapi.json → ./openapi.json')
} else if (!existsSync(localOpenapi)) { return true
}
return false
}
if (!trySiblingBackend()) {
if (!existsSync(localOpenapi)) {
console.error( console.error(
'No ../backend and no ./openapi.json — cannot generate API client.\n' + [
'In the satellite repo, openapi.json must be committed; re-sync from the monorepo.', 'No ../ghabilee-backend (or ../backend) and no ./openapi.json — cannot generate API client.',
'Place ghabilee-backend next to this repo, or wait for an OpenAPI sync PR / commit openapi.json.',
].join('\n'),
) )
process.exit(1) process.exit(1)
} else { }
console.log('==> No backend sibling — using committed ./openapi.json') console.log('==> Using committed ./openapi.json')
} }
console.log('==> Running orval...') console.log('==> Running orval...')