Compare commits
No commits in common. "2540666e1a317b6343fe22b49b4c0fdf6a34bd9c" and "5658ef7bcce2b4f9331247b04e9b983f3ea48e02" have entirely different histories.
2540666e1a
...
5658ef7bcc
10 changed files with 147 additions and 161 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -22,9 +22,6 @@ Thumbs.db
|
||||||
vite.config.js.timestamp-*
|
vite.config.js.timestamp-*
|
||||||
vite.config.ts.timestamp-*
|
vite.config.ts.timestamp-*
|
||||||
|
|
||||||
# Zwischendatei der Typgenerierung
|
|
||||||
.schema.tmp.json
|
|
||||||
|
|
||||||
# PocketBase-Laufzeitdaten
|
# PocketBase-Laufzeitdaten
|
||||||
backend/pb_data/
|
backend/pb_data/
|
||||||
*.db
|
*.db
|
||||||
|
|
|
||||||
12
CLAUDE.md
12
CLAUDE.md
|
|
@ -30,8 +30,7 @@ npm run check
|
||||||
# Type-check with watch mode
|
# Type-check with watch mode
|
||||||
npm run check:watch
|
npm run check:watch
|
||||||
|
|
||||||
# Generate TypeScript types from the schema migration in backend/pb_migrations
|
# Generate TypeScript types from PocketBase schema
|
||||||
# (no running instance, no token, no network access needed)
|
|
||||||
npm run generate-pocketbase-types
|
npm run generate-pocketbase-types
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -54,11 +53,8 @@ docker compose down
|
||||||
- **API Base URL**: konfigurierbar über `PUBLIC_PB_URL` in `frontend/.env`.
|
- **API Base URL**: konfigurierbar über `PUBLIC_PB_URL` in `frontend/.env`.
|
||||||
Default ist die produktive Instanz `https://api.stammtisch-hersbruck.de`;
|
Default ist die produktive Instanz `https://api.stammtisch-hersbruck.de`;
|
||||||
für das lokale Backend aus `backend/` auf `http://127.0.0.1:8090` umstellen.
|
für das lokale Backend aus `backend/` auf `http://127.0.0.1:8090` umstellen.
|
||||||
- **Schema**: versioniert als Migration in `backend/pb_migrations/`, kommt per
|
- **Schema**: versioniert als Migration in `backend/pb_migrations/`. Änderungen
|
||||||
`COPY` ins Image (kein Bind-Mount — der würde das Image-Verzeichnis
|
im Admin-UI erzeugen dort neue Dateien, die committet werden müssen.
|
||||||
überdecken). Im Admin-UI erzeugte Migrationen liegen deshalb zunächst nur im
|
|
||||||
Container und müssen mit `docker compose cp` ins Repo geholt werden; siehe
|
|
||||||
`backend/README.md`.
|
|
||||||
- **Type-safe client**: The PocketBase client is typed using auto-generated types in `frontend/src/lib/types.d.ts`
|
- **Type-safe client**: The PocketBase client is typed using auto-generated types in `frontend/src/lib/types.d.ts`
|
||||||
- **Collections**: users, teams, events, runs, riders, times
|
- **Collections**: users, teams, events, runs, riders, times
|
||||||
- **Authentication**: Handled through `src/lib/stores/pocketbase.svelte.ts` with the `AuthStore` class
|
- **Authentication**: Handled through `src/lib/stores/pocketbase.svelte.ts` with the `AuthStore` class
|
||||||
|
|
@ -100,7 +96,7 @@ The app uses Svelte 5 runes for state management with a custom store pattern:
|
||||||
- `$derived()` for computed values
|
- `$derived()` for computed values
|
||||||
- `{@render children?.()}` for slot content
|
- `{@render children?.()}` for slot content
|
||||||
|
|
||||||
**Type Generation**: After modifying the schema migration in `backend/pb_migrations/`, run `npm run generate-pocketbase-types` to update `frontend/src/lib/types.d.ts`. The script reads the collections array straight out of the migration (`frontend/scripts/schema-to-json.mjs`) — schema and types come from the same versioned source and cannot drift apart. Commit the regenerated file.
|
**Type Generation**: After modifying PocketBase schema, run `npm run generate-pocketbase-types` to update TypeScript types.
|
||||||
|
|
||||||
**Async Data Loading**: Root layout (`src/routes/+layout.svelte`) shows pattern:
|
**Async Data Loading**: Root layout (`src/routes/+layout.svelte`) shows pattern:
|
||||||
```svelte
|
```svelte
|
||||||
|
|
|
||||||
|
|
@ -28,24 +28,8 @@ per `GET /api/collections` abgezogen und ruft `importCollections` mit
|
||||||
`deleteMissing = false` auf — die Migration legt an und aktualisiert, löscht
|
`deleteMissing = false` auf — die Migration legt an und aktualisiert, löscht
|
||||||
aber nichts, was nicht im Snapshot steht.
|
aber nichts, was nicht im Snapshot steht.
|
||||||
|
|
||||||
### Schema-Änderungen aus dem Admin-UI holen
|
Schema-Änderungen im Admin-UI erzeugen in `pb_migrations/` neue Dateien; diese
|
||||||
|
müssen committet werden.
|
||||||
`pb_migrations/` wird **nicht** in den Container gemountet — die Migrationen
|
|
||||||
kommen über `COPY` ins Image (siehe `Dockerfile`). Das ist Absicht: Ein
|
|
||||||
Bind-Mount überdeckt das Image-Verzeichnis, und auf einem Deployment-Host ohne
|
|
||||||
ausgechecktes Repo legt Docker dort ein leeres Verzeichnis an. PocketBase
|
|
||||||
findet dann keine Migration und startet mit einer Datenbank ohne Collections.
|
|
||||||
|
|
||||||
Die Kehrseite: Eine im Admin-UI erzeugte Migration liegt zunächst nur im
|
|
||||||
Container und muss von Hand herausgeholt werden:
|
|
||||||
|
|
||||||
# Welche Dateien sind dazugekommen?
|
|
||||||
docker compose exec pocketbase ls /pb/pb_migrations
|
|
||||||
|
|
||||||
# Die neue Datei ins Repo kopieren und committen
|
|
||||||
docker compose cp pocketbase:/pb/pb_migrations/<datei> ./pb_migrations/
|
|
||||||
|
|
||||||
Ohne diesen Schritt ist die Änderung beim nächsten `--build` verloren.
|
|
||||||
|
|
||||||
Ein frisch gestarteter Container hat damit dasselbe Schema wie die produktive
|
Ein frisch gestarteter Container hat damit dasselbe Schema wie die produktive
|
||||||
Instanz — aber **keine** Daten.
|
Instanz — aber **keine** Daten.
|
||||||
|
|
|
||||||
|
|
@ -14,17 +14,12 @@ services:
|
||||||
# Redeploy alles weg — das Schema käme zwar aus pb_migrations zurück,
|
# Redeploy alles weg — das Schema käme zwar aus pb_migrations zurück,
|
||||||
# die Daten aber nicht.
|
# die Daten aber nicht.
|
||||||
- ./pb_data:/pb/pb_data
|
- ./pb_data:/pb/pb_data
|
||||||
# ACHTUNG: pb_migrations wird bewusst NICHT gemountet. Ein Bind-Mount
|
# Migrationen zurück auf den Host. Ohne dieses Mapping schreibt PocketBase
|
||||||
# überdeckt das Verzeichnis aus dem Image. Liegt auf dem Host kein
|
# die bei Schema-Änderungen im Admin-UI erzeugten Dateien nur ins
|
||||||
# ausgechecktes Repo daneben, legt Docker ein leeres Verzeichnis an —
|
# Container-Dateisystem — sie wären beim nächsten Build verloren und
|
||||||
# PocketBase findet dann keine einzige Migration und startet mit einer
|
# könnten nie committet werden. Das COPY im Dockerfile bleibt trotzdem
|
||||||
# Datenbank ohne Collections. Genau das ist bei einem Deployment
|
# bestehen, damit das Image auch ohne Bind-Mount das Schema mitbringt.
|
||||||
# passiert, das nur die compose-Datei kennt.
|
- ./pb_migrations:/pb/pb_migrations
|
||||||
#
|
|
||||||
# Die Migrationen kommen deshalb ausschließlich über COPY ins Image
|
|
||||||
# (siehe Dockerfile). Im Admin-UI erzeugte Migrationen landen damit nur
|
|
||||||
# im Container und müssen von Hand herausgeholt werden:
|
|
||||||
# docker compose cp pocketbase:/pb/pb_migrations/<datei> ./pb_migrations/
|
|
||||||
environment:
|
environment:
|
||||||
# Superuser wird nur beim allerersten Start angelegt (siehe entrypoint.sh)
|
# Superuser wird nur beim allerersten Start angelegt (siehe entrypoint.sh)
|
||||||
SUPERUSER_EMAIL: ${SUPERUSER_EMAIL:-}
|
SUPERUSER_EMAIL: ${SUPERUSER_EMAIL:-}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,19 @@
|
||||||
# Vorlage für die lokale .env — kopieren und ausfüllen:
|
# Vorlage für die lokale .env — kopieren und ausfüllen:
|
||||||
# cp .env.example .env
|
# cp .env.example .env
|
||||||
|
#
|
||||||
|
# Die echte .env steht in .gitignore und darf nicht committet werden,
|
||||||
|
# sie enthält den Superuser-Token.
|
||||||
|
|
||||||
# Basis-URL der PocketBase-Instanz, die das Frontend anspricht.
|
# Basis-URL der PocketBase-Instanz, die das Frontend anspricht.
|
||||||
# Produktiv: https://api.stammtisch-hersbruck.de
|
# Produktiv: https://api.stammtisch-hersbruck.de
|
||||||
# Lokales Backend aus ../backend: http://127.0.0.1:8090
|
# Lokales Backend aus ../backend: http://127.0.0.1:8090
|
||||||
#
|
|
||||||
# Die Variable wird zur Buildzeit eingesetzt ($env/static/public). Ein Wechsel
|
|
||||||
# der Instanz erfordert deshalb einen Neustart des Dev-Servers bzw. einen
|
|
||||||
# neuen Build.
|
|
||||||
PUBLIC_PB_URL=https://api.stammtisch-hersbruck.de
|
PUBLIC_PB_URL=https://api.stammtisch-hersbruck.de
|
||||||
|
|
||||||
|
# Ziel für die Typgenerierung (npm run generate-pocketbase-types) und die
|
||||||
|
# Scripts unter scripts/. Zeigt üblicherweise auf dieselbe Instanz wie oben.
|
||||||
|
PB_TYPEGEN_URL=https://api.stammtisch-hersbruck.de/
|
||||||
|
|
||||||
|
# Superuser-Token für Schema-Zugriffe. Im PocketBase-Admin-UI erzeugen.
|
||||||
|
# Niemals committen.
|
||||||
|
PB_SUPERUSER_TOKEN=
|
||||||
|
PB_TYPEGEN_TOKEN=
|
||||||
|
|
|
||||||
|
|
@ -35,27 +35,15 @@ Die App läuft dann auf http://stammtisch-hersbruck.de.localhost:31337
|
||||||
|
|
||||||
Die Variable wird von SvelteKit zur **Buildzeit** eingesetzt
|
Die Variable wird von SvelteKit zur **Buildzeit** eingesetzt
|
||||||
(`$env/static/public`). Ein Wechsel der Instanz erfordert deshalb einen
|
(`$env/static/public`). Ein Wechsel der Instanz erfordert deshalb einen
|
||||||
Neustart des Dev-Servers bzw. einen neuen Build — ein bloßer Neustart des
|
Neustart des Dev-Servers bzw. einen neuen Build — ein blosser Neustart des
|
||||||
Containers genügt nicht.
|
Containers genügt nicht.
|
||||||
|
|
||||||
Es ist die einzige Variable in `.env`; ein Token wird nicht mehr gebraucht.
|
`PB_TYPEGEN_URL` und `PB_SUPERUSER_TOKEN` gelten getrennt davon für
|
||||||
|
`npm run generate-pocketbase-types`.
|
||||||
|
|
||||||
## Typen
|
## Schema
|
||||||
|
|
||||||
Das maßgebliche Schema liegt als Migration in `../backend/pb_migrations/`.
|
Das maßgebliche Schema liegt als Migration in `../backend/pb_migrations/`.
|
||||||
Daraus entstehen auch die TypeScript-Typen:
|
Nach einer Schema-Änderung `npm run generate-pocketbase-types` ausführen — das
|
||||||
|
aktualisiert `src/lib/types.d.ts`, aus dem der PocketBase-Client seine Typen
|
||||||
npm run generate-pocketbase-types
|
bezieht.
|
||||||
|
|
||||||
Das Script liest das Collections-Array aus der Migration
|
|
||||||
(`scripts/schema-to-json.mjs`) und erzeugt daraus `src/lib/types.d.ts`. Es
|
|
||||||
braucht **keine laufende Instanz, keinen Token und keinen Netzwerkzugriff** —
|
|
||||||
Schema und Typen kommen aus derselben versionierten Quelle und können deshalb
|
|
||||||
nicht auseinanderlaufen.
|
|
||||||
|
|
||||||
Nach jeder Schema-Änderung in `../backend/pb_migrations/` einmal ausführen und
|
|
||||||
die aktualisierte `types.d.ts` mitcommitten.
|
|
||||||
|
|
||||||
> Die System-Collections (`_superusers`, `_mfas`, …) stehen bewusst nicht in
|
|
||||||
> der Migration und fehlen deshalb in den Typen. Die Anwendung verwendet sie
|
|
||||||
> nicht.
|
|
||||||
|
|
|
||||||
86
frontend/package-lock.json
generated
86
frontend/package-lock.json
generated
|
|
@ -1586,9 +1586,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "1.1.18",
|
"version": "1.1.12",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||||
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
|
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
|
@ -1697,7 +1697,6 @@
|
||||||
"version": "6.2.1",
|
"version": "6.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
|
||||||
"integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
|
"integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
|
||||||
"deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
|
@ -2108,9 +2107,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/es-object-atoms": {
|
"node_modules/es-object-atoms": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||||
"integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==",
|
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -2229,17 +2228,17 @@
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/form-data": {
|
"node_modules/form-data": {
|
||||||
"version": "4.0.6",
|
"version": "4.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
|
||||||
"integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==",
|
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"asynckit": "^0.4.0",
|
"asynckit": "^0.4.0",
|
||||||
"combined-stream": "^1.0.8",
|
"combined-stream": "^1.0.8",
|
||||||
"es-set-tostringtag": "^2.1.0",
|
"es-set-tostringtag": "^2.1.0",
|
||||||
"hasown": "^2.0.4",
|
"hasown": "^2.0.2",
|
||||||
"mime-types": "^2.1.35"
|
"mime-types": "^2.1.12"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
|
|
@ -2390,7 +2389,7 @@
|
||||||
"version": "7.2.3",
|
"version": "7.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||||
"deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
|
"deprecated": "Glob versions prior to v9 are no longer supported",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
|
@ -2467,9 +2466,9 @@
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/hasown": {
|
"node_modules/hasown": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||||
"integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==",
|
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -2628,9 +2627,9 @@
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/ip-address": {
|
"node_modules/ip-address": {
|
||||||
"version": "10.4.0",
|
"version": "10.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz",
|
||||||
"integrity": "sha512-oSK96Grm3aP6OrS263xVxbNDGVL7rzBtYdpGqlDG8iQdoenDoTs/nkki+DflYbAEE8Xl6o5YxhxlrKvI3nqKXQ==",
|
"integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
|
@ -3097,9 +3096,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/minimatch": {
|
"node_modules/minimatch": {
|
||||||
"version": "3.1.5",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||||
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
|
@ -3223,11 +3222,11 @@
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/minipass-flush": {
|
"node_modules/minipass-flush": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz",
|
||||||
"integrity": "sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==",
|
"integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BlueOak-1.0.0",
|
"license": "ISC",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minipass": "^3.0.0"
|
"minipass": "^3.0.0"
|
||||||
|
|
@ -3491,9 +3490,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/node-abi": {
|
"node_modules/node-abi": {
|
||||||
"version": "3.94.0",
|
"version": "3.78.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.94.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.78.0.tgz",
|
||||||
"integrity": "sha512-W5ZNO5KRPB5TkYmGVD9F6YqhsglXJzE6etpbmT+f6EQElhiX/UTG551cnsRGvLG3fyZEg9HwaDmNmj5nwJ4z9g==",
|
"integrity": "sha512-E2wEyrgX/CqvicaQYU3Ze1PFGjc4QYPGsjUrlYkqAE0WjHEZwgOsGMPMzkMse4LjJbDmaEuDX3CM036j5K2DSQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -3612,7 +3611,6 @@
|
||||||
"version": "6.2.1",
|
"version": "6.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
|
||||||
"integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
|
"integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
|
||||||
"deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
|
@ -3800,7 +3798,6 @@
|
||||||
"version": "7.1.3",
|
"version": "7.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
|
||||||
"integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
|
"integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
|
||||||
"deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -3848,9 +3845,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pump": {
|
"node_modules/pump": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
|
||||||
"integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==",
|
"integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -4042,9 +4039,9 @@
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "7.8.5",
|
"version": "7.7.3",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
|
||||||
"integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
|
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|
@ -4152,14 +4149,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/socks": {
|
"node_modules/socks": {
|
||||||
"version": "2.8.9",
|
"version": "2.8.7",
|
||||||
"resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz",
|
"resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz",
|
||||||
"integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==",
|
"integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ip-address": "^10.1.1",
|
"ip-address": "^10.0.1",
|
||||||
"smart-buffer": "^4.2.0"
|
"smart-buffer": "^4.2.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
@ -4276,7 +4273,6 @@
|
||||||
"version": "6.2.1",
|
"version": "6.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
|
||||||
"integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
|
"integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
|
||||||
"deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -4540,9 +4536,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tar-fs": {
|
"node_modules/tar-fs": {
|
||||||
"version": "2.1.5",
|
"version": "2.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
|
||||||
"integrity": "sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==",
|
"integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
"prepare": "svelte-kit sync || echo ''",
|
"prepare": "svelte-kit sync || echo ''",
|
||||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||||
"generate-pocketbase-types": "node scripts/schema-to-json.mjs > .schema.tmp.json && pocketbase-typegen --json .schema.tmp.json --out ./src/lib/types.d.ts && rm -f .schema.tmp.json"
|
"generate-pocketbase-types": "set -a && . ./.env && set +a && pocketbase-typegen --url \"$PB_TYPEGEN_URL\" --token \"$PB_SUPERUSER_TOKEN\" --out ./src/lib/types.d.ts"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@internationalized/date": "^3.12.1",
|
"@internationalized/date": "^3.12.1",
|
||||||
|
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
/**
|
|
||||||
* Extrahiert das Collections-Array aus der PocketBase-Migration und schreibt es
|
|
||||||
* als JSON auf stdout — in der Form, die `pocketbase-typegen --json` erwartet.
|
|
||||||
*
|
|
||||||
* Damit entstehen die TypeScript-Typen aus dem versionierten Schema im Repo,
|
|
||||||
* ohne laufende Instanz, ohne Token und ohne Netzwerkzugriff.
|
|
||||||
*
|
|
||||||
* Aufruf über npm run generate-pocketbase-types.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { readFileSync, readdirSync } from 'node:fs'
|
|
||||||
import { join } from 'node:path'
|
|
||||||
|
|
||||||
const MIGRATIONS_DIR = new URL('../../backend/pb_migrations/', import.meta.url).pathname
|
|
||||||
|
|
||||||
// Die Snapshot-Migration ist die einzige, die ein vollständiges
|
|
||||||
// `const collections = [...]` enthält. Bei mehreren Dateien gewinnt die
|
|
||||||
// jüngste — Migrationen sind nach Zeitstempel benannt.
|
|
||||||
const candidates = readdirSync(MIGRATIONS_DIR)
|
|
||||||
.filter((f) => f.endsWith('.js'))
|
|
||||||
.sort()
|
|
||||||
.reverse()
|
|
||||||
|
|
||||||
const MARKER = 'const collections = '
|
|
||||||
|
|
||||||
for (const file of candidates) {
|
|
||||||
const source = readFileSync(join(MIGRATIONS_DIR, file), 'utf8')
|
|
||||||
const start = source.indexOf(MARKER)
|
|
||||||
if (start === -1) continue
|
|
||||||
|
|
||||||
// Vom öffnenden [ bis zur zugehörigen schließenden Klammer zählen —
|
|
||||||
// ein Regex käme an den verschachtelten Arrays der Feldoptionen nicht vorbei.
|
|
||||||
const from = start + MARKER.length
|
|
||||||
let depth = 0
|
|
||||||
|
|
||||||
for (let i = from; i < source.length; i++) {
|
|
||||||
if (source[i] === '[') depth++
|
|
||||||
else if (source[i] === ']') {
|
|
||||||
depth--
|
|
||||||
if (depth === 0) {
|
|
||||||
process.stdout.write(source.slice(from, i + 1))
|
|
||||||
process.exit(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.error(
|
|
||||||
`Keine Migration mit "${MARKER.trim()}" in ${MIGRATIONS_DIR} gefunden.\n` +
|
|
||||||
`Ohne sie lassen sich die Typen nicht aus dem Repo erzeugen.`
|
|
||||||
)
|
|
||||||
process.exit(1)
|
|
||||||
74
frontend/src/lib/types.d.ts
vendored
74
frontend/src/lib/types.d.ts
vendored
|
|
@ -6,6 +6,11 @@ import type PocketBase from 'pocketbase'
|
||||||
import type { RecordService } from 'pocketbase'
|
import type { RecordService } from 'pocketbase'
|
||||||
|
|
||||||
export enum Collections {
|
export enum Collections {
|
||||||
|
Authorigins = "_authOrigins",
|
||||||
|
Externalauths = "_externalAuths",
|
||||||
|
Mfas = "_mfas",
|
||||||
|
Otps = "_otps",
|
||||||
|
Superusers = "_superusers",
|
||||||
Events = "events",
|
Events = "events",
|
||||||
Riders = "riders",
|
Riders = "riders",
|
||||||
Runs = "runs",
|
Runs = "runs",
|
||||||
|
|
@ -41,6 +46,55 @@ export type AuthSystemFields<T = unknown> = {
|
||||||
|
|
||||||
// Record types for each collection
|
// Record types for each collection
|
||||||
|
|
||||||
|
export type AuthoriginsRecord = {
|
||||||
|
collectionRef: string
|
||||||
|
created?: IsoDateString
|
||||||
|
fingerprint: string
|
||||||
|
id: string
|
||||||
|
recordRef: string
|
||||||
|
updated?: IsoDateString
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ExternalauthsRecord = {
|
||||||
|
collectionRef: string
|
||||||
|
created?: IsoDateString
|
||||||
|
id: string
|
||||||
|
provider: string
|
||||||
|
providerId: string
|
||||||
|
recordRef: string
|
||||||
|
updated?: IsoDateString
|
||||||
|
}
|
||||||
|
|
||||||
|
export type MfasRecord = {
|
||||||
|
collectionRef: string
|
||||||
|
created?: IsoDateString
|
||||||
|
id: string
|
||||||
|
method: string
|
||||||
|
recordRef: string
|
||||||
|
updated?: IsoDateString
|
||||||
|
}
|
||||||
|
|
||||||
|
export type OtpsRecord = {
|
||||||
|
collectionRef: string
|
||||||
|
created?: IsoDateString
|
||||||
|
id: string
|
||||||
|
password: string
|
||||||
|
recordRef: string
|
||||||
|
sentTo?: string
|
||||||
|
updated?: IsoDateString
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SuperusersRecord = {
|
||||||
|
created?: IsoDateString
|
||||||
|
email: string
|
||||||
|
emailVisibility?: boolean
|
||||||
|
id: string
|
||||||
|
password: string
|
||||||
|
tokenKey: string
|
||||||
|
updated?: IsoDateString
|
||||||
|
verified?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export enum EventsStatusOptions {
|
export enum EventsStatusOptions {
|
||||||
"draft" = "draft",
|
"draft" = "draft",
|
||||||
"active" = "active",
|
"active" = "active",
|
||||||
|
|
@ -128,6 +182,11 @@ export type UsersRecord = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Response types include system fields and match responses from the PocketBase API
|
// Response types include system fields and match responses from the PocketBase API
|
||||||
|
export type AuthoriginsResponse<Texpand = unknown> = Required<AuthoriginsRecord> & BaseSystemFields<Texpand>
|
||||||
|
export type ExternalauthsResponse<Texpand = unknown> = Required<ExternalauthsRecord> & BaseSystemFields<Texpand>
|
||||||
|
export type MfasResponse<Texpand = unknown> = Required<MfasRecord> & BaseSystemFields<Texpand>
|
||||||
|
export type OtpsResponse<Texpand = unknown> = Required<OtpsRecord> & BaseSystemFields<Texpand>
|
||||||
|
export type SuperusersResponse<Texpand = unknown> = Required<SuperusersRecord> & AuthSystemFields<Texpand>
|
||||||
export type EventsResponse<Texpand = unknown> = Required<EventsRecord> & BaseSystemFields<Texpand>
|
export type EventsResponse<Texpand = unknown> = Required<EventsRecord> & BaseSystemFields<Texpand>
|
||||||
export type RidersResponse<Texpand = unknown> = Required<RidersRecord> & BaseSystemFields<Texpand>
|
export type RidersResponse<Texpand = unknown> = Required<RidersRecord> & BaseSystemFields<Texpand>
|
||||||
export type RunsResponse<Texpand = unknown> = Required<RunsRecord> & BaseSystemFields<Texpand>
|
export type RunsResponse<Texpand = unknown> = Required<RunsRecord> & BaseSystemFields<Texpand>
|
||||||
|
|
@ -138,6 +197,11 @@ export type UsersResponse<Texpand = unknown> = Required<UsersRecord> & AuthSyste
|
||||||
// Types containing all Records and Responses, useful for creating typing helper functions
|
// Types containing all Records and Responses, useful for creating typing helper functions
|
||||||
|
|
||||||
export type CollectionRecords = {
|
export type CollectionRecords = {
|
||||||
|
_authOrigins: AuthoriginsRecord
|
||||||
|
_externalAuths: ExternalauthsRecord
|
||||||
|
_mfas: MfasRecord
|
||||||
|
_otps: OtpsRecord
|
||||||
|
_superusers: SuperusersRecord
|
||||||
events: EventsRecord
|
events: EventsRecord
|
||||||
riders: RidersRecord
|
riders: RidersRecord
|
||||||
runs: RunsRecord
|
runs: RunsRecord
|
||||||
|
|
@ -147,6 +211,11 @@ export type CollectionRecords = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CollectionResponses = {
|
export type CollectionResponses = {
|
||||||
|
_authOrigins: AuthoriginsResponse
|
||||||
|
_externalAuths: ExternalauthsResponse
|
||||||
|
_mfas: MfasResponse
|
||||||
|
_otps: OtpsResponse
|
||||||
|
_superusers: SuperusersResponse
|
||||||
events: EventsResponse
|
events: EventsResponse
|
||||||
riders: RidersResponse
|
riders: RidersResponse
|
||||||
runs: RunsResponse
|
runs: RunsResponse
|
||||||
|
|
@ -159,6 +228,11 @@ export type CollectionResponses = {
|
||||||
// https://github.com/pocketbase/js-sdk#specify-typescript-definitions
|
// https://github.com/pocketbase/js-sdk#specify-typescript-definitions
|
||||||
|
|
||||||
export type TypedPocketBase = PocketBase & {
|
export type TypedPocketBase = PocketBase & {
|
||||||
|
collection(idOrName: '_authOrigins'): RecordService<AuthoriginsResponse>
|
||||||
|
collection(idOrName: '_externalAuths'): RecordService<ExternalauthsResponse>
|
||||||
|
collection(idOrName: '_mfas'): RecordService<MfasResponse>
|
||||||
|
collection(idOrName: '_otps'): RecordService<OtpsResponse>
|
||||||
|
collection(idOrName: '_superusers'): RecordService<SuperusersResponse>
|
||||||
collection(idOrName: 'events'): RecordService<EventsResponse>
|
collection(idOrName: 'events'): RecordService<EventsResponse>
|
||||||
collection(idOrName: 'riders'): RecordService<RidersResponse>
|
collection(idOrName: 'riders'): RecordService<RidersResponse>
|
||||||
collection(idOrName: 'runs'): RecordService<RunsResponse>
|
collection(idOrName: 'runs'): RecordService<RunsResponse>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue