# @uschuster/webapp-scaffold Shared frontend build glue for webapp-template-derived projects. ## What's in v0.1 | Path | Purpose | |------|---------| | `bin/fetch-openapi.sh` | Pull the oatpp Swagger spec from a running backend. Configurable via `OPENAPI_URL` / `APP_URL` / `APP_TEST_PORT`, optional Bearer via `APP_API_KEY`. JSON-validated. | | `bin/postprocess-openapi.py` | Clean up oatpp 1.3's rough edges (missing `operationId`s, missing tags) before handing the spec to Orval. | | `bin/inject-hashed-filenames.py` | Rewrite HTML script tags to point at Vite's manifest-declared hashed bundle. Config-driven so projects with multiple entry points (admin + guest) use a single invocation. | | `src/vite-config.ts` | `defineAdminConfig({root, vendorChunks?, outDir?})` and `defineGuestConfig({root, entry?, vendorChunks?, outDir?})` helpers that bake in the `VITE_BASE`-driven prefix convention, manifest output, and the `static/{dist,guest/dist}` output layout the `StaticController` expects. | | `templates/orval.config.template.ts` | Starting `orval.config.ts` for derived projects to copy-and-tweak. | ## Install ```json { "devDependencies": { "@uschuster/webapp-scaffold": "^0.1.0" } } ``` Register the internal Forgejo npm registry (see your `~/.npmrc`): ``` @uschuster:registry=http://127.0.0.1:3000/api/packages/uwe.admin/npm/ ``` ## Consumer wiring ```ts // frontend/vite.config.ts import { defineAdminConfig } from '@uschuster/webapp-scaffold'; export default defineAdminConfig({ root: __dirname }); ``` ```sh # frontend/package.json > scripts > codegen webapp-scaffold-fetch-openapi && \ webapp-scaffold-postprocess-openapi && \ orval ``` ## `createCoreFetch` (v0.2) Orval's `client: 'fetch'` calls a mutator `coreFetch(url, init)` and expects `{data, status, headers}` back. `createCoreFetch(opts)` returns such a function, with credentials/CSRF headers / 204 / content-type handling already wired, and hooks for project-specific concerns: ```ts import { createCoreFetch } from '@uschuster/webapp-scaffold/core-fetch'; export const coreFetch = createCoreFetch({ baseUrl: import.meta.env.BASE_URL, syncTables: new Set(['bookings', 'persons', 'contacts']), onEnqueue: (req) => syncQueue.push(req), // returns true ⇒ skip network on401: () => window.location.assign('/admin'), on409: (_req, body) => ({ conflict: JSON.parse(body) }), }); ``` ## Roadmap - **v0.3** — i18n system (de/en × formal/informal with fallback chain).