feature: sk-react-toolkit holds the server helpers, web components and Vite font plugin shared by manage-ui and sql-query-webui.
Release / release (push) Failing after 1m18s

This commit is contained in:
slawek committed 2026-10-28 19:08:10 +01:00
commit 4505b37abc
30 files changed
+4826

No files matched your search

+101
View File
@@ -0,0 +1,101 @@
# sk-react-toolkit
The shared code of the web tools built as a Fastify server in TypeScript and a React application
with MUI built by Vite, such as azure-platform's manage-ui and sql-query-webui. It is TypeScript
source: Node 26 runs the server helpers, and the application's Vite build compiles the web code.
## Using it
The package is `@koszewscy/sk-react-toolkit`, published to the npm registry of Gitea,
`https://gitea.koszewscy.waw.pl/api/packages/koszewscy/npm/`. An application imports it as
`sk-react-toolkit`, by an alias. Its `.npmrc` names the registry of the scope:
```ini
@koszewscy:registry=https://gitea.koszewscy.waw.pl/api/packages/koszewscy/npm/
```
```json
{ "dependencies": { "sk-react-toolkit": "npm:@koszewscy/sk-react-toolkit@^0.1.0" } }
```
While the toolkit and an application change together, the application depends on the checkout
next to its own repository instead, the TypeScript source:
```json
{ "dependencies": { "sk-react-toolkit": "file:../sk-react-toolkit" } }
```
npm links the checkout into `node_modules`, and `npm ci` keeps the link. The web application adds
the toolkit's resolve options and font plugin to its `vite.config.ts`, so React, MUI and Emotion
come from its own `node_modules`, and allows the dev server to read the checkout:
```ts
import { font, fontChoice, TOOLKIT_RESOLVE } from 'sk-react-toolkit/vite'
import { defineConfig, loadEnv } from 'vite'
export default defineConfig(({ mode }) => ({
plugins: [react(), font(fontChoice(loadEnv(mode, import.meta.dirname)))],
resolve: TOOLKIT_RESOLVE,
server: { fs: { allow: ['..', '../../sk-react-toolkit'] } },
}))
```
The peer dependencies are the application's: `fastify` and `@fastify/static` for the server
helpers; `react`, `react-dom`, `@mui/material`, `@mui/icons-material` and Emotion for the web
code; `vite` for the Vite helpers.
## sk-react-toolkit/server
| Export | Purpose |
| --- | --- |
| `HttpError` | an error answered with its status and `{ error }`, with `problems` and a `detail` message for a refused write |
| `strict(properties)` | the JSON schema of an object with exactly these properties, all required |
| `errorHandler(log)` | Fastify's error handler: `{ error }`, or `{ error, problems, message }`; unexpected 5xx errors logged with their stack |
| `notFoundHandler(webDir, buildHint)` | 404 for `/api` paths, `index.html` for the others, 503 with the hint while the frontend is not built |
| `createLog`, `timestampsOn`, `QUIET`, `Log` | the log of a server, with optional timestamps and requests; `QUIET` for tests |
| `fail(message)` | prints the error in red and ends the process with status 2 |
| `gitVersion(dir, variable)` | `git describe` of the checkout, else the environment variable, else `dev` |
| `exitOnSignals(close)` | closes the server on Ctrl-C and SIGTERM, ending the process after 5 seconds at most |
| `readJsonObject(path, options)` | a JSON object file and its version, the SHA-256 of its bytes; optionally `{}` for a missing file |
## sk-react-toolkit/web
| Export | Purpose |
| --- | --- |
| `request`, `ApiError`, `Validation` | a JSON call to the backend, its error with the problems of a refused write, and the answer of a validate endpoint |
| `appTheme(colorSchemes?)`, `renderApp(options)` | the theme (light, dark and system, Regular font, small text fields) and the startup that retries the first call while showing Connecting |
| `REGULAR`, `MONOSPACED`, `verbatim` | the font styles and the attributes of inputs the browser must not change |
| `Card` | a centered panel with a title and a message |
| `ThemeMenu` | the button cycling light, dark and system theme |
| `SwitcherMenu`, `SwitcherItem` | a button naming the item chosen, whose menu chooses another, such as a page or a connection |
| `TextInput` | a text field with clear and show/hide buttons |
| `RowDialog`, `useValidation` | a dialog that edits a value validated by the server as it changes, and the validation hook |
| `createBrowserSettings(keys, event)` | switches kept in localStorage and followed across tabs |
## sk-react-toolkit/vite
| Export | Purpose |
| --- | --- |
| `font(choice)`, `fontChoice(env)`, `FONTS` | the font plugin of `VITE_FONT`: `cdn` (Google Fonts links, the default), `bundled` (`@fontsource/roboto`, a dependency of the application) or `none` |
| `TOOLKIT_RESOLVE` | the resolve options that keep one copy of React, MUI and Emotion |
## Development
`npm install` installs the peer dependencies as development dependencies; `npm run typecheck`
and `npm run lint` check the code. `npm run build` (`build.mjs`) builds the published package in
`dist/`: the code compiled to JavaScript with its declarations, README.md, CHANGELOG.md and a
`package.json` whose exports name the compiled files.
## Releases
`./release.mjs` commits, tags the version of the newest CHANGELOG.md entry and pushes `main` with
the tag; `-n` prints the git commands instead. The version of a release of the code, `x.y.z`, is
that of `package.json`, so a release raises both. A tag `x.y.z-n` releases changes that are not
code changes; its version is already published, so its run publishes nothing.
The `Release` workflow, `.gitea/workflows/release.yml`, builds and publishes the package on Gitea
Actions for each tag and on demand: it installs the dependencies, typechecks and lints the code,
builds the package and publishes `dist/` to the npm registry of the owner `CI_OWNER` on the server
`CI_URL`, with `CI_TOKEN`, a token with the package scope; all three are secrets of the
repository. A version already published is skipped, as the registry refuses the same version
again.