From 2fef91a54803138d240128c30a8cd8d694ac845d Mon Sep 17 00:00:00 2001 From: Peter Meier Date: Fri, 17 Apr 2026 22:01:30 +0200 Subject: [PATCH] Initial SvelteKit frontend port of windwiderstand.de Full parity with Astro site: content rows, post/tag routes, pagination, event badges + OSM map, comments, Live-Search via /api/search-index, CMS image proxy, RSS, sitemap. Deploy: Dockerfile + docker-compose.prod.yml + Gitea Actions workflow to build + push to git.pm86.de registry and ssh-deploy to Contabo. --- .dockerignore | 9 + .env.example | 26 + .gitea/workflows/deploy.yml | 103 + .gitignore | 21 + Dockerfile | 38 + docker-compose.prod.yml | 20 + docker-compose.yml | 17 + package-lock.json | 2780 +++ package.json | 34 + scripts/generate-api-types.mjs | 46 + src/app.css | 491 + src/app.d.ts | 8 + src/app.html | 12 + src/hooks.server.ts | 53 + src/lib/block-layout.ts | 163 + src/lib/block-types.ts | 252 + src/lib/blog-utils.ts | 582 + src/lib/cms-api.generated.ts | 15632 ++++++++++++++++ src/lib/cms.ts | 672 + src/lib/components/Accordion.svelte | 29 + src/lib/components/Badge.svelte | 22 + src/lib/components/BlogOverview.svelte | 301 + src/lib/components/Card.svelte | 32 + src/lib/components/CmsImage.svelte | 45 + src/lib/components/ContentRows.svelte | 154 + src/lib/components/EventBadges.svelte | 49 + src/lib/components/EventMap.svelte | 78 + src/lib/components/Footer.svelte | 58 + src/lib/components/Header.svelte | 248 + src/lib/components/HeaderOverlay.svelte | 21 + src/lib/components/Pagination.svelte | 76 + src/lib/components/PostCard.svelte | 78 + src/lib/components/PostMeta.svelte | 29 + src/lib/components/RustyImage.svelte | 25 + src/lib/components/Search.svelte | 166 + src/lib/components/Tag.svelte | 118 + src/lib/components/Tags.svelte | 59 + src/lib/components/TopBanner.svelte | 80 + src/lib/components/TranslationProvider.svelte | 25 + .../components/blocks/CalendarBlock.svelte | 349 + .../components/blocks/HeadlineBlock.svelte | 25 + src/lib/components/blocks/HtmlBlock.svelte | 16 + src/lib/components/blocks/IframeBlock.svelte | 67 + src/lib/components/blocks/ImageBlock.svelte | 77 + .../blocks/ImageGalleryBlock.svelte | 216 + .../components/blocks/LinkListBlock.svelte | 37 + .../components/blocks/MarkdownBlock.svelte | 36 + src/lib/components/blocks/OpnFormBlock.svelte | 99 + .../blocks/OrganisationsBlock.svelte | 231 + .../blocks/PostOverviewBlock.svelte | 59 + src/lib/components/blocks/QuoteBlock.svelte | 18 + .../blocks/SearchableTextBlock.svelte | 324 + .../blocks/YoutubeVideoBlock.svelte | 36 + src/lib/constants.ts | 38 + src/lib/iconify-offline.ts | 12 + src/lib/image-cache.server.ts | 211 + src/lib/overlay-store.ts | 7 + src/lib/rusty-image.ts | 203 + src/lib/transform-cache.ts | 123 + src/lib/translations.ts | 153 + src/lib/ui/Badge.svelte | 57 + src/lib/ui/Breadcrumbs.svelte | 41 + src/lib/ui/Button.svelte | 46 + src/lib/ui/Checkbox.svelte | 23 + src/lib/ui/Radio.svelte | 25 + src/lib/ui/Select.svelte | 49 + src/lib/ui/SidebarNav.svelte | 33 + src/lib/ui/Slider.svelte | 39 + src/lib/ui/TabBar.svelte | 51 + src/lib/ui/TextInput.svelte | 57 + src/lib/ui/Textarea.svelte | 57 + src/lib/ui/Toggle.svelte | 29 + src/lib/ui/Tooltip.svelte | 83 + src/lib/ui/index.ts | 16 + src/routes/+error.svelte | 27 + src/routes/+layout.server.ts | 238 + src/routes/+layout.svelte | 172 + src/routes/+page.server.ts | 84 + src/routes/+page.svelte | 37 + src/routes/[...slug]/+page.server.ts | 67 + src/routes/[...slug]/+page.svelte | 17 + src/routes/api/revalidate/+server.ts | 65 + src/routes/api/search-index/+server.ts | 97 + src/routes/api/transform/+server.ts | 38 + src/routes/blog/+page.server.ts | 6 + src/routes/blog/page/[page]/+page.server.ts | 6 + src/routes/blog/tag/[tag]/+page.server.ts | 6 + src/routes/cms-images/+server.ts | 106 + src/routes/p/[slug]/+page.server.ts | 7 + src/routes/post/[slug]/+page.server.ts | 128 + src/routes/post/[slug]/+page.svelte | 87 + src/routes/posts/+page.server.ts | 19 + src/routes/posts/+page.svelte | 39 + src/routes/posts/page/[page]/+page.server.ts | 20 + src/routes/posts/page/[page]/+page.svelte | 39 + src/routes/posts/rss.xml/+server.ts | 72 + src/routes/posts/tag/[tag]/+page.server.ts | 20 + src/routes/posts/tag/[tag]/+page.svelte | 39 + .../tag/[tag]/page/[page]/+page.server.ts | 21 + .../posts/tag/[tag]/page/[page]/+page.svelte | 39 + src/routes/robots.txt/+server.ts | 20 + src/routes/sitemap.xml/+server.ts | 111 + static/apple-touch-icon.svg | 11 + static/favicon.ico | Bin 0 -> 655 bytes static/favicon.svg | 10 + static/favicons/android-icon-144x144.png | Bin 0 -> 11059 bytes static/favicons/android-icon-192x192.png | Bin 0 -> 12375 bytes static/favicons/android-icon-36x36.png | Bin 0 -> 2959 bytes static/favicons/android-icon-48x48.png | Bin 0 -> 3733 bytes static/favicons/android-icon-72x72.png | Bin 0 -> 5337 bytes static/favicons/android-icon-96x96.png | Bin 0 -> 7143 bytes static/favicons/apple-icon-114x114.png | Bin 0 -> 8530 bytes static/favicons/apple-icon-120x120.png | Bin 0 -> 9051 bytes static/favicons/apple-icon-144x144.png | Bin 0 -> 11059 bytes static/favicons/apple-icon-152x152.png | Bin 0 -> 11873 bytes static/favicons/apple-icon-180x180.png | Bin 0 -> 14743 bytes static/favicons/apple-icon-57x57.png | Bin 0 -> 4452 bytes static/favicons/apple-icon-60x60.png | Bin 0 -> 4648 bytes static/favicons/apple-icon-72x72.png | Bin 0 -> 5337 bytes static/favicons/apple-icon-76x76.png | Bin 0 -> 5686 bytes static/favicons/apple-icon-precomposed.png | Bin 0 -> 13375 bytes static/favicons/apple-icon.png | Bin 0 -> 13375 bytes static/favicons/browserconfig.xml | 11 + static/favicons/favicon-16x16.png | Bin 0 -> 1938 bytes static/favicons/favicon-32x32.png | Bin 0 -> 2910 bytes static/favicons/favicon-96x96.png | Bin 0 -> 7143 bytes static/favicons/favicon.ico | Bin 0 -> 1150 bytes static/favicons/manifest.json | 46 + static/favicons/ms-icon-144x144.png | Bin 0 -> 11059 bytes static/favicons/ms-icon-150x150.png | Bin 0 -> 11782 bytes static/favicons/ms-icon-310x310.png | Bin 0 -> 32665 bytes static/favicons/ms-icon-70x70.png | Bin 0 -> 5196 bytes static/safari-pinned-tab.svg | 10 + svelte.config.js | 11 + tsconfig.json | 14 + vite.config.ts | 7 + yarn.lock | 1243 ++ 137 files changed, 28585 insertions(+) create mode 100644 .dockerignore create mode 100644 .env.example create mode 100644 .gitea/workflows/deploy.yml create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 docker-compose.prod.yml create mode 100644 docker-compose.yml create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 scripts/generate-api-types.mjs create mode 100644 src/app.css create mode 100644 src/app.d.ts create mode 100644 src/app.html create mode 100644 src/hooks.server.ts create mode 100644 src/lib/block-layout.ts create mode 100644 src/lib/block-types.ts create mode 100644 src/lib/blog-utils.ts create mode 100644 src/lib/cms-api.generated.ts create mode 100644 src/lib/cms.ts create mode 100644 src/lib/components/Accordion.svelte create mode 100644 src/lib/components/Badge.svelte create mode 100644 src/lib/components/BlogOverview.svelte create mode 100644 src/lib/components/Card.svelte create mode 100644 src/lib/components/CmsImage.svelte create mode 100644 src/lib/components/ContentRows.svelte create mode 100644 src/lib/components/EventBadges.svelte create mode 100644 src/lib/components/EventMap.svelte create mode 100644 src/lib/components/Footer.svelte create mode 100644 src/lib/components/Header.svelte create mode 100644 src/lib/components/HeaderOverlay.svelte create mode 100644 src/lib/components/Pagination.svelte create mode 100644 src/lib/components/PostCard.svelte create mode 100644 src/lib/components/PostMeta.svelte create mode 100644 src/lib/components/RustyImage.svelte create mode 100644 src/lib/components/Search.svelte create mode 100644 src/lib/components/Tag.svelte create mode 100644 src/lib/components/Tags.svelte create mode 100644 src/lib/components/TopBanner.svelte create mode 100644 src/lib/components/TranslationProvider.svelte create mode 100644 src/lib/components/blocks/CalendarBlock.svelte create mode 100644 src/lib/components/blocks/HeadlineBlock.svelte create mode 100644 src/lib/components/blocks/HtmlBlock.svelte create mode 100644 src/lib/components/blocks/IframeBlock.svelte create mode 100644 src/lib/components/blocks/ImageBlock.svelte create mode 100644 src/lib/components/blocks/ImageGalleryBlock.svelte create mode 100644 src/lib/components/blocks/LinkListBlock.svelte create mode 100644 src/lib/components/blocks/MarkdownBlock.svelte create mode 100644 src/lib/components/blocks/OpnFormBlock.svelte create mode 100644 src/lib/components/blocks/OrganisationsBlock.svelte create mode 100644 src/lib/components/blocks/PostOverviewBlock.svelte create mode 100644 src/lib/components/blocks/QuoteBlock.svelte create mode 100644 src/lib/components/blocks/SearchableTextBlock.svelte create mode 100644 src/lib/components/blocks/YoutubeVideoBlock.svelte create mode 100644 src/lib/constants.ts create mode 100644 src/lib/iconify-offline.ts create mode 100644 src/lib/image-cache.server.ts create mode 100644 src/lib/overlay-store.ts create mode 100644 src/lib/rusty-image.ts create mode 100644 src/lib/transform-cache.ts create mode 100644 src/lib/translations.ts create mode 100644 src/lib/ui/Badge.svelte create mode 100644 src/lib/ui/Breadcrumbs.svelte create mode 100644 src/lib/ui/Button.svelte create mode 100644 src/lib/ui/Checkbox.svelte create mode 100644 src/lib/ui/Radio.svelte create mode 100644 src/lib/ui/Select.svelte create mode 100644 src/lib/ui/SidebarNav.svelte create mode 100644 src/lib/ui/Slider.svelte create mode 100644 src/lib/ui/TabBar.svelte create mode 100644 src/lib/ui/TextInput.svelte create mode 100644 src/lib/ui/Textarea.svelte create mode 100644 src/lib/ui/Toggle.svelte create mode 100644 src/lib/ui/Tooltip.svelte create mode 100644 src/lib/ui/index.ts create mode 100644 src/routes/+error.svelte create mode 100644 src/routes/+layout.server.ts create mode 100644 src/routes/+layout.svelte create mode 100644 src/routes/+page.server.ts create mode 100644 src/routes/+page.svelte create mode 100644 src/routes/[...slug]/+page.server.ts create mode 100644 src/routes/[...slug]/+page.svelte create mode 100644 src/routes/api/revalidate/+server.ts create mode 100644 src/routes/api/search-index/+server.ts create mode 100644 src/routes/api/transform/+server.ts create mode 100644 src/routes/blog/+page.server.ts create mode 100644 src/routes/blog/page/[page]/+page.server.ts create mode 100644 src/routes/blog/tag/[tag]/+page.server.ts create mode 100644 src/routes/cms-images/+server.ts create mode 100644 src/routes/p/[slug]/+page.server.ts create mode 100644 src/routes/post/[slug]/+page.server.ts create mode 100644 src/routes/post/[slug]/+page.svelte create mode 100644 src/routes/posts/+page.server.ts create mode 100644 src/routes/posts/+page.svelte create mode 100644 src/routes/posts/page/[page]/+page.server.ts create mode 100644 src/routes/posts/page/[page]/+page.svelte create mode 100644 src/routes/posts/rss.xml/+server.ts create mode 100644 src/routes/posts/tag/[tag]/+page.server.ts create mode 100644 src/routes/posts/tag/[tag]/+page.svelte create mode 100644 src/routes/posts/tag/[tag]/page/[page]/+page.server.ts create mode 100644 src/routes/posts/tag/[tag]/page/[page]/+page.svelte create mode 100644 src/routes/robots.txt/+server.ts create mode 100644 src/routes/sitemap.xml/+server.ts create mode 100644 static/apple-touch-icon.svg create mode 100644 static/favicon.ico create mode 100644 static/favicon.svg create mode 100644 static/favicons/android-icon-144x144.png create mode 100644 static/favicons/android-icon-192x192.png create mode 100644 static/favicons/android-icon-36x36.png create mode 100644 static/favicons/android-icon-48x48.png create mode 100644 static/favicons/android-icon-72x72.png create mode 100644 static/favicons/android-icon-96x96.png create mode 100644 static/favicons/apple-icon-114x114.png create mode 100644 static/favicons/apple-icon-120x120.png create mode 100644 static/favicons/apple-icon-144x144.png create mode 100644 static/favicons/apple-icon-152x152.png create mode 100644 static/favicons/apple-icon-180x180.png create mode 100644 static/favicons/apple-icon-57x57.png create mode 100644 static/favicons/apple-icon-60x60.png create mode 100644 static/favicons/apple-icon-72x72.png create mode 100644 static/favicons/apple-icon-76x76.png create mode 100644 static/favicons/apple-icon-precomposed.png create mode 100644 static/favicons/apple-icon.png create mode 100644 static/favicons/browserconfig.xml create mode 100644 static/favicons/favicon-16x16.png create mode 100644 static/favicons/favicon-32x32.png create mode 100644 static/favicons/favicon-96x96.png create mode 100644 static/favicons/favicon.ico create mode 100644 static/favicons/manifest.json create mode 100644 static/favicons/ms-icon-144x144.png create mode 100644 static/favicons/ms-icon-150x150.png create mode 100644 static/favicons/ms-icon-310x310.png create mode 100644 static/favicons/ms-icon-70x70.png create mode 100644 static/safari-pinned-tab.svg create mode 100644 svelte.config.js create mode 100644 tsconfig.json create mode 100644 vite.config.ts create mode 100644 yarn.lock diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d76f1c9 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +node_modules/ +build/ +.svelte-kit/ +.cache/ +.env +.env.* +*.log +*.local +.DS_Store diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..0e6e13b --- /dev/null +++ b/.env.example @@ -0,0 +1,26 @@ +PUBLIC_CMS_URL=http://localhost:3000 +PUBLIC_SITE_URL=https://www.windwiderstand.de +PUBLIC_SITE_NAME=Windwiderstand +PUBLIC_UMAMI_SCRIPT_URL= +PUBLIC_UMAMI_WEBSITE_ID= + +# analytics.pm86.de Site-ID (Script-URL ist hartcodiert auf analytics.pm86.de) +PUBLIC_ANALYTICS_PM86_SITE_ID= + +# Formbricks Feedback-Widget +PUBLIC_FORMBRICKS_APP_URL= +PUBLIC_FORMBRICKS_ENVIRONMENT_ID= + +# Persistenter Disk-Cache für /cms-images (Default: .cache/images) +# IMAGE_CACHE_DIR=.cache/images +# Optional: In-Memory-Einträge vor Disk-Lesen (Default 200) +# IMAGE_CACHE_MAX_MEMORY=200 + +# Optional: Legacy-Proxy /api/transform (In-Memory + optional Datei) +# TRANSFORM_CACHE_MAX_ENTRIES=100 +# TRANSFORM_CACHE_DIR=.cache/transform + +# Shared Secret für RustyCMS Webhook → POST /api/revalidate +# Gleicher Wert muss in der Webhook-URL als ?token=... hängen. +# Generieren: openssl rand -hex 32 +REVALIDATE_TOKEN= diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml new file mode 100644 index 0000000..b068e6d --- /dev/null +++ b/.gitea/workflows/deploy.yml @@ -0,0 +1,103 @@ +# Deploy windwiderstand SvelteKit auf Contabo bei Push auf main. +# +# Setup auf dem Server (einmalig): +# mkdir -p /opt/windwiderstand +# DNS: windwiderstand.de + www.windwiderstand.de A → 167.86.74.105 +# +# Gitea Secrets (Repo → Settings → Secrets): +# SSH_DEPLOY_KEY ~/.ssh/contabo_rsa (privat) +# REGISTRY_USER Gitea-Username +# REGISTRY_TOKEN Gitea Access Token (Scope: package) +# PUBLIC_CMS_URL https://cms.pm86.de +# PUBLIC_SITE_URL https://www.windwiderstand.de +# PUBLIC_SITE_NAME Windwiderstand +# ORIGIN https://www.windwiderstand.de +# REVALIDATE_TOKEN openssl rand -hex 32 +# PUBLIC_UMAMI_WEBSITE_ID (optional, sonst leer) +# PUBLIC_ANALYTICS_PM86_SITE_ID (optional, sonst leer) + +name: Deploy + +on: + push: + branches: [main] + +jobs: + verify: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: "22" + cache: npm + - name: Install deps + run: npm ci + - name: Typecheck + run: npx svelte-check --threshold error + + deploy: + needs: verify + runs-on: ubuntu-latest + env: + DEPLOY_HOST: root@167.86.74.105 + DEPLOY_DIR: /opt/windwiderstand + IMAGE: git.pm86.de/admin/windwiderstand:latest + steps: + - uses: actions/checkout@v4 + + - name: Build and push image + run: | + echo "${{ secrets.REGISTRY_TOKEN }}" | docker login git.pm86.de -u ${{ secrets.REGISTRY_USER }} --password-stdin + docker build -t $IMAGE . + docker push $IMAGE + + - name: Setup SSH + run: | + mkdir -p ~/.ssh + echo "${{ secrets.SSH_DEPLOY_KEY }}" > ~/.ssh/deploy_key + chmod 600 ~/.ssh/deploy_key + cat > ~/.ssh/config < $DEPLOY_DIR/.env" <> /opt/caddy/extra-config/Caddyfile' + ssh vserver "docker exec caddy caddy reload --config /extra-config/Caddyfile" + + - name: Cleanup + if: always() + run: rm -f ~/.ssh/deploy_key diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3b01d27 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +# Dependencies +node_modules/ + +# Build / SvelteKit +build/ +.svelte-kit/ +dist/ + +# Environment +.env +.env.* +!.env.example + +# Local / IDE +.cache/ +.history/ +.DS_Store + +# Logs +*.log +npm-debug.log* diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2f6c509 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,38 @@ +# ───────────────────────────────────────────── +# Stage 1: Build +# ───────────────────────────────────────────── +FROM node:22-alpine AS builder +WORKDIR /app + +# Erst nur package*.json – besseres Layer-Caching +COPY package*.json ./ +# postinstall versucht CMS-Types zu generieren (|| true → unkritisch ohne CMS) +RUN npm ci + +COPY . . +RUN npm run build + +# ───────────────────────────────────────────── +# Stage 2: Schlankes Production-Image +# ───────────────────────────────────────────── +FROM node:22-alpine AS runner +WORKDIR /app +ENV NODE_ENV=production + +# Nur Production-Deps, kein postinstall nötig +COPY package*.json ./ +RUN npm ci --omit=dev --ignore-scripts + +# Build-Artefakt aus Stage 1 +COPY --from=builder /app/build ./build + +# Non-root user +RUN addgroup -g 1001 -S nodejs \ + && adduser -S svelte -u 1001 -G nodejs \ + && chown -R svelte:nodejs /app +USER svelte + +EXPOSE 3001 +ENV PORT=3001 + +CMD ["node", "build"] diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..19414aa --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,20 @@ +services: + windwiderstand: + image: git.pm86.de/admin/windwiderstand:latest + container_name: windwiderstand + restart: unless-stopped + expose: + - "3001" + env_file: /opt/windwiderstand/.env + volumes: + - image-cache:/data/image-cache + networks: + - web + +volumes: + image-cache: + +networks: + web: + external: true + name: stacks_web diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..16c0ecc --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,17 @@ +services: + windwiderstand: + build: . + ports: + - "3001:3001" + environment: + - PUBLIC_CMS_URL=${PUBLIC_CMS_URL:-http://rustycms:3000} + - PUBLIC_SITE_URL=${PUBLIC_SITE_URL:-https://www.windwiderstand.de} + - PUBLIC_SITE_NAME=${PUBLIC_SITE_NAME:-Windwiderstand} + - ORIGIN=${ORIGIN:-https://www.windwiderstand.de} + - IMAGE_CACHE_DIR=${IMAGE_CACHE_DIR:-/app/.cache/images} + volumes: + - image-cache:/app/.cache/images + restart: unless-stopped + +volumes: + image-cache: diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..a964d3f --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2780 @@ +{ + "name": "windwiderstand", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "windwiderstand", + "version": "0.0.1", + "hasInstallScript": true, + "dependencies": { + "@fontsource-variable/lora": "^5.2.8", + "@fontsource-variable/rubik": "^5.2.8", + "@fontsource/inter": "^5.2.8", + "@iconify/svelte": "^5.2.1", + "marked": "^17.0.2" + }, + "devDependencies": { + "@iconify-json/mdi": "^1.2.3", + "@sveltejs/adapter-node": "^5.2.12", + "@sveltejs/kit": "^2.21.4", + "@sveltejs/vite-plugin-svelte": "^5.0.3", + "@tailwindcss/vite": "^4.1.18", + "@types/node": "^22.10.0", + "openapi-typescript": "^7.4.0", + "svelte": "^5.28.2", + "tailwindcss": "^4.1.18", + "typescript": "^5.9.3", + "vite": "^6.3.5" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@fontsource-variable/lora": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/@fontsource-variable/lora/-/lora-5.2.8.tgz", + "integrity": "sha512-cxjTJ9BbOWIzusewR4UMBLVePvTSWV6dtNaNsCkF/oKoyA68fJGWfaYCILOOP1BObE4dmjfZ3xo6m9hdHhtYhg==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@fontsource-variable/rubik": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/@fontsource-variable/rubik/-/rubik-5.2.8.tgz", + "integrity": "sha512-vGDExLzB4a2Fj9mca5LqNoA2ZKcU9o+x5FEBLte/nxYkCB9hOQwZS6ZlItUv+Ssn7YMzKauGuI/Po+YueFuZbg==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@fontsource/inter": { + "version": "5.2.8", + "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-5.2.8.tgz", + "integrity": "sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@iconify-json/mdi": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@iconify-json/mdi/-/mdi-1.2.3.tgz", + "integrity": "sha512-O3cLwbDOK7NNDf2ihaQOH5F9JglnulNDFV7WprU2dSoZu3h3cWH//h74uQAB87brHmvFVxIOkuBX2sZSzYhScg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@iconify/types": "*" + } + }, + "node_modules/@iconify/svelte": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@iconify/svelte/-/svelte-5.2.1.tgz", + "integrity": "sha512-zHmsIPmnIhGd5gc95bNN5FL+GifwMZv7M2rlZEpa7IXYGFJm/XGHdWf6PWQa6OBoC+R69WyiPO9NAj5wjfjbow==", + "license": "MIT", + "dependencies": { + "@iconify/types": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/cyberalien" + }, + "peerDependencies": { + "svelte": ">5.0.0" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "license": "MIT" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@redocly/ajv": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.11.2.tgz", + "integrity": "sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js-replace": "^1.0.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@redocly/config": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@redocly/config/-/config-0.22.0.tgz", + "integrity": "sha512-gAy93Ddo01Z3bHuVdPWfCwzgfaYgMdaZPcfL7JZ7hWJoK9V0lXDbigTWkhiPFAaLWzbOJ+kbUQG1+XwIm0KRGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@redocly/openapi-core": { + "version": "1.34.11", + "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.34.11.tgz", + "integrity": "sha512-V09ayfnb5GyysmvARbt+voFZAjGcf7hSYxOYxSkCc4fbH/DTfq5YWoec8cflvmHHqyIFbqvmGKmYFzqhr9zxDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@redocly/ajv": "8.11.2", + "@redocly/config": "0.22.0", + "colorette": "1.4.0", + "https-proxy-agent": "7.0.6", + "js-levenshtein": "1.1.6", + "js-yaml": "4.1.1", + "minimatch": "5.1.9", + "pluralize": "8.0.0", + "yaml-ast-parser": "0.0.43" + }, + "engines": { + "node": ">=18.17.0", + "npm": ">=9.5.0" + } + }, + "node_modules/@rollup/plugin-commonjs": { + "version": "29.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-29.0.2.tgz", + "integrity": "sha512-S/ggWH1LU7jTyi9DxZOKyxpVd4hF/OZ0JrEbeLjXk/DFXwRny0tjD2c992zOUYQobLrVkRVMDdmHP16HKP7GRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "fdir": "^6.2.0", + "is-reference": "1.2.1", + "magic-string": "^0.30.3", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=16.0.0 || 14 >= 14.17" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-json": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", + "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.1.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz", + "integrity": "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sveltejs/acorn-typescript": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.9.tgz", + "integrity": "sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA==", + "license": "MIT", + "peerDependencies": { + "acorn": "^8.9.0" + } + }, + "node_modules/@sveltejs/adapter-node": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-5.5.4.tgz", + "integrity": "sha512-45X92CXW+2J8ZUzPv3eLlKWEzINKiiGeFWTjyER4ZN4sGgNoaoeSkCY/QYNxHpPXy71QPsctwccBo9jJs0ySPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/plugin-commonjs": "^29.0.0", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-node-resolve": "^16.0.0", + "rollup": "^4.59.0" + }, + "peerDependencies": { + "@sveltejs/kit": "^2.4.0" + } + }, + "node_modules/@sveltejs/kit": { + "version": "2.55.0", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.55.0.tgz", + "integrity": "sha512-MdFRjevVxmAknf2NbaUkDF16jSIzXMWd4Nfah0Qp8TtQVoSp3bV4jKt8mX7z7qTUTWvgSaxtR0EG5WJf53gcuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@sveltejs/acorn-typescript": "^1.0.5", + "@types/cookie": "^0.6.0", + "acorn": "^8.14.1", + "cookie": "^0.6.0", + "devalue": "^5.6.4", + "esm-env": "^1.2.2", + "kleur": "^4.1.5", + "magic-string": "^0.30.5", + "mrmime": "^2.0.0", + "set-cookie-parser": "^3.0.0", + "sirv": "^3.0.0" + }, + "bin": { + "svelte-kit": "svelte-kit.js" + }, + "engines": { + "node": ">=18.13" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0", + "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "typescript": "^5.3.3", + "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@sveltejs/vite-plugin-svelte": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-5.1.1.tgz", + "integrity": "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", + "debug": "^4.4.1", + "deepmerge": "^4.3.1", + "kleur": "^4.1.5", + "magic-string": "^0.30.17", + "vitefu": "^1.0.6" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22" + }, + "peerDependencies": { + "svelte": "^5.0.0", + "vite": "^6.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte-inspector": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-4.0.1.tgz", + "integrity": "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.7" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "svelte": "^5.0.0", + "vite": "^6.0.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.1.tgz", + "integrity": "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.19.0", + "jiti": "^2.6.1", + "lightningcss": "1.31.1", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.2.1" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.1.tgz", + "integrity": "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.2.1", + "@tailwindcss/oxide-darwin-arm64": "4.2.1", + "@tailwindcss/oxide-darwin-x64": "4.2.1", + "@tailwindcss/oxide-freebsd-x64": "4.2.1", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1", + "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1", + "@tailwindcss/oxide-linux-arm64-musl": "4.2.1", + "@tailwindcss/oxide-linux-x64-gnu": "4.2.1", + "@tailwindcss/oxide-linux-x64-musl": "4.2.1", + "@tailwindcss/oxide-wasm32-wasi": "4.2.1", + "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1", + "@tailwindcss/oxide-win32-x64-msvc": "4.2.1" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.1.tgz", + "integrity": "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.1.tgz", + "integrity": "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.1.tgz", + "integrity": "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.1.tgz", + "integrity": "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.1.tgz", + "integrity": "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.1.tgz", + "integrity": "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.1.tgz", + "integrity": "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.1.tgz", + "integrity": "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.1.tgz", + "integrity": "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.1.tgz", + "integrity": "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.8.1", + "@emnapi/runtime": "^1.8.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.1", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.1.tgz", + "integrity": "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.1.tgz", + "integrity": "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.1.tgz", + "integrity": "sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.2.1", + "@tailwindcss/oxide": "4.2.1", + "tailwindcss": "4.2.1" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.19.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.15.tgz", + "integrity": "sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/types": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.1.tgz", + "integrity": "sha512-S29BOBPJSFUiblEl6RzPPjJt6w25A6XsBqRVDt53tA/tlL8q7ceQNZHTjPeONt/3S7KRI4quk+yP9jK2WjBiPQ==", + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.1.tgz", + "integrity": "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/change-case": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", + "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/devalue": { + "version": "5.6.4", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.4.tgz", + "integrity": "sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA==", + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz", + "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/esm-env": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", + "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", + "license": "MIT" + }, + "node_modules/esrap": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.4.tgz", + "integrity": "sha512-suICpxAmZ9A8bzJjEl/+rLJiDKC0X4gYWUxT6URAWBLvlXmtbZd5ySMu/N2ZGEtMCAmflUDPSehrP9BQcsGcSg==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15", + "@typescript-eslint/types": "^8.2.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/index-to-position": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz", + "integrity": "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lightningcss": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", + "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.31.1", + "lightningcss-darwin-arm64": "1.31.1", + "lightningcss-darwin-x64": "1.31.1", + "lightningcss-freebsd-x64": "1.31.1", + "lightningcss-linux-arm-gnueabihf": "1.31.1", + "lightningcss-linux-arm64-gnu": "1.31.1", + "lightningcss-linux-arm64-musl": "1.31.1", + "lightningcss-linux-x64-gnu": "1.31.1", + "lightningcss-linux-x64-musl": "1.31.1", + "lightningcss-win32-arm64-msvc": "1.31.1", + "lightningcss-win32-x64-msvc": "1.31.1" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz", + "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz", + "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz", + "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz", + "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz", + "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz", + "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz", + "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz", + "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", + "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz", + "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz", + "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/marked": { + "version": "17.0.4", + "resolved": "https://registry.npmjs.org/marked/-/marked-17.0.4.tgz", + "integrity": "sha512-NOmVMM+KAokHMvjWmC5N/ZOvgmSWuqJB8FoYI019j4ogb/PeRMKoKIjReZ2w3376kkA8dSJIP8uD993Kxc0iRQ==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/openapi-typescript": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-7.13.0.tgz", + "integrity": "sha512-EFP392gcqXS7ntPvbhBzbF8TyBA+baIYEm791Hy5YkjDYKTnk/Tn5OQeKm5BIZvJihpp8Zzr4hzx0Irde1LNGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@redocly/openapi-core": "^1.34.6", + "ansi-colors": "^4.1.3", + "change-case": "^5.4.4", + "parse-json": "^8.3.0", + "supports-color": "^10.2.2", + "yargs-parser": "^21.1.1" + }, + "bin": { + "openapi-typescript": "bin/cli.js" + }, + "peerDependencies": { + "typescript": "^5.x" + } + }, + "node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/set-cookie-parser": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.0.1.tgz", + "integrity": "sha512-n7Z7dXZhJbwuAHhNzkTti6Aw9QDDjZtm3JTpTGATIdNzdQz5GuFs22w90BcvF4INfnrL5xrX3oGsuqO5Dx3A1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", + "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svelte": { + "version": "5.53.12", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.53.12.tgz", + "integrity": "sha512-4x/uk4rQe/d7RhfvS8wemTfNjQ0bJbKvamIzRBfTe2eHHjzBZ7PZicUQrC2ryj83xxEacfA1zHKd1ephD1tAxA==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "@jridgewell/sourcemap-codec": "^1.5.0", + "@sveltejs/acorn-typescript": "^1.0.5", + "@types/estree": "^1.0.5", + "@types/trusted-types": "^2.0.7", + "acorn": "^8.12.1", + "aria-query": "5.3.1", + "axobject-query": "^4.1.0", + "clsx": "^2.1.1", + "devalue": "^5.6.4", + "esm-env": "^1.2.1", + "esrap": "^2.2.2", + "is-reference": "^3.0.3", + "locate-character": "^3.0.0", + "magic-string": "^0.30.11", + "zimmerframe": "^1.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/svelte/node_modules/is-reference": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", + "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.6" + } + }, + "node_modules/tailwindcss": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz", + "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/uri-js-replace": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uri-js-replace/-/uri-js-replace-1.0.1.tgz", + "integrity": "sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", + "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitefu": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.2.tgz", + "integrity": "sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw==", + "dev": true, + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*", + "tests/projects/workspace/packages/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/yaml-ast-parser": { + "version": "0.0.43", + "resolved": "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz", + "integrity": "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/zimmerframe": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz", + "integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==", + "license": "MIT" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..a530305 --- /dev/null +++ b/package.json @@ -0,0 +1,34 @@ +{ + "name": "windwiderstand", + "version": "0.0.1", + "private": true, + "scripts": { + "dev": "vite dev", + "build": "vite build", + "preview": "vite preview", + "start": "node build", + "generate:api-types": "node scripts/generate-api-types.mjs", + "postinstall": "node scripts/generate-api-types.mjs || true" + }, + "devDependencies": { + "@iconify-json/mdi": "^1.2.3", + "@sveltejs/adapter-node": "^5.2.12", + "@sveltejs/kit": "^2.21.4", + "@sveltejs/vite-plugin-svelte": "^5.0.3", + "@tailwindcss/vite": "^4.1.18", + "@types/node": "^22.10.0", + "openapi-typescript": "^7.4.0", + "svelte": "^5.28.2", + "tailwindcss": "^4.1.18", + "typescript": "^5.9.3", + "vite": "^6.3.5" + }, + "dependencies": { + "@fontsource-variable/lora": "^5.2.8", + "@fontsource-variable/rubik": "^5.2.8", + "@fontsource/inter": "^5.2.8", + "@iconify/svelte": "^5.2.1", + "marked": "^17.0.2" + }, + "type": "module" +} diff --git a/scripts/generate-api-types.mjs b/scripts/generate-api-types.mjs new file mode 100644 index 0000000..2f968b4 --- /dev/null +++ b/scripts/generate-api-types.mjs @@ -0,0 +1,46 @@ +#!/usr/bin/env node +/** + * Generiert TypeScript-Typen aus der RustyCMS OpenAPI-Spec. + * Verwendet PUBLIC_CMS_URL aus .env (Default: http://localhost:3000). + * RustyCMS muss laufen: cd ../rustycms && cargo run + */ +import { execSync } from "node:child_process"; +import { readFileSync, existsSync } from "node:fs"; +import { fileURLToPath } from "node:url"; +import { dirname, join } from "node:path"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const root = join(__dirname, ".."); +const envPath = join(root, ".env"); + +if (existsSync(envPath)) { + const lines = readFileSync(envPath, "utf8").split("\n"); + for (const line of lines) { + const trimmed = line.trim(); + if (trimmed && !trimmed.startsWith("#") && trimmed.includes("=")) { + const idx = trimmed.indexOf("="); + const key = trimmed.slice(0, idx).trim(); + const value = trimmed.slice(idx + 1).trim().replace(/^["']|["']$/g, ""); + if (key && !process.env[key]) process.env[key] = value; + } + } +} + +const base = (process.env.PUBLIC_CMS_URL || "http://localhost:3000").replace(/\/$/, ""); +const specUrl = `${base}/api-docs/openapi.json`; +const outFile = join(root, "src/lib/cms-api.generated.ts"); + +console.log("Fetching OpenAPI spec from", specUrl); +console.log("Writing types to", outFile); + +try { + execSync(`npx openapi-typescript "${specUrl}" -o "${outFile}"`, { + stdio: "inherit", + cwd: root, + }); + console.log("Done. Types are in src/lib/cms-api.generated.ts"); +} catch (err) { + console.error("\nFehler: OpenAPI-Spec konnte nicht geladen werden."); + console.error("Ist RustyCMS gestartet? z.B.: cd ../rustycms && cargo run"); + process.exit(1); +} diff --git a/src/app.css b/src/app.css new file mode 100644 index 0000000..1868162 --- /dev/null +++ b/src/app.css @@ -0,0 +1,491 @@ +/* Windwiderstand Design System – Fonts */ +@import "@fontsource/inter/latin-300.css"; +@import "@fontsource/inter/latin-400.css"; +@import "@fontsource/inter/latin-500.css"; +@import "@fontsource/inter/latin-600.css"; +@import "@fontsource/inter/latin-700.css"; +@import "@fontsource/inter/latin-800.css"; +@import "@fontsource/inter/latin-900.css"; +@import "@fontsource-variable/lora"; + +@import "tailwindcss"; + +/* ========================================================================== + Design Tokens – Windwiderstand (01-colors, 02-typography, 06-tokens.json) + ========================================================================== */ + +@theme { + /* Palette: Wald (Primary) */ + --color-wald-50: #f0f5f1; + --color-wald-100: #d9e8dc; + --color-wald-200: #b3d1b9; + --color-wald-300: #7fb58a; + --color-wald-400: #4a9960; + --color-wald-500: #2d7a45; + --color-wald-600: #236335; + --color-wald-700: #1a4d28; + --color-wald-800: #12361c; + --color-wald-900: #0a2011; + + /* Palette: Erde (Secondary) */ + --color-erde-50: #faf6f1; + --color-erde-100: #f0e6d6; + --color-erde-200: #e0ccad; + --color-erde-300: #c9a87a; + --color-erde-400: #b08a52; + --color-erde-500: #8b6d3f; + --color-erde-600: #6e5530; + --color-erde-700: #524023; + --color-erde-800: #372b18; + --color-erde-900: #1c160c; + + /* Palette: Himmel (Accent / Links) */ + --color-himmel-50: #f2f5f7; + --color-himmel-100: #dce4ea; + --color-himmel-200: #b8c9d4; + --color-himmel-300: #8aaabb; + --color-himmel-400: #5e8ba2; + --color-himmel-500: #436e85; + --color-himmel-600: #34576a; + --color-himmel-700: #264150; + --color-himmel-800: #1a2c36; + --color-himmel-900: #0e181e; + + /* Palette: Stein (Neutrals) */ + --color-stein-0: #ffffff; + --color-stein-50: #f7f8f7; + --color-stein-100: #eceeed; + --color-stein-200: #d5d8d6; + --color-stein-300: #b0b5b2; + --color-stein-400: #868c89; + --color-stein-500: #636966; + --color-stein-600: #4a4f4c; + --color-stein-700: #333735; + --color-stein-800: #1f2221; + --color-stein-900: #0f1110; + + /* Semantic: Success, Warning, Error, Info */ + --color-success: var(--color-wald-500); + --color-success-subtle: var(--color-wald-50); + --color-warning: #a6780a; + --color-warning-subtle: #fdf8ec; + --color-error: #b53629; + --color-error-subtle: #fdf2f1; + --color-info: var(--color-himmel-500); + --color-info-subtle: var(--color-himmel-50); + + /* Button (Primary = Wald) – für @apply bg-btn-bg, text-btn-txt, bg-btn-hover-bg */ + --color-btn-bg: var(--color-wald-500); + --color-btn-hover-bg: var(--color-wald-600); + --color-btn-txt: #fff; + + /* Link (Himmel) – für @apply text-link */ + --color-link: var(--color-himmel-500); +} + +:root { + /* Typography – Inter (primary), Lora (quotes) */ + --font-body: Inter, ui-sans-serif, system-ui, -apple-system, sans-serif; + --font-secondary: "Lora Variable", Lora, Georgia, "Times New Roman", serif; + + /* Semantic (nur Light Theme) */ + --bg-primary: #ffffff; + --bg-secondary: #f7f8f7; + --bg-tertiary: #eceeed; + --bg-elevated: #ffffff; + --text-primary: #1f2221; + --text-secondary: #636966; + --text-tertiary: #868c89; + --border-default: #d5d8d6; + --border-strong: #b0b5b2; + --accent: #2d7a45; + --accent-hover: #236335; + --link: #436e85; + + /* Legacy / App-Aliase (weiterverwendet) */ + --color-font: var(--text-primary); + --color-headings: var(--text-primary); + --color-font-highlight: var(--color-error); + --color-navigation: var(--color-stein-0); + --background-color: var(--bg-primary); + --color-text: var(--text-primary); + --color-link: var(--link); + --color-btn-bg: var(--accent); + --color-btn-hover-bg: var(--accent-hover); + --color-btn-txt: #fff; + /* Breakout-Bereich: Verlauf Wald-50 → Wald-100 */ + --color-container-breakout: linear-gradient( + to bottom, + white, + var(--color-wald-50) + ); + + font-family: var(--font-body); + font-size: 1.125rem; /* 18px – Body Large laut Design System */ + line-height: 1.556; + color: var(--color-font); +} + +html { + background: var(--background-color); +} + +main { + background: var(--bg-primary); +} + +/* ========================================================================== + Typography – Type Scale (02-typography.md) + Erlaubte Gewichte: 300, 400, 500, 600, 700. Inter primary, Lora nur Zitate. + ========================================================================== */ + +h1, +h2, +h3, +h4 { + color: var(--color-headings); +} + +/* Mobile first, dann Tablet (768px), Desktop (1024px) */ +h1 { + font-size: 1.75rem; + line-height: 2.125rem; + font-weight: 700; + letter-spacing: -0.015em; +} + +h2 { + font-size: 1.375rem; + line-height: 1.75rem; + font-weight: 700; + letter-spacing: -0.01em; +} + +h3 { + font-size: 1.25rem; + line-height: 1.625rem; + font-weight: 600; + letter-spacing: -0.005em; +} + +h4 { + font-size: 1.125rem; + line-height: 1.5rem; + font-weight: 600; +} + +@media (min-width: 768px) { + h1 { + font-size: 2.125rem; + line-height: 2.625rem; + } + h2 { + font-size: 1.5rem; + line-height: 2rem; + } + h3 { + font-size: 1.375rem; + line-height: 1.875rem; + } + h4 { + font-size: 1.125rem; + line-height: 1.625rem; + } +} + +@media (min-width: 1024px) { + h1 { + font-size: 2.5rem; + line-height: 3rem; + } + h2 { + font-size: 1.75rem; + line-height: 2.25rem; + } + h3 { + font-size: 1.5rem; + line-height: 2rem; + } +} + +/* Page-Titel (wie www.windwiderstand.de) */ +.pageTitle h1 { + font-size: 1.5rem; + line-height: 2rem; + font-weight: 700; + margin-bottom: 0.5rem; +} + +.pageTitle h2 { + font-size: 1rem; + line-height: 1.5rem; + font-weight: 500; + text-transform: none; + letter-spacing: 0; +} + +.pageTitle h1, +.pageTitle h2 { + text-wrap: balance; + word-break: break-word; + overflow-wrap: break-word; +} + +.pageTitle strong { + font-weight: 700; +} + +@media (min-width: 768px) { + .pageTitle h1 { + font-size: 2.25rem; + line-height: 2.5rem; + } + .pageTitle h2 { + font-size: 1.5rem; + line-height: 2rem; + padding-left: 0.25rem; + } +} + +@media (min-width: 1024px) { + .pageTitle h1 { + font-size: 3.75rem; + line-height: 1.14; + font-weight: 700; + letter-spacing: -0.02em; + } + .pageTitle h2 { + font-size: 1.875rem; + line-height: 2.25rem; + padding-left: 0.25rem; + } +} + +/* Content-Links: Himmel (Design System – Links) */ +main a:not(.no-underline) { + color: var(--color-link); + text-decoration: underline; +} + +main a:not(.no-underline):hover { + color: var(--color-himmel-600); +} + +/* Lange URLs umbrechen, damit sie nicht über den Bildschirmrand ragen */ +main a, +.markdown a { + overflow-wrap: break-word; + word-break: break-all; +} + +main strong { + font-weight: 600; +} + +main ul { + margin-left: 1em; + margin-bottom: 1em; +} + +main ul li { + list-style: disc; +} + +main ol { + margin-left: 1.1em; + margin-bottom: 1em; +} + +main ol li { + list-style-type: decimal; +} + +/* Buttons – Wald (Primary) */ +.btn-primary { + @apply inline-block no-underline transition-colors duration-200 font-light px-4 py-2 rounded-md shadow-sm bg-btn-bg text-btn-txt; +} + +.btn-primary:hover { + @apply bg-btn-hover-bg; +} + +/* Content-Blöcke */ +.content p { + @apply mb-4; +} + +.content h1, +.content h2, +.content h3, +.content h4 { + @apply mb-2; +} + +/* Markdown: Abstände, Listen, Bilder, Tabellen (Stein-Palette) */ +.markdown { + @apply min-w-0 overflow-x-auto; +} + +.markdown h1, +.markdown h2, +.markdown h3, +.markdown h4, +.markdown hr { + @apply mt-4 mb-3; +} + +.markdown li, +.markdown li p { + @apply mt-0 mb-0; +} + +.markdown p { + @apply mb-4; +} + +.markdown ul, +.markdown ol { + @apply mt-0 mb-4; +} + +.markdown li ul, +.markdown li ol { + @apply mb-0; +} + +/* Markdown-Bilder: /cms-images-Transform, max-height begrenzt Höhe; Link öffnet Bild in neuem Tab */ +.markdown img { + @apply max-w-full w-full my-2 border border-stein-200 rounded-md bg-stein-200 shadow-sm inline-block; + max-height: 30vh; +} + +.markdown .markdown-image-link { + @apply inline-block; +} + +.markdown table { + @apply w-full min-w-max border-collapse text-left text-sm mb-4; +} + +.markdown thead { + @apply bg-stein-100; +} + +.markdown th { + @apply px-3 py-2 font-medium border border-stein-200; +} + +.markdown td { + @apply px-3 py-2 border border-stein-200; +} + +.markdown tbody tr:nth-child(even) { + @apply bg-stein-50; +} + +.markdown tbody tr:hover { + @apply bg-stein-100; +} + +.markdown table a { + @apply text-link underline underline-offset-2 break-all; +} + +.markdown table a:hover { + @apply text-himmel-600; +} + +/* Code: Inline und Block (pre/code) – lesbare Größe, Stein-Palette */ +main code, +.content code, +.markdown code { + @apply font-mono bg-stein-100 text-stein-800 border border-stein-200; + @apply text-sm px-1.5 py-0.5; +} + +main pre, +.content pre, +.markdown pre { + @apply mt-3 mb-4 overflow-x-auto rounded-md border border-stein-200 bg-stein-100 px-4 py-3 text-stein-800 leading-normal; +} + +main pre code, +.content pre code, +.markdown pre code { + @apply border-0 bg-transparent p-0 text-inherit; +} + +/* Container */ +.container-custom { + @apply w-full mx-auto px-4 md:px-6; +} + +@media (min-width: 768px) { + .container-custom { + max-width: 768px; + } +} + +@media (min-width: 1024px) { + .container-custom { + max-width: 1024px; + } +} + +@media (min-width: 1280px) { + .container-custom { + max-width: 1280px; + } +} + +/* Zitate: Lora (Design System – nur für Zitate) */ +[data-block-type="quote"] blockquote, +[data-block-type="quote"] blockquote p, +[data-block-type="quote"] blockquote cite { + font-family: var(--font-secondary); +} + +.content-row + .content-row { + margin-top: 1.5rem; +} + +/* Footer */ +footer a, +.content-footer a { + color: var(--color-link); +} + +footer a:hover, +.content-footer a:hover { + color: var(--color-himmel-600); +} + +.container-breakout { + margin-left: calc(50% - 50vw + 0.01rem); + margin-right: calc(50% - 50vw + 0.01rem); + background: var(--color-container-breakout); +} + +/* Kalender: Container Query – links Kalender, rechts Eventblock ab ~500px Containerbreite */ +.calendar-block { + container-type: inline-size; + container-name: calendar; +} +@container calendar (min-width: 600px) { + .calendar-block .calendar-grid-wrapper { + grid-template-columns: auto 1fr; + } + .calendar-block .calendar-column { + min-width: 300px; + max-width: 450px; + } + .calendar-block .calendar-events-wrapper { + position: relative; + } + .calendar-block .calendar-events-panel { + position: absolute; + inset: 0; + border-top: none; + border-left: 1px solid var(--color-stein-200); + } +} diff --git a/src/app.d.ts b/src/app.d.ts new file mode 100644 index 0000000..1fab0c3 --- /dev/null +++ b/src/app.d.ts @@ -0,0 +1,8 @@ +declare global { + namespace App { + interface Locals { + translations: Record; + } + } +} +export {}; diff --git a/src/app.html b/src/app.html new file mode 100644 index 0000000..4705f0d --- /dev/null +++ b/src/app.html @@ -0,0 +1,12 @@ + + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ + diff --git a/src/hooks.server.ts b/src/hooks.server.ts new file mode 100644 index 0000000..3530e45 --- /dev/null +++ b/src/hooks.server.ts @@ -0,0 +1,53 @@ +import { getTranslationBundleBySlug } from '$lib/cms'; +import { TRANSLATION_BUNDLE_SLUG } from '$lib/constants'; +import type { Handle } from '@sveltejs/kit'; + +/** + * Page-Routen: kurze Edge-Cache + SWR. Webhook purged App-Cache, + * Edge läuft via stale-while-revalidate auf den warmen App-Cache. + */ +const PAGE_CACHE_CONTROL = + 'public, max-age=0, s-maxage=30, stale-while-revalidate=300'; + +function isCacheablePath(pathname: string): boolean { + if (pathname.startsWith('/api/')) return false; + if (pathname.startsWith('/cms-images/')) return false; + if (pathname.startsWith('/_app/')) return false; + return true; +} + +export const handle: Handle = async ({ event, resolve }) => { + try { + const bundle = await getTranslationBundleBySlug(TRANSLATION_BUNDLE_SLUG, { locale: 'de' }); + if (bundle?.strings && typeof bundle.strings === 'object') { + const normalized: Record = {}; + for (const [key, val] of Object.entries(bundle.strings)) { + const v = val as unknown; + const str = + typeof v === 'string' + ? v + : typeof v === 'object' && v !== null && 'value' in v + ? (v as { value?: unknown }).value + : (v as { text?: unknown })?.text ?? (v as { label?: unknown })?.label; + if (typeof str === 'string') normalized[key] = str; + } + event.locals.translations = normalized; + } else { + event.locals.translations = {}; + } + } catch { + event.locals.translations = {}; + } + + const response = await resolve(event); + + if ( + event.request.method === 'GET' && + isCacheablePath(event.url.pathname) && + !response.headers.has('cache-control') + ) { + response.headers.set('cache-control', PAGE_CACHE_CONTROL); + } + + return response; +}; diff --git a/src/lib/block-layout.ts b/src/lib/block-layout.ts new file mode 100644 index 0000000..e497afc --- /dev/null +++ b/src/lib/block-layout.ts @@ -0,0 +1,163 @@ +/** + * Layout für Content-Blöcke (z. B. Markdown): Grid-Spalten (1–12) und Abstand. + * Entspricht component_layout im CMS (desktop/tablet/mobile = Breite in 12tel, spaceBottom = rem). + */ + +export type BlockLayout = { + /** Breite auf Desktop (1–12), z. B. "8" = 8/12. */ + desktop?: + | "1" + | "2" + | "3" + | "4" + | "5" + | "6" + | "7" + | "8" + | "9" + | "10" + | "11" + | "12"; + /** Breite auf Tablet (1–12). */ + tablet?: + | "1" + | "2" + | "3" + | "4" + | "5" + | "6" + | "7" + | "8" + | "9" + | "10" + | "11" + | "12"; + /** Breite auf Mobile (1–12), Default 12. */ + mobile?: + | "1" + | "2" + | "3" + | "4" + | "5" + | "6" + | "7" + | "8" + | "9" + | "10" + | "11" + | "12"; + /** Abstand nach unten (rem): 0, 0.5, 1, 1.5, 2. */ + spaceBottom?: 0 | 0.5 | 1 | 1.5 | 2; + /** true = Block fullwidth aus dem Grid ausbrechen (viewport-breit). */ + breakout?: boolean; +}; + +const COL_SPAN: Record = { + "1": "col-span-1", + "2": "col-span-2", + "3": "col-span-3", + "4": "col-span-4", + "5": "col-span-5", + "6": "col-span-6", + "7": "col-span-7", + "8": "col-span-8", + "9": "col-span-9", + "10": "col-span-10", + "11": "col-span-11", + "12": "col-span-12", +}; + +const MD_COL_SPAN: Record = { + "1": "md:col-span-1", + "2": "md:col-span-2", + "3": "md:col-span-3", + "4": "md:col-span-4", + "5": "md:col-span-5", + "6": "md:col-span-6", + "7": "md:col-span-7", + "8": "md:col-span-8", + "9": "md:col-span-9", + "10": "md:col-span-10", + "11": "md:col-span-11", + "12": "md:col-span-12", +}; + +const LG_COL_SPAN: Record = { + "1": "lg:col-span-1", + "2": "lg:col-span-2", + "3": "lg:col-span-3", + "4": "lg:col-span-4", + "5": "lg:col-span-5", + "6": "lg:col-span-6", + "7": "lg:col-span-7", + "8": "lg:col-span-8", + "9": "lg:col-span-9", + "10": "lg:col-span-10", + "11": "lg:col-span-11", + "12": "lg:col-span-12", +}; + +const SPACE_BOTTOM: Record = { + 0: "mb-0", + 0.5: "mb-2", // 0.5rem + 1: "mb-4", // 1rem + 1.5: "mb-6", // 1.5rem + 2: "mb-8", // 2rem +}; + +/** + * Gibt Tailwind-Klassen für das Block-Layout zurück (12-Spalten-Grid + Abstand). + * Parent muss grid grid-cols-12 haben. + */ +/** + * Gibt Tailwind-Klassen für den Block-Inhalt zurück. + * Bei breakout: true nur w-full + Abstand (Spalten/Wrapper kommen von außen). + */ +export function getBlockLayoutClasses( + layout: BlockLayout | undefined | null, +): string { + if (!layout || typeof layout !== "object") { + return "col-span-12 mb-4"; + } + const breakout = layout.breakout === true; + const sb = + typeof layout.spaceBottom === "number" + ? layout.spaceBottom + : Number(layout.spaceBottom); + const spaceClass = SPACE_BOTTOM[sb as keyof typeof SPACE_BOTTOM] ?? "mb-4"; + + if (breakout) { + return "w-full"; + } + + const mobile = String(layout.mobile ?? "12"); + const tablet = layout.tablet != null ? String(layout.tablet) : undefined; + const desktop = layout.desktop != null ? String(layout.desktop) : undefined; + + const parts: string[] = [ + COL_SPAN[mobile] ?? "col-span-12", + tablet ? (MD_COL_SPAN[tablet] ?? "") : "", + desktop ? (LG_COL_SPAN[desktop] ?? "") : "", + spaceClass, + ]; + return parts.filter(Boolean).join(" "); +} + +/** Tailwind-Klasse für spaceBottom (z. B. am Breakout-Wrapper). */ +export function getSpaceBottomClass( + layout: BlockLayout | undefined | null, +): string { + if (!layout || typeof layout !== "object") return "mb-4"; + const sb = + typeof layout.spaceBottom === "number" + ? layout.spaceBottom + : Number(layout.spaceBottom); + return SPACE_BOTTOM[sb as keyof typeof SPACE_BOTTOM] ?? "mb-4"; +} + +/** Prüft, ob das Layout breakout (fullwidth) haben soll. */ +export function isBlockLayoutBreakout( + layout: BlockLayout | undefined | null, +): boolean { + return !!(layout && typeof layout === "object" && layout.breakout === true); +} diff --git a/src/lib/block-types.ts b/src/lib/block-types.ts new file mode 100644 index 0000000..0845fca --- /dev/null +++ b/src/lib/block-types.ts @@ -0,0 +1,252 @@ +/** + * Gemeinsame Typen für Content-Blöcke (Rows, Markdown, …). + * Wird von SvelteKit-Seiten und Svelte-Komponenten genutzt. + * Kalender-Typen basieren auf der OpenAPI-Spec (cms-api.generated). + */ + +import type { BlockLayout } from "./block-layout"; +import type { components } from "./cms-api.generated"; + +/** Aufgelöster Block vom CMS (mit _type, _slug + typ-spezifische Felder). */ +export type ResolvedBlock = { + _type?: string; + _slug?: string; + [key: string]: unknown; +}; + +/** Gemeinsames Row-Layout (page, post, footer erben content_layout). */ +export interface RowContentLayout { + row1Content?: unknown[]; + row1JustifyContent?: string; + row1AlignItems?: string; + row2Content?: unknown[]; + row2JustifyContent?: string; + row2AlignItems?: string; + row3Content?: unknown[]; + row3JustifyContent?: string; + row3AlignItems?: string; +} + +/** Resolved Markdown-Block vom CMS (_type: "markdown"). resolvedContent = HTML mit transformierten Bildern (von resolveContentImages). */ +export interface MarkdownBlockData { + _type?: "markdown"; + _slug?: string; + name?: string; + content?: string; + /** Gesetzt von resolveContentImages: HTML (Bilder transformiert, in Links eingewickelt). */ + resolvedContent?: string; + alignment?: "left" | "center" | "right"; + layout?: BlockLayout; +} + +/** Headline (_type: "headline"). */ +export interface HeadlineBlockData { + _type?: "headline"; + _slug?: string; + tag?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6"; + text?: string; + align?: "left" | "center" | "right"; + layout?: BlockLayout; +} + +/** HTML (_type: "html"). */ +export interface HtmlBlockData { + _type?: "html"; + _slug?: string; + html?: string; + layout?: BlockLayout; +} + +/** Iframe (_type: "iframe"). */ +export interface IframeBlockData { + _type?: "iframe"; + _slug?: string; + iframe?: string; + content?: string; + layout?: BlockLayout; +} + +/** Image (_type: "image"). image oder img: Slug, URL-String oder aufgelöstes Objekt (src/description oder file.url). */ +export interface ImageBlockData { + _type?: "image"; + _slug?: string; + image?: + | string + | { + _type?: "img"; + _slug?: string; + src?: string; + description?: string; + file?: { url?: string }; + title?: string; + }; + /** Alternative zu image (manche CMS-Responses liefern img). */ + img?: + | string + | { + _type?: "img"; + _slug?: string; + src?: string; + description?: string; + file?: { url?: string }; + title?: string; + }; + /** Nach resolveContentImages: Proxy-URL zum transformierten Bild. */ + resolvedImageSrc?: string; + caption?: string; + aspectRatio?: number; + layout?: BlockLayout; +} + +/** Eintrag in einer image_gallery (img mit src/description). */ +export interface ImageGalleryImage { + _type?: "img"; + _slug?: string; + src?: string; + description?: string; + file?: { url?: string }; + /** Nach resolveContentImages: Proxy-URL zum transformierten Bild (16:9). */ + resolvedSrc?: string; +} + +/** Bildergalerie (_type: "image_gallery"). images: Array von img-Objekten (src, description). */ +export interface ImageGalleryBlockData { + _type?: "image_gallery"; + _slug?: string; + /** Optionaler Einleitungstext (Markdown). */ + description?: string; + images?: ImageGalleryImage[]; + layout?: BlockLayout; +} + +/** YouTube-Video (_type: "youtube_video"). */ +export interface YoutubeVideoBlockData { + _type?: "youtube_video"; + _slug?: string; + youtubeId?: string; + title?: string; + description?: string; + params?: string; + layout?: BlockLayout; +} + +/** Zitat (_type: "quote"). */ +export interface QuoteBlockData { + _type?: "quote"; + _slug?: string; + quote?: string; + author?: string; + variant?: "left" | "right"; + layout?: BlockLayout; +} + +/** Link-Liste (_type: "link_list"). links können Slugs oder aufgelöste link-Objekte sein. */ +export interface LinkListBlockData { + _type?: "link_list"; + _slug?: string; + headline?: string; + links?: Array; + layout?: BlockLayout; +} + +/** Post-Übersicht (_type: "post_overview"). Nach resolvePostOverviewBlocks: postsResolved gesetzt. */ +export interface PostOverviewBlockData { + _type?: "post_overview"; + _slug?: string; + headline?: string; + /** Einleitungstext (Markdown). */ + text?: string; + /** true = alle Posts laden; false = posts (Slugs/Objekte) aus dem Block nutzen. */ + allPosts?: boolean; + /** Nur wenn allPosts false: feste Post-Liste (Slugs oder aufgelöste Einträge). */ + posts?: unknown[]; + /** Tag-Slugs, nach denen gefiltert wird (nur bei allPosts true). */ + filterByTag?: string[]; + /** Max. Anzahl Einträge. */ + numberItems?: number; + /** "list" | "cards". */ + design?: "list" | "cards"; + layout?: BlockLayout; + /** Nach resolvePostOverviewBlocks: geladene/gefilterte Posts (PostEntry[]). */ + postsResolved?: unknown[]; +} + +/** Tag-Referenz (API liefert oft { _slug, _type, name }). */ +export type SearchableTextTagRef = string | { _slug?: string; name?: string }; + +/** Ein Text-Fragment (aus text_fragment), für SearchableTextBlock. */ +export interface SearchableTextFragment { + _slug?: string; + title?: string; + text?: string; + tags?: SearchableTextTagRef[]; +} + +/** Durchsuchbarer Text (_type: "searchable_text"). textFragments können Slugs oder aufgelöste Objekte sein. */ +export interface SearchableTextBlockData { + _type?: "searchable_text"; + _slug?: string; + /** Titel der Suchkomponente. */ + title?: string; + /** Einleitung (Markdown). */ + description?: string; + /** Slugs oder aufgelöste text_fragment-Einträge. */ + textFragments?: (string | SearchableTextFragment)[]; + layout?: BlockLayout; +} + +/** OpnForm embed (_type: "opnform"). */ +export interface OpnFormBlockData { + _type?: "opnform"; + _slug?: string; + id?: string; + formId?: string; + baseUrl?: string; + iframeTitle?: string; + layout?: BlockLayout; +} + +/** Einzelne Organisation (aufgelöst aus organisation-Collection). */ +export interface OrganisationEntry { + _type?: "organisation"; + _slug?: string; + name?: string; + logo?: string | { src?: string; description?: string }; + /** Nach resolveContentImages: Proxy-URL zum Logo (WebP). */ + resolvedLogoSrc?: string; + description?: string; + link?: string | { url?: string; linkName?: string; newTab?: boolean }; + badge?: string | { label?: string; color?: string }; +} + +/** Organisations-Block (_type: "organisations"). */ +export interface OrganisationsBlockData { + _type?: "organisations"; + _slug?: string; + headline?: string; + description?: string; + /** default = Karten-Grid; compact = engere Karten, kleinere Typo, Logo links */ + presentation?: "default" | "compact"; + addOrganisationTitle?: string; + addOrganisationMarkdown?: string; + /** Referenz auf link-Collection (aufgelöst: url, linkName, newTab) */ + addOrganisationLink?: string | { url?: string; linkName?: string; newTab?: boolean }; + organisations?: (string | OrganisationEntry)[]; + layout?: BlockLayout; +} + +/** Kalender-Item (calendar_item) – aus OpenAPI; terminZeit = ISO date-time. */ +export type CalendarItemData = components["schemas"]["calendar_item"]; + +/** Kalender-Block (_type: "calendar"). items nach Resolve: CalendarItemData[]. Basis aus OpenAPI (calendar). */ +export type CalendarBlockData = Omit< + components["schemas"]["calendar"], + "items" +> & { + _type?: "calendar"; + /** Optionaler Titel über dem Kalender. */ + title?: string; + /** Slugs oder aufgelöste calendar_item-Einträge. */ + items?: (string | CalendarItemData)[]; + layout?: BlockLayout; +}; diff --git a/src/lib/blog-utils.ts b/src/lib/blog-utils.ts new file mode 100644 index 0000000..158d8bd --- /dev/null +++ b/src/lib/blog-utils.ts @@ -0,0 +1,582 @@ +import type { PostEntry } from "./cms"; +import { + getPosts, + getPostBySlug, + getTags, + getTextFragmentBySlug, + getCalendarBySlug, + getCalendarItemBySlug, +} from "./cms"; +import type { RowContentLayout } from "./block-types"; +import type { CalendarItemData } from "./block-types"; +import { ensureTransformedImage } from "./rusty-image"; + +/** Aus der Tag-API: Anzeigename plus optionales Icon und Farbe (CMS-Felder icon / color). */ +export type TagMeta = { + name: string; + icon?: string; + color?: string; +}; + +/** Slug → TagMeta aus der Tag-API. Für Auflösung von post.postTag. */ +export async function getTagsMap(): Promise> { + const tags = await getTags(); + const m = new Map(); + for (const t of tags) { + const slug = + (t as { _slug?: string })._slug ?? (t as { slug?: string }).slug ?? ""; + if (!slug) continue; + const name = (t as { name?: string }).name?.trim() ?? slug; + const icon = (t as { icon?: string }).icon?.trim(); + const color = (t as { color?: string }).color?.trim(); + m.set(slug, { + name, + ...(icon ? { icon } : {}), + ...(color ? { color } : {}), + }); + } + return m; +} + +export type ResolvedPostTag = { + _slug: string; + name: string; + icon?: string; + color?: string; +}; + +/** Setzt post.postTag auf { _slug, name, icon?, color? }[]; Metadaten aus slugToMeta bzw. bereits aufgelösten Refs. */ +export function resolvePostTagsInPost( + post: PostEntry, + slugToMeta: Map, +): void { + const raw = post.postTag ?? []; + if (!Array.isArray(raw)) return; + (post as { postTag?: ResolvedPostTag[] }).postTag = raw.map((t) => { + if (typeof t === "string") { + const meta = slugToMeta.get(t); + return { + _slug: t, + name: meta?.name ?? t, + ...(meta?.icon ? { icon: meta.icon } : {}), + ...(meta?.color ? { color: meta.color } : {}), + }; + } + const o = t as { + _slug?: string; + name?: string; + icon?: string; + color?: string; + }; + const slug = o._slug ?? o?.name ?? ""; + const meta = slug ? slugToMeta.get(slug) : undefined; + const icon = (o.icon ?? meta?.icon)?.trim(); + const color = (o.color ?? meta?.color)?.trim(); + return { + _slug: slug, + name: o?.name ?? meta?.name ?? slug, + ...(icon ? { icon } : {}), + ...(color ? { color } : {}), + }; + }); +} + +const POSTS_PER_PAGE = 10; + +export function getPostsPerPage(): number { + return POSTS_PER_PAGE; +} + +/** Filtert Posts mit hideFromListing: true aus Übersichten heraus. */ +export function filterHiddenPosts(posts: PostEntry[]): PostEntry[] { + return posts.filter( + (p) => !(p as PostEntry & { hideFromListing?: boolean }).hideFromListing, + ); +} + +/** Sortiert Posts nach Datum (neueste zuerst). */ +export function sortPostsByDate(posts: PostEntry[]): PostEntry[] { + return [...posts].sort((a, b) => { + const da = a.created ?? ""; + const db = b.created ?? ""; + if (!da) return 1; + if (!db) return -1; + return new Date(db).getTime() - new Date(da).getTime(); + }); +} + +/** Filtert Posts nach Tag-Slug (post.postTag enthält den Slug). */ +export function filterPostsByTag( + posts: PostEntry[], + tagSlug: string | null, +): PostEntry[] { + if (!tagSlug) return posts; + return posts.filter((p) => { + const tags = p.postTag ?? []; + return tags.some((t) => { + const slug = typeof t === "string" ? t : (t as { _slug?: string })?._slug; + return slug === tagSlug; + }); + }); +} + +/** URL aus post.postImage (RustyCMS img mit src, oder legacy file.url). */ +export function getPostImageUrl( + postImage: PostEntry["postImage"], +): string | null { + if (!postImage || typeof postImage === "string") return null; + const obj = postImage as { + src?: string; + file?: { url?: string }; + fields?: { file?: { url?: string } }; + }; + const url = obj?.src ?? obj?.file?.url ?? obj?.fields?.file?.url; + return typeof url === "string" + ? url.startsWith("//") + ? `https:${url}` + : url + : null; +} + +/** Filtert Posts: behält nur solche, die mindestens einen der Tag-Slugs haben. */ +export function filterPostsByTagSlugs( + posts: PostEntry[], + tagSlugs: string[], +): PostEntry[] { + if (!tagSlugs?.length) return posts; + return posts.filter((p) => { + const tags = p.postTag ?? []; + return tags.some((t) => { + const slug = typeof t === "string" ? t : (t as { _slug?: string })?._slug; + return tagSlugs.includes(slug ?? ""); + }); + }); +} + +export function getTotalPages(count: number, perPage: number): number { + return Math.max(1, Math.ceil(count / perPage)); +} + +export function paginate(items: T[], page: number, perPage: number): T[] { + const start = (page - 1) * perPage; + return items.slice(start, start + perPage); +} + +export type PostSearchIndexEntry = { + slug: string; + headline: string; + excerpt: string; + subheadline: string; + tags: string[]; + image: string | null; + created: string | null; + isEvent: boolean; + eventDate: string | null; +}; + +type PostWithEventIndex = PostEntry & { + isEvent?: boolean; + eventDate?: string; + _resolvedImageUrl?: string; +}; + +export function buildPostSearchIndex(posts: PostEntry[]): PostSearchIndexEntry[] { + return posts.map((p) => ({ + slug: p.slug ?? p._slug ?? "", + headline: p.headline ?? "", + excerpt: p.excerpt ?? "", + subheadline: p.subheadline ?? "", + tags: (p.postTag ?? []) + .map((t) => + typeof t === "string" + ? t + : (t as { name?: string; _slug?: string }).name ?? + (t as { _slug?: string })._slug ?? + "", + ) + .filter(Boolean), + image: (p as PostWithEventIndex)._resolvedImageUrl ?? null, + created: p.created ?? null, + isEvent: Boolean((p as PostWithEventIndex).isEvent), + eventDate: (p as PostWithEventIndex).eventDate ?? null, + })); +} + +export type LoadPostsResult = { + posts: PostEntry[]; + tags: Awaited>; + activeTag: string | null; + currentPage: number; + totalPages: number; + totalPosts: number; + upcomingEvents: PostEntry[]; + searchIndex: PostSearchIndexEntry[]; + tagName: string | null; + cmsError: string | null; +}; + +/** Gemeinsame Ladefunktion für /posts, /posts/page/[n], /posts/tag/[t], /posts/tag/[t]/page/[n]. */ +export async function loadPostsList(opts: { + tagSlug?: string | null; + page?: number; +}): Promise { + const tagSlug = opts.tagSlug ?? null; + const requestedPage = Math.max(1, opts.page ?? 1); + const perPage = getPostsPerPage(); + + let posts: PostEntry[] = []; + let tags: Awaited> = []; + let cmsError: string | null = null; + + try { + [posts, tags] = await Promise.all([ + getPosts({ resolve: ["postImage"] }), + getTags(), + ]); + posts = filterHiddenPosts(sortPostsByDate(posts)); + const tagsMap = await getTagsMap(); + for (const p of posts) resolvePostTagsInPost(p, tagsMap); + for (const post of posts) { + const raw = getPostImageUrl(post.postImage); + if (raw) { + try { + const url = await ensureTransformedImage(raw, { + width: 400, + height: 267, + fit: "cover", + format: "webp", + }); + (post as PostEntry & { _resolvedImageUrl?: string })._resolvedImageUrl = url; + } catch { + /* image optional */ + } + } + } + } catch (e) { + cmsError = e instanceof Error ? e.message : String(e); + } + + const filtered = filterPostsByTag(posts, tagSlug); + const totalPages = getTotalPages(filtered.length, perPage); + const pageNum = Math.min(requestedPage, totalPages); + const pagePosts = paginate(filtered, pageNum, perPage); + + const tagName = tagSlug + ? (tags.find((t) => ((t as { _slug?: string })._slug ?? "") === tagSlug)?.name ?? tagSlug) + : null; + + const upcomingEvents = selectUpcomingEvents(posts); + const searchIndex = buildPostSearchIndex(posts); + + return { + posts: pagePosts, + tags, + activeTag: tagSlug, + currentPage: pageNum, + totalPages, + totalPosts: filtered.length, + upcomingEvents, + searchIndex, + tagName, + cmsError, + }; +} + +export function selectUpcomingEvents(posts: PostEntry[], max = 4): PostEntry[] { + const now = Date.now(); + return (posts as PostWithEventIndex[]) + .filter( + (p) => p.isEvent && p.eventDate && new Date(p.eventDate).getTime() >= now, + ) + .sort( + (a, b) => + new Date(a.eventDate ?? 0).getTime() - + new Date(b.eventDate ?? 0).getTime(), + ) + .slice(0, max) as PostEntry[]; +} + +const POST_BASE = "/post"; + +/** Post-URL: slug ist die URL; führender Slash entfernt. */ +export function postHref(post: PostEntry): string { + const slug = post.slug ?? post._slug ?? ""; + const norm = (slug ?? "").replace(/^\//, "").trim(); + return norm ? `${POST_BASE}/${encodeURIComponent(norm)}` : POST_BASE; +} + +export function formatPostDate(value: string | undefined): string { + if (!value) return ""; + try { + const d = new Date(value); + return Number.isNaN(d.getTime()) + ? "" + : d.toLocaleDateString("de-DE", { + year: "numeric", + month: "short", + day: "numeric", + }); + } catch { + return ""; + } +} + +/** Prüft, ob ein Block ein Post-Overview-Block ist (mit _type "post_overview"). */ +function isPostOverviewBlock(item: unknown): item is { + _type?: string; + allPosts?: boolean; + posts?: unknown[]; + filterByTag?: unknown[]; + numberItems?: number; + postsResolved?: unknown[]; +} { + return ( + typeof item === "object" && + item !== null && + (item as { _type?: string })._type === "post_overview" + ); +} + +/** + * Lädt Posts für alle post_overview-Blöcke im Layout und setzt postsResolved. + * Nutzt die globale Tag-API (getTagsMap()) für Slug → TagMeta. + * Gibt die tagsMap zurück (z. B. für resolvePostTagsInPost auf [slug]+page.server.ts). + */ +export async function resolvePostOverviewBlocks( + layout: RowContentLayout | null | undefined, +): Promise> { + const tagsMap = await getTagsMap(); + + if (!layout) return tagsMap; + const rows = [ + layout.row1Content ?? [], + layout.row2Content ?? [], + layout.row3Content ?? [], + ]; + let allPosts: PostEntry[] | null = null; + + for (const content of rows) { + if (!Array.isArray(content)) continue; + for (const item of content) { + if (!isPostOverviewBlock(item)) continue; + if (item.allPosts) { + if (allPosts === null) + allPosts = await getPosts({ + _sort: "created", + _order: "desc", + resolve: "all", + }); + let list = filterHiddenPosts(sortPostsByDate(allPosts)); + const rawFilter = item.filterByTag ?? []; + const tagSlugs = Array.isArray(rawFilter) + ? rawFilter + .map((t) => + typeof t === "string" + ? t + : ((t as { _slug?: string })?._slug ?? ""), + ) + .filter(Boolean) + : []; + if (tagSlugs.length) list = filterPostsByTagSlugs(list, tagSlugs); + const limit = + typeof item.numberItems === "number" ? item.numberItems : 9999; + item.postsResolved = list.slice(0, limit); + } else if (Array.isArray(item.posts) && item.posts.length > 0) { + const first = item.posts[0]; + const isResolved = + typeof first === "object" && + first !== null && + "_slug" in first && + ("headline" in first || "linkName" in first); + if (isResolved) { + item.postsResolved = item.posts as PostEntry[]; + } else { + const slugs = item.posts + .map((p) => + typeof p === "string" + ? p + : ((p as { _slug?: string })?._slug ?? ""), + ) + .filter(Boolean); + const limit = + typeof item.numberItems === "number" ? item.numberItems : 9999; + const resolved: PostEntry[] = []; + for (const slug of slugs.slice(0, limit)) { + const post = await getPostBySlug(slug, { + locale: "de", + resolve: ["all"], + }); + if (post) resolved.push(post); + } + item.postsResolved = resolved; + } + } + if (Array.isArray(item.postsResolved)) { + const posts = item.postsResolved as PostEntry[]; + if (posts.length > 0) { + for (const post of posts) resolvePostTagsInPost(post, tagsMap); + } + for (const post of item.postsResolved as PostEntry[]) { + const raw = getPostImageUrl(post.postImage); + if (raw) { + try { + const url = await ensureTransformedImage(raw, { + width: 400, + height: 267, + fit: "cover", + format: "webp", + }); + ( + post as PostEntry & { _resolvedImageUrl?: string } + )._resolvedImageUrl = url; + } catch { + // Bild optional + } + } + } + } + } + } + return tagsMap; +} + +function isCalendarBlock( + item: unknown, +): item is { _type?: string; _slug?: string; items?: unknown[] } { + return ( + typeof item === "object" && + item !== null && + (item as { _type?: string })._type === "calendar" + ); +} + +/** + * Löst Calendar-Blöcke auf: Lädt Kalender per Slug und setzt block.items + * mit den aufgelösten calendar_item-Einträgen (title, terminZeit, description, link). + */ +export async function resolveCalendarBlocks( + layout: RowContentLayout, +): Promise { + const rows = [ + layout.row1Content ?? [], + layout.row2Content ?? [], + layout.row3Content ?? [], + ]; + + for (const content of rows) { + if (!Array.isArray(content)) continue; + for (const item of content) { + if (!isCalendarBlock(item)) continue; + const slug = item._slug; + if (!slug) continue; + const rawItems = item.items ?? []; + const first = rawItems[0]; + const alreadyResolved = + typeof first === "object" && + first !== null && + "terminZeit" in first && + "title" in first; + if (alreadyResolved) continue; + + const calendar = await getCalendarBySlug(slug, { + locale: "de", + resolve: "items", + }); + const raw = calendar?.items ?? rawItems; + const resolved: CalendarItemData[] = []; + for (const x of raw) { + if (typeof x === "object" && x !== null && "terminZeit" in x && "title" in x) { + resolved.push(x as CalendarItemData); + } else { + const islug = typeof x === "string" ? x : (x as { _slug?: string })?._slug; + if (islug) { + const entry = await getCalendarItemBySlug(islug, { locale: "de" }); + if (entry) resolved.push(entry); + } + } + } + (item as { items?: CalendarItemData[] }).items = resolved; + } + } +} + +function isSearchableTextBlock( + item: unknown, +): item is { _type?: string; textFragments?: unknown[] } { + return ( + typeof item === "object" && + item !== null && + (item as { _type?: string })._type === "searchable_text" + ); +} + +/** Prüft, ob ein Fragment bereits aufgelöst ist (hat title oder text). */ +function isResolvedFragment(f: unknown): boolean { + if (typeof f !== "object" || f === null) return false; + const o = f as { title?: string; text?: string }; + return "title" in o || "text" in o; +} + +/** + * Normalisiert tags eines Fragments zu Anzeigenamen (string[]). + * Nutzt slugToMeta für Slug → Anzeigename; Objekte mit name/_slug werden unterstützt. + */ +function resolveFragmentTags( + tagsRaw: unknown[] | undefined, + slugToMeta: Map, +): string[] { + if (!Array.isArray(tagsRaw)) return []; + return tagsRaw + .map((t) => { + if (typeof t === "string") return slugToMeta.get(t)?.name ?? t; + const o = t as { _slug?: string; name?: string }; + const slug = o._slug ?? ""; + return (o.name ?? slugToMeta.get(slug)?.name ?? slug).trim(); + }) + .filter(Boolean); +} + +/** + * Lädt für alle searchable_text-Blöcke im Layout die textFragments nach + * (wenn sie als Slugs/Refs kommen), setzt die aufgelösten Einträge und + * löst Tag-Slugs/Refs in Anzeigenamen auf. + * @param slugToMeta Optionale Map Slug → TagMeta (z. B. von resolvePostOverviewBlocks); sonst getTagsMap(). + */ +export async function resolveSearchableTextBlocks( + layout: RowContentLayout | null | undefined, + slugToMeta?: Map, +): Promise { + if (!layout) return; + const tagsMap = slugToMeta ?? (await getTagsMap()); + const rows = [ + layout.row1Content ?? [], + layout.row2Content ?? [], + layout.row3Content ?? [], + ]; + for (const content of rows) { + if (!Array.isArray(content)) continue; + for (const item of content) { + if (!isSearchableTextBlock(item)) continue; + const raw = item.textFragments ?? []; + if (!Array.isArray(raw) || raw.length === 0) continue; + const needsResolve = raw.some((f) => !isResolvedFragment(f)); + if (!needsResolve) continue; + const resolved: unknown[] = []; + for (const f of raw) { + const slug = + typeof f === "string" ? f : ((f as { _slug?: string })?._slug ?? ""); + if (!slug) { + if (isResolvedFragment(f)) resolved.push(f); + continue; + } + const frag = await getTextFragmentBySlug(slug, { locale: "de" }); + if (frag) { + const fragObj = frag as { tags?: unknown[] }; + const tagNames = resolveFragmentTags(fragObj.tags, tagsMap); + resolved.push({ ...fragObj, tags: tagNames }); + } + } + (item as { textFragments?: unknown[] }).textFragments = resolved; + } + } +} diff --git a/src/lib/cms-api.generated.ts b/src/lib/cms-api.generated.ts new file mode 100644 index 0000000..7a21139 --- /dev/null +++ b/src/lib/cms-api.generated.ts @@ -0,0 +1,15632 @@ +/** + * This file was auto-generated by openapi-typescript. + * Do not make direct changes to the file. + */ + +export interface paths { + "/api/assets": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List all assets + * @description Returns all image files stored in `content/assets/`. + */ + get: operations["listAssets"]; + put?: never; + /** + * Upload an image asset + * @description Upload an image file (jpg, jpeg, png, webp, avif, gif, svg) to `content/assets/`. Requires API key when `RUSTYCMS_API_KEY` is set. + */ + post: operations["uploadAsset"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/assets/{filename}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Serve an asset + * @description Returns the raw image file with the appropriate `Content-Type` header. Cached by browsers for 1 year (`Cache-Control: immutable`). + */ + get: operations["getAsset"]; + put?: never; + post?: never; + /** + * Delete an asset + * @description Deletes an image file from `content/assets/`. Requires API key when `RUSTYCMS_API_KEY` is set. + */ + delete: operations["deleteAsset"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List all collections */ + get: operations["listCollections"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/badge": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'badge' */ + get: operations["getBadgeSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/calendar": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'calendar' */ + get: operations["getCalendarSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/calendar_item": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'calendar_item' */ + get: operations["getCalendarItemSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/campaign": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'campaign' */ + get: operations["getCampaignSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/campaigns": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'campaigns' */ + get: operations["getCampaignsSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/content_layout": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'content_layout' */ + get: operations["getContentLayoutSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/demo": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'demo' */ + get: operations["getDemoSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/footer": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'footer' */ + get: operations["getFooterSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/fullwidth_banner": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'fullwidth_banner' */ + get: operations["getFullwidthBannerSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/headline": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'headline' */ + get: operations["getHeadlineSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/html": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'html' */ + get: operations["getHtmlSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/iframe": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'iframe' */ + get: operations["getIframeSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/image": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'image' */ + get: operations["getImageSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/image_gallery": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'image_gallery' */ + get: operations["getImageGallerySchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/link": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'link' */ + get: operations["getLinkSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/link_list": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'link_list' */ + get: operations["getLinkListSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/list": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'list' */ + get: operations["getListSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/markdown": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'markdown' */ + get: operations["getMarkdownSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/navgroup": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'navgroup' */ + get: operations["getNavgroupSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/navigation": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'navigation' */ + get: operations["getNavigationSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/opnform": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'opnform' */ + get: operations["getOpnformSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/organisation": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'organisation' */ + get: operations["getOrganisationSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/organisations": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'organisations' */ + get: operations["getOrganisationsSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/page": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'page' */ + get: operations["getPageSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/page_config": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'page_config' */ + get: operations["getPageConfigSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/post": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'post' */ + get: operations["getPostSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/post_overview": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'post_overview' */ + get: operations["getPostOverviewSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/product": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'product' */ + get: operations["getProductSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/quote": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'quote' */ + get: operations["getQuoteSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/searchable_text": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'searchable_text' */ + get: operations["getSearchableTextSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/seo": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'seo' */ + get: operations["getSeoSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/tag": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'tag' */ + get: operations["getTagSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/text_fragment": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'text_fragment' */ + get: operations["getTextFragmentSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/top_banner": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'top_banner' */ + get: operations["getTopBannerSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/translation_bundle": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'translation_bundle' */ + get: operations["getTranslationBundleSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/collections/youtube_video": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get schema definition for 'youtube_video' */ + get: operations["getYoutubeVideoSchema"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/badge": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'badge' entries */ + get: operations["listBadge"]; + put?: never; + /** Create a new 'badge' entry */ + post: operations["createBadge"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/badge/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'badge' entry by slug */ + get: operations["getBadge"]; + /** Update 'badge' entry */ + put: operations["updateBadge"]; + post?: never; + /** Delete 'badge' entry */ + delete: operations["deleteBadge"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/badge/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'badge' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getBadgeReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/calendar": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'calendar' entries */ + get: operations["listCalendar"]; + put?: never; + /** Create a new 'calendar' entry */ + post: operations["createCalendar"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/calendar/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'calendar' entry by slug */ + get: operations["getCalendar"]; + /** Update 'calendar' entry */ + put: operations["updateCalendar"]; + post?: never; + /** Delete 'calendar' entry */ + delete: operations["deleteCalendar"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/calendar/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'calendar' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getCalendarReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/calendar_item": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'calendar_item' entries */ + get: operations["listCalendarItem"]; + put?: never; + /** Create a new 'calendar_item' entry */ + post: operations["createCalendarItem"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/calendar_item/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'calendar_item' entry by slug */ + get: operations["getCalendarItem"]; + /** Update 'calendar_item' entry */ + put: operations["updateCalendarItem"]; + post?: never; + /** Delete 'calendar_item' entry */ + delete: operations["deleteCalendarItem"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/calendar_item/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'calendar_item' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getCalendarItemReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/campaign": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'campaign' entries */ + get: operations["listCampaign"]; + put?: never; + /** Create a new 'campaign' entry */ + post: operations["createCampaign"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/campaign/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'campaign' entry by slug */ + get: operations["getCampaign"]; + /** Update 'campaign' entry */ + put: operations["updateCampaign"]; + post?: never; + /** Delete 'campaign' entry */ + delete: operations["deleteCampaign"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/campaign/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'campaign' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getCampaignReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/campaigns": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'campaigns' entries */ + get: operations["listCampaigns"]; + put?: never; + /** Create a new 'campaigns' entry */ + post: operations["createCampaigns"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/campaigns/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'campaigns' entry by slug */ + get: operations["getCampaigns"]; + /** Update 'campaigns' entry */ + put: operations["updateCampaigns"]; + post?: never; + /** Delete 'campaigns' entry */ + delete: operations["deleteCampaigns"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/campaigns/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'campaigns' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getCampaignsReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/content_layout": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'content_layout' entries */ + get: operations["listContentLayout"]; + put?: never; + /** Create a new 'content_layout' entry */ + post: operations["createContentLayout"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/content_layout/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'content_layout' entry by slug */ + get: operations["getContentLayout"]; + /** Update 'content_layout' entry */ + put: operations["updateContentLayout"]; + post?: never; + /** Delete 'content_layout' entry */ + delete: operations["deleteContentLayout"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/content_layout/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'content_layout' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getContentLayoutReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/demo": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'demo' entries */ + get: operations["listDemo"]; + put?: never; + /** Create a new 'demo' entry */ + post: operations["createDemo"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/demo/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'demo' entry by slug */ + get: operations["getDemo"]; + /** Update 'demo' entry */ + put: operations["updateDemo"]; + post?: never; + /** Delete 'demo' entry */ + delete: operations["deleteDemo"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/demo/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'demo' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getDemoReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/footer": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'footer' entries */ + get: operations["listFooter"]; + put?: never; + /** Create a new 'footer' entry */ + post: operations["createFooter"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/footer/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'footer' entry by slug */ + get: operations["getFooter"]; + /** Update 'footer' entry */ + put: operations["updateFooter"]; + post?: never; + /** Delete 'footer' entry */ + delete: operations["deleteFooter"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/footer/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'footer' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getFooterReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/fullwidth_banner": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'fullwidth_banner' entries */ + get: operations["listFullwidthBanner"]; + put?: never; + /** Create a new 'fullwidth_banner' entry */ + post: operations["createFullwidthBanner"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/fullwidth_banner/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'fullwidth_banner' entry by slug */ + get: operations["getFullwidthBanner"]; + /** Update 'fullwidth_banner' entry */ + put: operations["updateFullwidthBanner"]; + post?: never; + /** Delete 'fullwidth_banner' entry */ + delete: operations["deleteFullwidthBanner"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/fullwidth_banner/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'fullwidth_banner' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getFullwidthBannerReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/headline": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'headline' entries */ + get: operations["listHeadline"]; + put?: never; + /** Create a new 'headline' entry */ + post: operations["createHeadline"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/headline/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'headline' entry by slug */ + get: operations["getHeadline"]; + /** Update 'headline' entry */ + put: operations["updateHeadline"]; + post?: never; + /** Delete 'headline' entry */ + delete: operations["deleteHeadline"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/headline/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'headline' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getHeadlineReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/html": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'html' entries */ + get: operations["listHtml"]; + put?: never; + /** Create a new 'html' entry */ + post: operations["createHtml"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/html/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'html' entry by slug */ + get: operations["getHtml"]; + /** Update 'html' entry */ + put: operations["updateHtml"]; + post?: never; + /** Delete 'html' entry */ + delete: operations["deleteHtml"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/html/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'html' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getHtmlReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/iframe": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'iframe' entries */ + get: operations["listIframe"]; + put?: never; + /** Create a new 'iframe' entry */ + post: operations["createIframe"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/iframe/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'iframe' entry by slug */ + get: operations["getIframe"]; + /** Update 'iframe' entry */ + put: operations["updateIframe"]; + post?: never; + /** Delete 'iframe' entry */ + delete: operations["deleteIframe"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/iframe/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'iframe' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getIframeReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/image": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'image' entries */ + get: operations["listImage"]; + put?: never; + /** Create a new 'image' entry */ + post: operations["createImage"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/image/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'image' entry by slug */ + get: operations["getImage"]; + /** Update 'image' entry */ + put: operations["updateImage"]; + post?: never; + /** Delete 'image' entry */ + delete: operations["deleteImage"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/image/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'image' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getImageReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/image_gallery": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'image_gallery' entries */ + get: operations["listImageGallery"]; + put?: never; + /** Create a new 'image_gallery' entry */ + post: operations["createImageGallery"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/image_gallery/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'image_gallery' entry by slug */ + get: operations["getImageGallery"]; + /** Update 'image_gallery' entry */ + put: operations["updateImageGallery"]; + post?: never; + /** Delete 'image_gallery' entry */ + delete: operations["deleteImageGallery"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/image_gallery/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'image_gallery' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getImageGalleryReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/link": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'link' entries */ + get: operations["listLink"]; + put?: never; + /** Create a new 'link' entry */ + post: operations["createLink"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/link/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'link' entry by slug */ + get: operations["getLink"]; + /** Update 'link' entry */ + put: operations["updateLink"]; + post?: never; + /** Delete 'link' entry */ + delete: operations["deleteLink"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/link/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'link' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getLinkReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/link_list": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'link_list' entries */ + get: operations["listLinkList"]; + put?: never; + /** Create a new 'link_list' entry */ + post: operations["createLinkList"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/link_list/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'link_list' entry by slug */ + get: operations["getLinkList"]; + /** Update 'link_list' entry */ + put: operations["updateLinkList"]; + post?: never; + /** Delete 'link_list' entry */ + delete: operations["deleteLinkList"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/link_list/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'link_list' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getLinkListReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/list": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'list' entries */ + get: operations["listList"]; + put?: never; + /** Create a new 'list' entry */ + post: operations["createList"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/list/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'list' entry by slug */ + get: operations["getList"]; + /** Update 'list' entry */ + put: operations["updateList"]; + post?: never; + /** Delete 'list' entry */ + delete: operations["deleteList"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/list/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'list' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getListReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/markdown": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'markdown' entries */ + get: operations["listMarkdown"]; + put?: never; + /** Create a new 'markdown' entry */ + post: operations["createMarkdown"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/markdown/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'markdown' entry by slug */ + get: operations["getMarkdown"]; + /** Update 'markdown' entry */ + put: operations["updateMarkdown"]; + post?: never; + /** Delete 'markdown' entry */ + delete: operations["deleteMarkdown"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/markdown/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'markdown' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getMarkdownReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/navgroup": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'navgroup' entries */ + get: operations["listNavgroup"]; + put?: never; + /** Create a new 'navgroup' entry */ + post: operations["createNavgroup"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/navgroup/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'navgroup' entry by slug */ + get: operations["getNavgroup"]; + /** Update 'navgroup' entry */ + put: operations["updateNavgroup"]; + post?: never; + /** Delete 'navgroup' entry */ + delete: operations["deleteNavgroup"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/navgroup/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'navgroup' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getNavgroupReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/navigation": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'navigation' entries */ + get: operations["listNavigation"]; + put?: never; + /** Create a new 'navigation' entry */ + post: operations["createNavigation"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/navigation/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'navigation' entry by slug */ + get: operations["getNavigation"]; + /** Update 'navigation' entry */ + put: operations["updateNavigation"]; + post?: never; + /** Delete 'navigation' entry */ + delete: operations["deleteNavigation"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/navigation/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'navigation' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getNavigationReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/opnform": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'opnform' entries */ + get: operations["listOpnform"]; + put?: never; + /** Create a new 'opnform' entry */ + post: operations["createOpnform"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/opnform/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'opnform' entry by slug */ + get: operations["getOpnform"]; + /** Update 'opnform' entry */ + put: operations["updateOpnform"]; + post?: never; + /** Delete 'opnform' entry */ + delete: operations["deleteOpnform"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/opnform/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'opnform' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getOpnformReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/organisation": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'organisation' entries */ + get: operations["listOrganisation"]; + put?: never; + /** Create a new 'organisation' entry */ + post: operations["createOrganisation"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/organisation/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'organisation' entry by slug */ + get: operations["getOrganisation"]; + /** Update 'organisation' entry */ + put: operations["updateOrganisation"]; + post?: never; + /** Delete 'organisation' entry */ + delete: operations["deleteOrganisation"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/organisation/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'organisation' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getOrganisationReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/organisations": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'organisations' entries */ + get: operations["listOrganisations"]; + put?: never; + /** Create a new 'organisations' entry */ + post: operations["createOrganisations"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/organisations/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'organisations' entry by slug */ + get: operations["getOrganisations"]; + /** Update 'organisations' entry */ + put: operations["updateOrganisations"]; + post?: never; + /** Delete 'organisations' entry */ + delete: operations["deleteOrganisations"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/organisations/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'organisations' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getOrganisationsReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/page": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'page' entries */ + get: operations["listPage"]; + put?: never; + /** Create a new 'page' entry */ + post: operations["createPage"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/page/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'page' entry by slug */ + get: operations["getPage"]; + /** Update 'page' entry */ + put: operations["updatePage"]; + post?: never; + /** Delete 'page' entry */ + delete: operations["deletePage"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/page/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'page' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getPageReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/page_config": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'page_config' entries */ + get: operations["listPageConfig"]; + put?: never; + /** Create a new 'page_config' entry */ + post: operations["createPageConfig"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/page_config/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'page_config' entry by slug */ + get: operations["getPageConfig"]; + /** Update 'page_config' entry */ + put: operations["updatePageConfig"]; + post?: never; + /** Delete 'page_config' entry */ + delete: operations["deletePageConfig"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/page_config/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'page_config' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getPageConfigReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/post": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'post' entries */ + get: operations["listPost"]; + put?: never; + /** Create a new 'post' entry */ + post: operations["createPost"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/post/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'post' entry by slug */ + get: operations["getPost"]; + /** Update 'post' entry */ + put: operations["updatePost"]; + post?: never; + /** Delete 'post' entry */ + delete: operations["deletePost"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/post/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'post' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getPostReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/post_overview": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'post_overview' entries */ + get: operations["listPostOverview"]; + put?: never; + /** Create a new 'post_overview' entry */ + post: operations["createPostOverview"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/post_overview/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'post_overview' entry by slug */ + get: operations["getPostOverview"]; + /** Update 'post_overview' entry */ + put: operations["updatePostOverview"]; + post?: never; + /** Delete 'post_overview' entry */ + delete: operations["deletePostOverview"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/post_overview/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'post_overview' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getPostOverviewReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/product": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'product' entries */ + get: operations["listProduct"]; + put?: never; + /** Create a new 'product' entry */ + post: operations["createProduct"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/product/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'product' entry by slug */ + get: operations["getProduct"]; + /** Update 'product' entry */ + put: operations["updateProduct"]; + post?: never; + /** Delete 'product' entry */ + delete: operations["deleteProduct"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/product/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'product' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getProductReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/quote": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'quote' entries */ + get: operations["listQuote"]; + put?: never; + /** Create a new 'quote' entry */ + post: operations["createQuote"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/quote/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'quote' entry by slug */ + get: operations["getQuote"]; + /** Update 'quote' entry */ + put: operations["updateQuote"]; + post?: never; + /** Delete 'quote' entry */ + delete: operations["deleteQuote"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/quote/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'quote' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getQuoteReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/searchable_text": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'searchable_text' entries */ + get: operations["listSearchableText"]; + put?: never; + /** Create a new 'searchable_text' entry */ + post: operations["createSearchableText"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/searchable_text/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'searchable_text' entry by slug */ + get: operations["getSearchableText"]; + /** Update 'searchable_text' entry */ + put: operations["updateSearchableText"]; + post?: never; + /** Delete 'searchable_text' entry */ + delete: operations["deleteSearchableText"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/searchable_text/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'searchable_text' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getSearchableTextReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/seo": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'seo' entries */ + get: operations["listSeo"]; + put?: never; + /** Create a new 'seo' entry */ + post: operations["createSeo"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/seo/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'seo' entry by slug */ + get: operations["getSeo"]; + /** Update 'seo' entry */ + put: operations["updateSeo"]; + post?: never; + /** Delete 'seo' entry */ + delete: operations["deleteSeo"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/seo/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'seo' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getSeoReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/tag": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'tag' entries */ + get: operations["listTag"]; + put?: never; + /** Create a new 'tag' entry */ + post: operations["createTag"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/tag/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'tag' entry by slug */ + get: operations["getTag"]; + /** Update 'tag' entry */ + put: operations["updateTag"]; + post?: never; + /** Delete 'tag' entry */ + delete: operations["deleteTag"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/tag/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'tag' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getTagReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/text_fragment": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'text_fragment' entries */ + get: operations["listTextFragment"]; + put?: never; + /** Create a new 'text_fragment' entry */ + post: operations["createTextFragment"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/text_fragment/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'text_fragment' entry by slug */ + get: operations["getTextFragment"]; + /** Update 'text_fragment' entry */ + put: operations["updateTextFragment"]; + post?: never; + /** Delete 'text_fragment' entry */ + delete: operations["deleteTextFragment"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/text_fragment/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'text_fragment' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getTextFragmentReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/top_banner": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'top_banner' entries */ + get: operations["listTopBanner"]; + put?: never; + /** Create a new 'top_banner' entry */ + post: operations["createTopBanner"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/top_banner/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'top_banner' entry by slug */ + get: operations["getTopBanner"]; + /** Update 'top_banner' entry */ + put: operations["updateTopBanner"]; + post?: never; + /** Delete 'top_banner' entry */ + delete: operations["deleteTopBanner"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/top_banner/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'top_banner' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getTopBannerReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/translation_bundle": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'translation_bundle' entries */ + get: operations["listTranslationBundle"]; + put?: never; + /** Create a new 'translation_bundle' entry */ + post: operations["createTranslationBundle"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/translation_bundle/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'translation_bundle' entry by slug */ + get: operations["getTranslationBundle"]; + /** Update 'translation_bundle' entry */ + put: operations["updateTranslationBundle"]; + post?: never; + /** Delete 'translation_bundle' entry */ + delete: operations["deleteTranslationBundle"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/translation_bundle/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'translation_bundle' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getTranslationBundleReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/youtube_video": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List 'youtube_video' entries */ + get: operations["listYoutubeVideo"]; + put?: never; + /** Create a new 'youtube_video' entry */ + post: operations["createYoutubeVideo"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/youtube_video/{slug}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get 'youtube_video' entry by slug */ + get: operations["getYoutubeVideo"]; + /** Update 'youtube_video' entry */ + put: operations["updateYoutubeVideo"]; + post?: never; + /** Delete 'youtube_video' entry */ + delete: operations["deleteYoutubeVideo"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/content/youtube_video/{slug}/referrers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List referrers of 'youtube_video' entry + * @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS). + */ + get: operations["getYoutubeVideoReferrers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/environments": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List content spaces + * @description Returns the active environment list. Empty when multi-environment mode is off (no `RUSTYCMS_ENVIRONMENTS`). + */ + get: operations["listEnvironments"]; + put?: never; + /** + * Create a new space + * @description Creates a new environment. Body accepts optional `locales` array — when omitted, the space inherits the global locale list; `[]` disables i18n for this space only. + */ + post: operations["createEnvironment"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/environments/{name}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** Delete a space (including all content) */ + delete: operations["deleteEnvironment"]; + options?: never; + head?: never; + /** Rename a space */ + patch: operations["renameEnvironment"]; + trace?: never; + }; + "/api/environments/{name}/duplicate": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Deep-copy a space */ + post: operations["duplicateEnvironment"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/environments/{name}/locales": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get a space's locale configuration + * @description Returns the active locale list (per-env override or global fallback), plus the on-disk locale folders for orphan detection ("Karteileichen"). + */ + get: operations["getEnvironmentLocales"]; + /** + * Set or clear per-space locale override + * @description Body `{ locales: [..] }` sets an explicit override, `{ locales: null }` clears it (follow global). `[]` disables i18n for this space only. First array element becomes the default locale. Content in removed locales is kept on disk. + */ + put: operations["putEnvironmentLocales"]; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/locales": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Effective locale list for a space + * @description Resolves the active locale list for the environment passed via `_environment` (falls back to the default space / global list). + */ + get: operations["listLocales"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/transform": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Transform image from external URL + * @description Fetches an image from the given URL and returns it resized/cropped. Supports JPEG, PNG, WebP, AVIF output. + */ + get: operations["transformImage"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; +} +export type webhooks = Record; +export interface components { + schemas: { + Asset: { + /** @description Filename of the asset */ + filename?: string; + /** @description MIME type (e.g. image/jpeg) */ + mime_type?: string; + /** @description File size in bytes */ + size?: number; + /** @description URL path to serve the asset (e.g. /api/assets/hero.jpg) */ + url?: string; + }; + EnvironmentLocales: { + /** @description First entry in `locales`, or null when i18n is off */ + default?: string | null; + /** @description Global fallback list for UI diffing / reset */ + global?: string[]; + /** @description Active locale list (override if present, otherwise global fallback) */ + locales?: string[]; + /** @description Locale sub-directories present on disk. Values NOT in `locales` are orphans ("Karteileichen"). */ + on_disk?: string[]; + /** @description True when the space has its own `.rustycms.json5` override */ + override?: boolean; + }; + badge: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Optional color hint (e.g. green, #4caf50, CSS class name) */ + color?: string; + /** @description Display label shown in UI (e.g. Gründungsmitglied) */ + label: string; + /** @description Internal key (e.g. gruendungsmitglied) */ + name: string; + }; + badge_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Optional color hint (e.g. green, #4caf50, CSS class name) */ + color?: string; + /** @description Display label shown in UI (e.g. Gründungsmitglied) */ + label: string; + /** @description Internal key (e.g. gruendungsmitglied) */ + name: string; + }; + calendar: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** + * @description Include entries from post (optional) + * @default false + */ + fromPost: boolean; + /** @description Calendar entries (references to calendar_item) */ + items?: string[]; + }; + calendar_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** + * @description Include entries from post (optional) + * @default false + */ + fromPost: boolean; + /** @description Calendar entries (references to calendar_item) */ + items?: string[]; + }; + calendar_item: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Event description (optional) */ + description?: string; + /** @description Optional link (e.g. registration or details page) */ + link?: string; + /** + * Format: date-time + * @description Event date/time + */ + terminZeit: string; + /** @description Event title */ + title: string; + }; + calendar_item_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Event description (optional) */ + description?: string; + /** @description Optional link (e.g. registration or details page) */ + link?: string; + /** + * Format: date-time + * @description Event date/time + */ + terminZeit: string; + /** @description Event title */ + title: string; + }; + campaign: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Optional CSS */ + css?: string; + /** @description HTML content (optional) */ + html?: string; + /** + * @description Position relative to selector + * @default beforeend + * @enum {string} + */ + insertHtml: "afterbegin" | "beforeend" | "afterend" | "beforebegin" | "replace"; + /** @description Optional JavaScript */ + javascript?: string; + /** @description Media/images (optional) */ + medias?: string[]; + /** @description CSS selector where content is inserted */ + selector: string; + /** + * Format: date-time + * @description Campaign end time (optional) + */ + timeUntil?: string; + /** @description URL pattern (e.g. regex) where campaign applies */ + urlPattern: string; + }; + campaign_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Optional CSS */ + css?: string; + /** @description HTML content (optional) */ + html?: string; + /** + * @description Position relative to selector + * @default beforeend + * @enum {string} + */ + insertHtml: "afterbegin" | "beforeend" | "afterend" | "beforebegin" | "replace"; + /** @description Optional JavaScript */ + javascript?: string; + /** @description Media/images (optional) */ + medias?: string[]; + /** @description CSS selector where content is inserted */ + selector: string; + /** + * Format: date-time + * @description Campaign end time (optional) + */ + timeUntil?: string; + /** @description URL pattern (e.g. regex) where campaign applies */ + urlPattern: string; + }; + campaigns: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Campaign list (optional) */ + campaigns?: string[]; + /** + * @description Campaigns enabled + * @default true + */ + enable: boolean; + /** @description Unique ID (e.g. campaigns-global) */ + id: string; + }; + campaigns_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Campaign list (optional) */ + campaigns?: string[]; + /** + * @description Campaigns enabled + * @default true + */ + enable: boolean; + /** @description Unique ID (e.g. campaigns-global) */ + id: string; + }; + content_layout: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** + * @description Align items for row 1 + * @default stretch + * @enum {string} + */ + row1AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 1 (references to markdown, headline, image, etc.) */ + row1Content?: string[]; + /** + * @description Justify content for row 1 + * @default start + * @enum {string} + */ + row1JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row2AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 2 */ + row2Content?: string[]; + /** + * @description Row 2: justify content + * @default start + * @enum {string} + */ + row2JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row3AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 3 */ + row3Content?: string[]; + /** + * @description Row 3: justify content + * @default start + * @enum {string} + */ + row3JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + }; + content_layout_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** + * @description Align items for row 1 + * @default stretch + * @enum {string} + */ + row1AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 1 (references to markdown, headline, image, etc.) */ + row1Content?: string[]; + /** + * @description Justify content for row 1 + * @default start + * @enum {string} + */ + row1JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row2AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 2 */ + row2Content?: string[]; + /** + * @description Row 2: justify content + * @default start + * @enum {string} + */ + row2JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row3AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 3 */ + row3Content?: string[]; + /** + * @description Row 3: justify content + * @default start + * @enum {string} + */ + row3JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + }; + demo: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description html – HTML content */ + bodyHtml?: string; + /** @description markdown – Markdown content */ + bodyMarkdown?: string; + /** @description richtext – rich text editor */ + bodyRichtext?: string; + /** @description textOrRef – inline text or file:path to load from file */ + bodyTextOrRef?: string; + /** @description number – floating point */ + count?: number; + /** @description string + widget: code, codeLanguage: css – code field with syntax highlighting and copy */ + css?: string; + /** @description boolean – checkbox, true/false */ + isActive?: boolean; + /** @description array – items type string (list of strings) */ + labels?: string[]; + /** @description object – image asset with src and alt text */ + mainImage?: string; + /** @description object – fixed sub-fields (key, value) */ + meta?: { + key?: string; + value?: string; + }; + /** + * Format: date-time + * @description datetime – ISO 8601 date-time + */ + publishedAt?: string; + /** @description integer – whole number */ + quantity?: number; + /** @description referenceOrInline – slug ref or inline object (collection must exist) */ + relatedPage?: string | { + /** @description Page headline */ + headline: string; + /** @description Icon identifier (optional) */ + icon?: string; + /** @description Display name in navigation */ + linkName: string; + /** @description Internal page name */ + name: string; + /** + * @description Align items for row 1 + * @default stretch + * @enum {string} + */ + row1AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 1 (references to markdown, headline, image, etc.) */ + row1Content?: string[]; + /** + * @description Justify content for row 1 + * @default start + * @enum {string} + */ + row1JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row2AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 2 */ + row2Content?: string[]; + /** + * @description Row 2: justify content + * @default start + * @enum {string} + */ + row2JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row3AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 3 */ + row3Content?: string[]; + /** + * @description Row 3: justify content + * @default start + * @enum {string} + */ + row3JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** @description Meta description for search engines (optional) */ + seoDescription?: string; + /** + * @description Robots meta directive + * @default index, follow + * @enum {string} + */ + seoMetaRobots: "index, follow" | "noindex, follow" | "index, nofollow" | "noindex, nofollow"; + /** @description SEO page title (browser tab, search results) */ + seoTitle: string; + /** @description URL slug */ + slug: string; + /** @description Optional subheadline */ + subheadline?: string; + /** @description Hero banner at the top */ + topFullwidthBanner?: string; + }; + /** @description array – items type reference (slugs to page collection) */ + relatedPages?: string[]; + /** @description array – items type number */ + scores?: number[]; + /** + * @description string + enum – single-value dropdown (Select) + * @enum {string} + */ + singleSelect?: "A" | "B" | "C"; + /** @description string – single line, optional */ + summary?: string; + /** + * @description multiSelect + enum – checkboxes, value is string[] + * @enum {string} + */ + tags?: "news" | "tutorial" | "announcement"; + /** @description string – single line (required) */ + title: string; + }; + demo_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description html – HTML content */ + bodyHtml?: string; + /** @description markdown – Markdown content */ + bodyMarkdown?: string; + /** @description richtext – rich text editor */ + bodyRichtext?: string; + /** @description textOrRef – inline text or file:path to load from file */ + bodyTextOrRef?: string; + /** @description number – floating point */ + count?: number; + /** @description string + widget: code, codeLanguage: css – code field with syntax highlighting and copy */ + css?: string; + /** @description boolean – checkbox, true/false */ + isActive?: boolean; + /** @description array – items type string (list of strings) */ + labels?: string[]; + /** @description object – image asset with src and alt text */ + mainImage?: string; + /** @description object – fixed sub-fields (key, value) */ + meta?: { + key?: string; + value?: string; + }; + /** + * Format: date-time + * @description datetime – ISO 8601 date-time + */ + publishedAt?: string; + /** @description integer – whole number */ + quantity?: number; + /** @description referenceOrInline – slug ref or inline object (collection must exist) */ + relatedPage?: string | { + /** @description Page headline */ + headline: string; + /** @description Icon identifier (optional) */ + icon?: string; + /** @description Display name in navigation */ + linkName: string; + /** @description Internal page name */ + name: string; + /** + * @description Align items for row 1 + * @default stretch + * @enum {string} + */ + row1AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 1 (references to markdown, headline, image, etc.) */ + row1Content?: string[]; + /** + * @description Justify content for row 1 + * @default start + * @enum {string} + */ + row1JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row2AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 2 */ + row2Content?: string[]; + /** + * @description Row 2: justify content + * @default start + * @enum {string} + */ + row2JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row3AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 3 */ + row3Content?: string[]; + /** + * @description Row 3: justify content + * @default start + * @enum {string} + */ + row3JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** @description Meta description for search engines (optional) */ + seoDescription?: string; + /** + * @description Robots meta directive + * @default index, follow + * @enum {string} + */ + seoMetaRobots: "index, follow" | "noindex, follow" | "index, nofollow" | "noindex, nofollow"; + /** @description SEO page title (browser tab, search results) */ + seoTitle: string; + /** @description URL slug */ + slug: string; + /** @description Optional subheadline */ + subheadline?: string; + /** @description Hero banner at the top */ + topFullwidthBanner?: string; + }; + /** @description array – items type reference (slugs to page collection) */ + relatedPages?: string[]; + /** @description array – items type number */ + scores?: number[]; + /** + * @description string + enum – single-value dropdown (Select) + * @enum {string} + */ + singleSelect?: "A" | "B" | "C"; + /** @description string – single line, optional */ + summary?: string; + /** + * @description multiSelect + enum – checkboxes, value is string[] + * @enum {string} + */ + tags?: "news" | "tutorial" | "announcement"; + /** @description string – single line (required) */ + title: string; + }; + footer: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Unique footer ID (e.g. footer-main) */ + id: string; + /** + * @description Align items for row 1 + * @default stretch + * @enum {string} + */ + row1AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 1 (references to markdown, headline, image, etc.) */ + row1Content?: string[]; + /** + * @description Justify content for row 1 + * @default start + * @enum {string} + */ + row1JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row2AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 2 */ + row2Content?: string[]; + /** + * @description Row 2: justify content + * @default start + * @enum {string} + */ + row2JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row3AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 3 */ + row3Content?: string[]; + /** + * @description Row 3: justify content + * @default start + * @enum {string} + */ + row3JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + }; + footer_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Unique footer ID (e.g. footer-main) */ + id: string; + /** + * @description Align items for row 1 + * @default stretch + * @enum {string} + */ + row1AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 1 (references to markdown, headline, image, etc.) */ + row1Content?: string[]; + /** + * @description Justify content for row 1 + * @default start + * @enum {string} + */ + row1JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row2AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 2 */ + row2Content?: string[]; + /** + * @description Row 2: justify content + * @default start + * @enum {string} + */ + row2JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row3AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 3 */ + row3Content?: string[]; + /** + * @description Row 3: justify content + * @default start + * @enum {string} + */ + row3JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + }; + fullwidth_banner: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Banner headline */ + headline?: string; + /** @description Banner image (optional) */ + image?: string; + /** @description Internal name */ + name: string; + /** @description Optional subheadline */ + subheadline?: string; + /** @description Banner body text (optional) */ + text?: string; + /** + * @description Color variant + * @default light + * @enum {string} + */ + variant: "dark" | "light"; + }; + fullwidth_banner_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Banner headline */ + headline?: string; + /** @description Banner image (optional) */ + image?: string; + /** @description Internal name */ + name: string; + /** @description Optional subheadline */ + subheadline?: string; + /** @description Banner body text (optional) */ + text?: string; + /** + * @description Color variant + * @default light + * @enum {string} + */ + variant: "dark" | "light"; + }; + headline: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** + * @description Text alignment + * @default left + * @enum {string} + */ + align: "left" | "center" | "right"; + /** @description Internal key (optional) */ + internal?: string; + /** @description Column width (grid) */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + /** + * @description HTML tag (h1–h6). Default: h2 + * @default h2 + * @enum {string} + */ + tag: "h1" | "h2" | "h3" | "h4" | "h5" | "h6"; + /** @description Headline text */ + text: string; + }; + headline_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** + * @description Text alignment + * @default left + * @enum {string} + */ + align: "left" | "center" | "right"; + /** @description Internal key (optional) */ + internal?: string; + /** @description Column width (grid) */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + /** + * @description HTML tag (h1–h6). Default: h2 + * @default h2 + * @enum {string} + */ + tag: "h1" | "h2" | "h3" | "h4" | "h5" | "h6"; + /** @description Headline text */ + text: string; + }; + html: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description HTML content (safely embedded) */ + html: string; + /** @description Unique component ID */ + id: string; + /** @description Column width (grid). Optional. */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + }; + html_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description HTML content (safely embedded) */ + html: string; + /** @description Unique component ID */ + id: string; + /** @description Column width (grid). Optional. */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + }; + iframe: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Description/content for iframe */ + content: string; + /** @description Iframe URL or embed code */ + iframe: string; + /** @description Column width (grid). Optional. */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + /** @description Internal component name */ + name: string; + /** @description Optional overlay image */ + overlayImage?: string; + }; + iframe_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Description/content for iframe */ + content: string; + /** @description Iframe URL or embed code */ + iframe: string; + /** @description Column width (grid). Optional. */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + /** @description Internal component name */ + name: string; + /** @description Optional overlay image */ + overlayImage?: string; + }; + image: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** + * @description Aspect ratio + * @default 4:3 + * @enum {string} + */ + aspectRatio: "1:1" | "4:3" | "3:2" | "16:9" | "21:9" | "2:3" | "3:4"; + /** @description Image caption */ + caption?: string; + /** @description Image asset */ + img: string; + /** @description Column width (grid) */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + /** @description Max width in px */ + maxWidth?: number; + /** @description Internal component name */ + name: string; + }; + image_gallery: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Gallery description (optional) */ + description?: string; + /** @description Bilder (Asset-URL + optionale Bildunterschrift) */ + images: string[]; + /** @description Column width (grid). Optional. */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + /** @description Internal gallery name */ + name: string; + }; + image_gallery_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Gallery description (optional) */ + description?: string; + /** @description Bilder (Asset-URL + optionale Bildunterschrift) */ + images: string[]; + /** @description Column width (grid). Optional. */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + /** @description Internal gallery name */ + name: string; + }; + image_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** + * @description Aspect ratio + * @default 4:3 + * @enum {string} + */ + aspectRatio: "1:1" | "4:3" | "3:2" | "16:9" | "21:9" | "2:3" | "3:4"; + /** @description Image caption */ + caption?: string; + /** @description Image asset */ + img: string; + /** @description Column width (grid) */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + /** @description Max width in px */ + maxWidth?: number; + /** @description Internal component name */ + name: string; + }; + link: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Alt text (e.g. for icon). Not used in app. */ + alt?: string; + /** @description Author (e.g. for sources). Not used in app. */ + author?: string; + /** @description Color (e.g. for buttons). Not used in app. */ + color?: string; + /** @description Date (e.g. publication). Not used in app. */ + date?: string; + /** @description Optional description. Not used in app. */ + description?: string; + /** + * @description External link. Not used in app. + * @default false + */ + external: boolean; + /** @description Icon identifier (e.g. Iconify). Used for social links; fallback 'mdi:link'. */ + icon?: string; + /** @description Internal key. Not used in app. */ + internal?: string; + /** @description Display name/label. Used in navigation and LinkListBlock. */ + linkName: string; + /** @description Internal link name. Fallback for linkName (e.g. in layout). */ + name?: string; + /** + * @description Open in new tab (LinkListBlock: target=_blank, rel=noopener noreferrer). + * @default false + */ + newTab: boolean; + /** + * @description Show text. Not used in app. + * @default true + */ + showText: boolean; + /** @description Source. Not used in app. */ + source?: string; + /** @description Target URL (href). Used everywhere: navigation, social, LinkListBlock. */ + url: string; + }; + link_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Alt text (e.g. for icon). Not used in app. */ + alt?: string; + /** @description Author (e.g. for sources). Not used in app. */ + author?: string; + /** @description Color (e.g. for buttons). Not used in app. */ + color?: string; + /** @description Date (e.g. publication). Not used in app. */ + date?: string; + /** @description Optional description. Not used in app. */ + description?: string; + /** + * @description External link. Not used in app. + * @default false + */ + external: boolean; + /** @description Icon identifier (e.g. Iconify). Used for social links; fallback 'mdi:link'. */ + icon?: string; + /** @description Internal key. Not used in app. */ + internal?: string; + /** @description Display name/label. Used in navigation and LinkListBlock. */ + linkName: string; + /** @description Internal link name. Fallback for linkName (e.g. in layout). */ + name?: string; + /** + * @description Open in new tab (LinkListBlock: target=_blank, rel=noopener noreferrer). + * @default false + */ + newTab: boolean; + /** + * @description Show text. Not used in app. + * @default true + */ + showText: boolean; + /** @description Source. Not used in app. */ + source?: string; + /** @description Target URL (href). Used everywhere: navigation, social, LinkListBlock. */ + url: string; + }; + link_list: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Link list headline */ + headline: string; + /** @description Links (references to link) */ + links: string[]; + }; + link_list_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Link list headline */ + headline: string; + /** @description Links (references to link) */ + links: string[]; + }; + list: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Internal key (optional) */ + internal?: string; + /** @description List entries */ + item: string[]; + }; + list_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Internal key (optional) */ + internal?: string; + /** @description List entries */ + item: string[]; + }; + markdown: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** + * @description Text alignment + * @default left + * @enum {string} + */ + alignment: "left" | "center" | "right"; + /** @description Markdown/body: inline text or file reference (e.g. file:slug.content.md) */ + content?: string; + /** @description Column width (grid). Optional. */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + /** @description Internal component name */ + name: string; + }; + markdown_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** + * @description Text alignment + * @default left + * @enum {string} + */ + alignment: "left" | "center" | "right"; + /** @description Markdown/body: inline text or file reference (e.g. file:slug.content.md) */ + content?: string; + /** @description Column width (grid). Optional. */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + /** @description Internal component name */ + name: string; + }; + navgroup: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Display label of the group */ + label: string; + /** @description Sub-links shown in the dropdown */ + links: string[]; + /** @description Optional URL for the group label itself */ + url?: string; + }; + navgroup_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Display label of the group */ + label: string; + /** @description Sub-links shown in the dropdown */ + links: string[]; + /** @description Optional URL for the group label itself */ + url?: string; + }; + navigation: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Internal key (e.g. navigation-header, navigation-footer) */ + internal: string; + /** @description Navigation entries (references to link, page or post) */ + links: string[]; + /** @description Display name of navigation */ + name: string; + }; + navigation_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Internal key (e.g. navigation-header, navigation-footer) */ + internal: string; + /** @description Navigation entries (references to link, page or post) */ + links: string[]; + /** @description Display name of navigation */ + name: string; + }; + opnform: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description OpnForm instance origin without trailing slash (default: https://opnform.pm86.de) */ + baseUrl?: string; + /** @description Form slug from OpnForm URL path, e.g. contact-form-ojxxgb */ + formId: string; + /** @description Unique component ID (internal) */ + id: string; + /** @description Accessible title for the iframe */ + iframeTitle?: string; + /** @description Column width (grid). Optional. */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + }; + opnform_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description OpnForm instance origin without trailing slash (default: https://opnform.pm86.de) */ + baseUrl?: string; + /** @description Form slug from OpnForm URL path, e.g. contact-form-ojxxgb */ + formId: string; + /** @description Unique component ID (internal) */ + id: string; + /** @description Accessible title for the iframe */ + iframeTitle?: string; + /** @description Column width (grid). Optional. */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + }; + organisation: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Badge label for this organisation (exactly one) */ + badge?: string; + /** @description Short description of the organisation (Markdown) */ + description?: string; + /** @description Optional link (website, contact, etc.) */ + link?: string; + /** @description Optional logo image */ + logo?: string; + /** @description Organisation name */ + name: string; + }; + organisation_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Badge label for this organisation (exactly one) */ + badge?: string; + /** @description Short description of the organisation (Markdown) */ + description?: string; + /** @description Optional link (website, contact, etc.) */ + link?: string; + /** @description Optional logo image */ + logo?: string; + /** @description Organisation name */ + name: string; + }; + organisations: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Optional CTA link in the dashed card (label from link.linkName) */ + addOrganisationLink?: string; + /** @description Optional markdown body for the dashed CTA card (no link here; use addOrganisationLink) */ + addOrganisationMarkdown?: string; + /** @description Optional section title shown above the organisation list */ + addOrganisationTitle?: string; + /** @description Restrict which badges may be assigned to organisations in this block */ + allowedBadges?: string[]; + /** @description Optional intro text (Markdown) */ + description?: string; + /** @description Optional block headline */ + headline?: string; + /** @description List of organisations */ + organisations?: string[]; + /** + * @description Darstellung: default (große Karten) oder compact (kompaktere Zeilenkarten) + * @default default + * @enum {string} + */ + presentation: "default" | "compact"; + }; + organisations_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Optional CTA link in the dashed card (label from link.linkName) */ + addOrganisationLink?: string; + /** @description Optional markdown body for the dashed CTA card (no link here; use addOrganisationLink) */ + addOrganisationMarkdown?: string; + /** @description Optional section title shown above the organisation list */ + addOrganisationTitle?: string; + /** @description Restrict which badges may be assigned to organisations in this block */ + allowedBadges?: string[]; + /** @description Optional intro text (Markdown) */ + description?: string; + /** @description Optional block headline */ + headline?: string; + /** @description List of organisations */ + organisations?: string[]; + /** + * @description Darstellung: default (große Karten) oder compact (kompaktere Zeilenkarten) + * @default default + * @enum {string} + */ + presentation: "default" | "compact"; + }; + page: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Page headline */ + headline: string; + /** @description Icon identifier (optional) */ + icon?: string; + /** @description Display name in navigation */ + linkName: string; + /** @description Internal page name */ + name: string; + /** + * @description Align items for row 1 + * @default stretch + * @enum {string} + */ + row1AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 1 (references to markdown, headline, image, etc.) */ + row1Content?: string[]; + /** + * @description Justify content for row 1 + * @default start + * @enum {string} + */ + row1JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row2AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 2 */ + row2Content?: string[]; + /** + * @description Row 2: justify content + * @default start + * @enum {string} + */ + row2JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row3AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 3 */ + row3Content?: string[]; + /** + * @description Row 3: justify content + * @default start + * @enum {string} + */ + row3JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** @description Meta description for search engines (optional) */ + seoDescription?: string; + /** + * @description Robots meta directive + * @default index, follow + * @enum {string} + */ + seoMetaRobots: "index, follow" | "noindex, follow" | "index, nofollow" | "noindex, nofollow"; + /** @description SEO page title (browser tab, search results) */ + seoTitle: string; + /** @description URL slug */ + slug: string; + /** @description Optional subheadline */ + subheadline?: string; + /** @description Hero banner at the top */ + topFullwidthBanner?: string; + }; + page_config: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Headline for blog overview page (optional) */ + blogPostsPageHeadline?: string; + /** @description Subheadline for blog overview page (optional) */ + blogPostsPageSubHeadline?: string; + /** @description Headline for tag page (optional) */ + blogTagPageHeadline?: string; + /** @description Footer text (e.g. copyright) */ + footerText1: string; + /** @description Logo image */ + logo: string; + /** @description HTML/JS snippet injected below each post. Use {{PAGE_ID}}, {{PAGE_URL}}, {{PAGE_TITLE}} as placeholders. */ + postCommentSlot?: string; + /** @description Default meta description */ + seoDescription: string; + /** @description Default SEO title for website */ + seoTitle: string; + /** @description Site name */ + siteName: string; + /** @description Website URL */ + website: string; + }; + page_config_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Headline for blog overview page (optional) */ + blogPostsPageHeadline?: string; + /** @description Subheadline for blog overview page (optional) */ + blogPostsPageSubHeadline?: string; + /** @description Headline for tag page (optional) */ + blogTagPageHeadline?: string; + /** @description Footer text (e.g. copyright) */ + footerText1: string; + /** @description Logo image */ + logo: string; + /** @description HTML/JS snippet injected below each post. Use {{PAGE_ID}}, {{PAGE_URL}}, {{PAGE_TITLE}} as placeholders. */ + postCommentSlot?: string; + /** @description Default meta description */ + seoDescription: string; + /** @description Default SEO title for website */ + seoTitle: string; + /** @description Site name */ + siteName: string; + /** @description Website URL */ + website: string; + }; + page_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Page headline */ + headline: string; + /** @description Icon identifier (optional) */ + icon?: string; + /** @description Display name in navigation */ + linkName: string; + /** @description Internal page name */ + name: string; + /** + * @description Align items for row 1 + * @default stretch + * @enum {string} + */ + row1AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 1 (references to markdown, headline, image, etc.) */ + row1Content?: string[]; + /** + * @description Justify content for row 1 + * @default start + * @enum {string} + */ + row1JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row2AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 2 */ + row2Content?: string[]; + /** + * @description Row 2: justify content + * @default start + * @enum {string} + */ + row2JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row3AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 3 */ + row3Content?: string[]; + /** + * @description Row 3: justify content + * @default start + * @enum {string} + */ + row3JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** @description Meta description for search engines (optional) */ + seoDescription?: string; + /** + * @description Robots meta directive + * @default index, follow + * @enum {string} + */ + seoMetaRobots: "index, follow" | "noindex, follow" | "index, nofollow" | "noindex, nofollow"; + /** @description SEO page title (browser tab, search results) */ + seoTitle: string; + /** @description URL slug */ + slug: string; + /** @description Optional subheadline */ + subheadline?: string; + /** @description Hero banner at the top */ + topFullwidthBanner?: string; + }; + post: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Post body (Markdown) */ + content: string; + /** Format: date-time */ + readonly created?: string; + /** + * Format: date-time + * @description Event date and time + */ + eventDate?: string; + /** @description Event location */ + eventLocation?: { + /** @description Latitude (optional, for map) */ + lat?: number; + /** @description Longitude (optional, for map) */ + lng?: number; + /** @description Address / description (e.g. Town hall Schleusingen) */ + text?: string; + }; + /** @description Short summary for previews */ + excerpt?: string; + /** @description Post headline */ + headline: string; + /** + * @description Hide this post from all listing pages (still accessible via direct URL) + * @default false + */ + hideFromListing: boolean; + /** @description Optional icon identifier */ + icon?: string; + /** + * @description Mark post as important + * @default false + */ + important: boolean; + /** + * @description This post is an event + * @default false + */ + isEvent: boolean; + /** @description Display name (e.g. in navigation or link lists) */ + linkName: string; + /** @description Featured image */ + postImage?: string; + /** @description Associated tags */ + postTag?: string[]; + /** + * @description Align items for row 1 + * @default stretch + * @enum {string} + */ + row1AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 1 (references to markdown, headline, image, etc.) */ + row1Content?: string[]; + /** + * @description Justify content for row 1 + * @default start + * @enum {string} + */ + row1JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row2AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 2 */ + row2Content?: string[]; + /** + * @description Row 2: justify content + * @default start + * @enum {string} + */ + row2JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row3AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 3 */ + row3Content?: string[]; + /** + * @description Row 3: justify content + * @default start + * @enum {string} + */ + row3JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** @description Meta description for search engines (optional) */ + seoDescription?: string; + /** + * @description Robots meta directive + * @default index, follow + * @enum {string} + */ + seoMetaRobots: "index, follow" | "noindex, follow" | "index, nofollow" | "noindex, nofollow"; + /** @description SEO page title (browser tab, search results) */ + seoTitle: string; + /** + * @description Show comment section (default: true) + * @default true + */ + showCommentSection: boolean; + /** @description URL slug (e.g. demo-260325-suhl-regionalplan) */ + slug: string; + /** @description Optional subheadline below headline */ + subheadline?: string; + }; + post_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Post body (Markdown) */ + content: string; + /** + * Format: date-time + * @description Event date and time + */ + eventDate?: string; + /** @description Event location */ + eventLocation?: { + /** @description Latitude (optional, for map) */ + lat?: number; + /** @description Longitude (optional, for map) */ + lng?: number; + /** @description Address / description (e.g. Town hall Schleusingen) */ + text?: string; + }; + /** @description Short summary for previews */ + excerpt?: string; + /** @description Post headline */ + headline: string; + /** + * @description Hide this post from all listing pages (still accessible via direct URL) + * @default false + */ + hideFromListing: boolean; + /** @description Optional icon identifier */ + icon?: string; + /** + * @description Mark post as important + * @default false + */ + important: boolean; + /** + * @description This post is an event + * @default false + */ + isEvent: boolean; + /** @description Display name (e.g. in navigation or link lists) */ + linkName: string; + /** @description Featured image */ + postImage?: string; + /** @description Associated tags */ + postTag?: string[]; + /** + * @description Align items for row 1 + * @default stretch + * @enum {string} + */ + row1AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 1 (references to markdown, headline, image, etc.) */ + row1Content?: string[]; + /** + * @description Justify content for row 1 + * @default start + * @enum {string} + */ + row1JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row2AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 2 */ + row2Content?: string[]; + /** + * @description Row 2: justify content + * @default start + * @enum {string} + */ + row2JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row3AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 3 */ + row3Content?: string[]; + /** + * @description Row 3: justify content + * @default start + * @enum {string} + */ + row3JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** @description Meta description for search engines (optional) */ + seoDescription?: string; + /** + * @description Robots meta directive + * @default index, follow + * @enum {string} + */ + seoMetaRobots: "index, follow" | "noindex, follow" | "index, nofollow" | "noindex, nofollow"; + /** @description SEO page title (browser tab, search results) */ + seoTitle: string; + /** + * @description Show comment section (default: true) + * @default true + */ + showCommentSection: boolean; + /** @description URL slug (e.g. demo-260325-suhl-regionalplan) */ + slug: string; + /** @description Optional subheadline below headline */ + subheadline?: string; + }; + post_overview: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** + * @description Show all posts; if false, use filterByTag or posts + * @default false + */ + allPosts: boolean; + /** + * @description Display as cards or list (optional) + * @enum {string} + */ + design?: "cards" | "list"; + /** @description Only posts with these tags (optional) */ + filterByTag?: string[]; + /** @description Headline */ + headline: string; + /** @description Unique post overview ID */ + id: string; + /** @description Column width (grid). Optional. */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + /** @description Max. number of displayed entries (optional) */ + numberItems?: number; + /** @description Fixed list of posts when not allPosts (optional) */ + posts?: string[]; + /** + * @description Align items for row 1 + * @default stretch + * @enum {string} + */ + row1AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 1 (references to markdown, headline, image, etc.) */ + row1Content?: string[]; + /** + * @description Justify content for row 1 + * @default start + * @enum {string} + */ + row1JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row2AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 2 */ + row2Content?: string[]; + /** + * @description Row 2: justify content + * @default start + * @enum {string} + */ + row2JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row3AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 3 */ + row3Content?: string[]; + /** + * @description Row 3: justify content + * @default start + * @enum {string} + */ + row3JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** @description Meta description for search engines (optional) */ + seoDescription?: string; + /** + * @description Robots meta directive + * @default index, follow + * @enum {string} + */ + seoMetaRobots: "index, follow" | "noindex, follow" | "index, nofollow" | "noindex, nofollow"; + /** @description SEO page title (browser tab, search results) */ + seoTitle: string; + /** @description Intro text (optional) */ + text?: string; + }; + post_overview_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** + * @description Show all posts; if false, use filterByTag or posts + * @default false + */ + allPosts: boolean; + /** + * @description Display as cards or list (optional) + * @enum {string} + */ + design?: "cards" | "list"; + /** @description Only posts with these tags (optional) */ + filterByTag?: string[]; + /** @description Headline */ + headline: string; + /** @description Unique post overview ID */ + id: string; + /** @description Column width (grid). Optional. */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + /** @description Max. number of displayed entries (optional) */ + numberItems?: number; + /** @description Fixed list of posts when not allPosts (optional) */ + posts?: string[]; + /** + * @description Align items for row 1 + * @default stretch + * @enum {string} + */ + row1AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 1 (references to markdown, headline, image, etc.) */ + row1Content?: string[]; + /** + * @description Justify content for row 1 + * @default start + * @enum {string} + */ + row1JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row2AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 2 */ + row2Content?: string[]; + /** + * @description Row 2: justify content + * @default start + * @enum {string} + */ + row2JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** + * @default stretch + * @enum {string} + */ + row3AlignItems: "start" | "end" | "center" | "baseline" | "stretch"; + /** @description Content components for row 3 */ + row3Content?: string[]; + /** + * @description Row 3: justify content + * @default start + * @enum {string} + */ + row3JustifyContent: "start" | "end" | "center" | "between" | "around" | "evenly"; + /** @description Meta description for search engines (optional) */ + seoDescription?: string; + /** + * @description Robots meta directive + * @default index, follow + * @enum {string} + */ + seoMetaRobots: "index, follow" | "noindex, follow" | "index, nofollow" | "noindex, nofollow"; + /** @description SEO page title (browser tab, search results) */ + seoTitle: string; + /** @description Intro text (optional) */ + text?: string; + }; + product: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** + * @description Product category + * @enum {string} + */ + category: "electronics" | "clothing" | "books" | "food" | "other"; + /** + * Format: date-time + * @description Auto-set on create + */ + readonly created_at?: string; + /** @description Detailed product description (optional) */ + description?: string; + /** @description Product image URLs 1–10 (optional) */ + images?: string[]; + /** + * @description Whether the product is in stock + * @default true + */ + in_stock: boolean; + /** @description Price in EUR */ + price: number; + /** @description Average customer rating 0–5, null if unrated (optional) */ + rating?: number | null; + /** @description Stock Keeping Unit (e.g. EL-1234, BOOK-00042) */ + sku: string; + /** @description Product name */ + title: string; + }; + product_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** + * @description Product category + * @enum {string} + */ + category: "electronics" | "clothing" | "books" | "food" | "other"; + /** @description Detailed product description (optional) */ + description?: string; + /** @description Product image URLs 1–10 (optional) */ + images?: string[]; + /** + * @description Whether the product is in stock + * @default true + */ + in_stock: boolean; + /** @description Price in EUR */ + price: number; + /** @description Average customer rating 0–5, null if unrated (optional) */ + rating?: number | null; + /** @description Stock Keeping Unit (e.g. EL-1234, BOOK-00042) */ + sku: string; + /** @description Product name */ + title: string; + }; + quote: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Author or source of quote */ + author: string; + /** @description Column width (grid). Optional. */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + /** @description Quote text */ + quote: string; + /** + * @description Quote alignment + * @default left + * @enum {string} + */ + variant: "left" | "right"; + }; + quote_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Author or source of quote */ + author: string; + /** @description Column width (grid). Optional. */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + /** @description Quote text */ + quote: string; + /** + * @description Quote alignment + * @default left + * @enum {string} + */ + variant: "left" | "right"; + }; + searchable_text: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Description (optional) */ + description?: string; + /** @description Unique component ID */ + id: string; + /** @description Column width (grid). Optional. */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + /** @description Only search content with these tags (optional) */ + tagWhitelist?: string[]; + /** @description Searchable text fragments (references to text_fragment) */ + textFragments: string[]; + /** @description Search component title (optional) */ + title?: string; + }; + searchable_text_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Description (optional) */ + description?: string; + /** @description Unique component ID */ + id: string; + /** @description Column width (grid). Optional. */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + /** @description Only search content with these tags (optional) */ + tagWhitelist?: string[]; + /** @description Searchable text fragments (references to text_fragment) */ + textFragments: string[]; + /** @description Search component title (optional) */ + title?: string; + }; + seo: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Meta description for search engines (optional) */ + seoDescription?: string; + /** + * @description Robots meta directive + * @default index, follow + * @enum {string} + */ + seoMetaRobots: "index, follow" | "noindex, follow" | "index, nofollow" | "noindex, nofollow"; + /** @description SEO page title (browser tab, search results) */ + seoTitle: string; + }; + seo_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Meta description for search engines (optional) */ + seoDescription?: string; + /** + * @description Robots meta directive + * @default index, follow + * @enum {string} + */ + seoMetaRobots: "index, follow" | "noindex, follow" | "index, nofollow" | "noindex, nofollow"; + /** @description SEO page title (browser tab, search results) */ + seoTitle: string; + }; + tag: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Optional pill color (CSS, e.g. #2d5a27 or rgb()). Admin: color picker + text field. */ + color?: string; + /** @description Optional Iconify icon id (e.g. mdi:map-marker, same as link.icon). */ + icon?: string; + /** @description Tag name (e.g. politik, termin). Must be unique. */ + name: string; + }; + tag_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Optional pill color (CSS, e.g. #2d5a27 or rgb()). Admin: color picker + text field. */ + color?: string; + /** @description Optional Iconify icon id (e.g. mdi:map-marker, same as link.icon). */ + icon?: string; + /** @description Tag name (e.g. politik, termin). Must be unique. */ + name: string; + }; + text_fragment: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Unique fragment ID */ + id: string; + /** @description Tags for categorisation (optional) */ + tags?: string[]; + /** @description Searchable text content */ + text: string; + /** @description Text fragment title */ + title: string; + }; + text_fragment_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Unique fragment ID */ + id: string; + /** @description Tags for categorisation (optional) */ + tags?: string[]; + /** @description Searchable text content */ + text: string; + /** @description Text fragment title */ + title: string; + }; + top_banner: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Unique ID */ + id: string; + /** @description Banner text (e.g. notice at top of page) */ + text: string; + }; + top_banner_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Unique ID */ + id: string; + /** @description Banner text (e.g. notice at top of page) */ + text: string; + }; + translation_bundle: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Map: translation key → text (e.g. searchable_text_help, footer_copyright) */ + strings: Record; + }; + translation_bundle_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Map: translation key → text (e.g. searchable_text_help, footer_copyright) */ + strings: Record; + }; + youtube_video: { + /** @description Entry identifier (filename) */ + readonly _slug?: string; + /** @description Short description (optional) */ + description?: string; + /** @description Unique ID (optional; otherwise _slug is used) */ + id?: string; + /** @description Column width (grid). Optional. */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + /** @description URL params (e.g. start=30, autoplay=1). Optional. */ + params?: string; + /** @description Video title (optional) */ + title?: string; + /** @description YouTube video ID (from URL ?v=VIDEO_ID) */ + youtubeId: string; + }; + youtube_video_input: { + /** @description URL slug (used as filename) */ + _slug: string; + /** @description Short description (optional) */ + description?: string; + /** @description Unique ID (optional; otherwise _slug is used) */ + id?: string; + /** @description Column width (grid). Optional. */ + layout?: { + /** + * @description Breakout layout (full width) + * @default false + */ + breakout: boolean; + /** + * @description Width on desktop (optional) + * @enum {string} + */ + desktop?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Width on mobile (1–12) + * @default 12 + * @enum {string} + */ + mobile: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + /** + * @description Space below (rem) + * @default 0 + * @enum {number} + */ + spaceBottom: 0 | 0.5 | 1 | 1.5 | 2; + /** + * @description Width on tablet (optional) + * @enum {string} + */ + tablet?: "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12"; + }; + /** @description URL params (e.g. start=30, autoplay=1). Optional. */ + params?: string; + /** @description Video title (optional) */ + title?: string; + /** @description YouTube video ID (from URL ?v=VIDEO_ID) */ + youtubeId: string; + }; + }; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; +} +export type $defs = Record; +export interface operations { + listAssets: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of assets */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + assets?: components["schemas"]["Asset"][]; + total?: number; + }; + }; + }; + }; + }; + uploadAsset: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "multipart/form-data": { + /** + * Format: binary + * @description Image file to upload + */ + file: string; + }; + }; + }; + responses: { + /** @description Asset uploaded */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Asset"]; + }; + }; + /** @description Invalid file or disallowed extension */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Missing or invalid API key */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Asset with this filename already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getAsset: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Asset filename (e.g. hero.jpg) */ + filename: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Image file */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "image/avif": string; + "image/gif": string; + "image/jpeg": string; + "image/png": string; + "image/svg+xml": string; + "image/webp": string; + }; + }; + /** @description Invalid filename */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Asset not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteAsset: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Asset filename (e.g. hero.jpg) */ + filename: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Asset deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Missing or invalid API key */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Asset not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + listCollections: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of registered content type collections */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + collections?: { + extends?: string | null; + field_count?: number; + name?: string; + }[]; + }; + }; + }; + }; + }; + getBadgeSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getCalendarSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getCalendarItemSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getCampaignSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getCampaignsSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getContentLayoutSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getDemoSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getFooterSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getFullwidthBannerSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getHeadlineSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getHtmlSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getIframeSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getImageSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getImageGallerySchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getLinkSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getLinkListSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getListSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getMarkdownSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getNavgroupSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getNavigationSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getOpnformSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getOrganisationSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getOrganisationsSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getPageSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getPageConfigSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getPostSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getPostOverviewSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getProductSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getQuoteSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getSearchableTextSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getSeoSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getTagSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getTextFragmentSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getTopBannerSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getTranslationBundleSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getYoutubeVideoSchema: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Schema definition */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Collection not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + listBadge: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by name */ + name?: string; + /** @description Filter by label */ + label?: string; + /** @description Filter by color */ + color?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["badge"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createBadge: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["badge_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["badge"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getBadge: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["badge"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateBadge: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["badge"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["badge"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteBadge: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getBadgeReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listCalendar: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by items */ + items?: string; + /** @description Filter by fromPost */ + fromPost?: boolean; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["calendar"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createCalendar: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["calendar_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["calendar"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getCalendar: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["calendar"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateCalendar: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["calendar"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["calendar"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteCalendar: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getCalendarReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listCalendarItem: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by title */ + title?: string; + /** @description Filter by terminZeit */ + terminZeit?: string; + /** @description Filter by description */ + description?: string; + /** @description Filter by link */ + link?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["calendar_item"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createCalendarItem: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["calendar_item_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["calendar_item"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getCalendarItem: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["calendar_item"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateCalendarItem: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["calendar_item"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["calendar_item"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteCalendarItem: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getCalendarItemReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listCampaign: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by css */ + css?: string; + /** @description Filter by html */ + html?: string; + /** @description Filter by insertHtml */ + insertHtml?: string; + /** @description Filter by javascript */ + javascript?: string; + /** @description Filter by medias */ + medias?: string; + /** @description Filter by selector */ + selector?: string; + /** @description Filter by timeUntil */ + timeUntil?: string; + /** @description Filter by urlPattern */ + urlPattern?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["campaign"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createCampaign: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["campaign_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["campaign"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getCampaign: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["campaign"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateCampaign: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["campaign"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["campaign"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteCampaign: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getCampaignReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listCampaigns: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by id */ + id?: string; + /** @description Filter by enable */ + enable?: boolean; + /** @description Filter by campaigns */ + campaigns?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["campaigns"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createCampaigns: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["campaigns_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["campaigns"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getCampaigns: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["campaigns"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateCampaigns: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["campaigns"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["campaigns"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteCampaigns: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getCampaignsReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listContentLayout: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by row1JustifyContent */ + row1JustifyContent?: string; + /** @description Filter by row1AlignItems */ + row1AlignItems?: string; + /** @description Filter by row1Content */ + row1Content?: string; + /** @description Filter by row2JustifyContent */ + row2JustifyContent?: string; + /** @description Filter by row2AlignItems */ + row2AlignItems?: string; + /** @description Filter by row2Content */ + row2Content?: string; + /** @description Filter by row3JustifyContent */ + row3JustifyContent?: string; + /** @description Filter by row3AlignItems */ + row3AlignItems?: string; + /** @description Filter by row3Content */ + row3Content?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["content_layout"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createContentLayout: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["content_layout_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["content_layout"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getContentLayout: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["content_layout"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateContentLayout: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["content_layout"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["content_layout"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteContentLayout: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getContentLayoutReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listDemo: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by bodyHtml */ + bodyHtml?: string; + /** @description Filter by bodyMarkdown */ + bodyMarkdown?: string; + /** @description Filter by bodyRichtext */ + bodyRichtext?: string; + /** @description Filter by bodyTextOrRef */ + bodyTextOrRef?: string; + /** @description Filter by count */ + count?: number; + /** @description Filter by css */ + css?: string; + /** @description Filter by isActive */ + isActive?: boolean; + /** @description Filter by labels */ + labels?: string; + /** @description Filter by mainImage */ + mainImage?: string; + /** @description Filter by meta */ + meta?: string; + /** @description Filter by publishedAt */ + publishedAt?: string; + /** @description Filter by quantity */ + quantity?: number; + /** @description Filter by relatedPage */ + relatedPage?: string; + /** @description Filter by relatedPages */ + relatedPages?: string; + /** @description Filter by scores */ + scores?: string; + /** @description Filter by singleSelect */ + singleSelect?: string; + /** @description Filter by summary */ + summary?: string; + /** @description Filter by tags */ + tags?: string; + /** @description Filter by title */ + title?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["demo"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createDemo: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["demo_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["demo"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getDemo: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["demo"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateDemo: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["demo"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["demo"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteDemo: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getDemoReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listFooter: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by row1JustifyContent */ + row1JustifyContent?: string; + /** @description Filter by row1AlignItems */ + row1AlignItems?: string; + /** @description Filter by row1Content */ + row1Content?: string; + /** @description Filter by row2JustifyContent */ + row2JustifyContent?: string; + /** @description Filter by row2AlignItems */ + row2AlignItems?: string; + /** @description Filter by row2Content */ + row2Content?: string; + /** @description Filter by row3JustifyContent */ + row3JustifyContent?: string; + /** @description Filter by row3AlignItems */ + row3AlignItems?: string; + /** @description Filter by row3Content */ + row3Content?: string; + /** @description Filter by id */ + id?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["footer"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createFooter: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["footer_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["footer"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getFooter: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["footer"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateFooter: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["footer"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["footer"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteFooter: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getFooterReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listFullwidthBanner: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by headline */ + headline?: string; + /** @description Filter by image */ + image?: string; + /** @description Filter by name */ + name?: string; + /** @description Filter by subheadline */ + subheadline?: string; + /** @description Filter by text */ + text?: string; + /** @description Filter by variant */ + variant?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["fullwidth_banner"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createFullwidthBanner: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["fullwidth_banner_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["fullwidth_banner"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getFullwidthBanner: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["fullwidth_banner"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateFullwidthBanner: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["fullwidth_banner"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["fullwidth_banner"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteFullwidthBanner: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getFullwidthBannerReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listHeadline: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by text */ + text?: string; + /** @description Filter by tag */ + tag?: string; + /** @description Filter by align */ + align?: string; + /** @description Filter by layout */ + layout?: string; + /** @description Filter by internal */ + internal?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["headline"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createHeadline: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["headline_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["headline"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getHeadline: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["headline"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateHeadline: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["headline"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["headline"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteHeadline: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getHeadlineReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listHtml: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by id */ + id?: string; + /** @description Filter by html */ + html?: string; + /** @description Filter by layout */ + layout?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["html"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createHtml: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["html_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["html"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getHtml: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["html"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateHtml: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["html"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["html"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteHtml: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getHtmlReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listIframe: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by content */ + content?: string; + /** @description Filter by iframe */ + iframe?: string; + /** @description Filter by layout */ + layout?: string; + /** @description Filter by name */ + name?: string; + /** @description Filter by overlayImage */ + overlayImage?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["iframe"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createIframe: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["iframe_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["iframe"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getIframe: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["iframe"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateIframe: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["iframe"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["iframe"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteIframe: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getIframeReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listImage: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by aspectRatio */ + aspectRatio?: string; + /** @description Filter by caption */ + caption?: string; + /** @description Filter by img */ + img?: string; + /** @description Filter by layout */ + layout?: string; + /** @description Filter by maxWidth */ + maxWidth?: number; + /** @description Filter by name */ + name?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["image"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createImage: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["image_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["image"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getImage: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["image"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateImage: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["image"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["image"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteImage: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getImageReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listImageGallery: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by description */ + description?: string; + /** @description Filter by images */ + images?: string; + /** @description Filter by layout */ + layout?: string; + /** @description Filter by name */ + name?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["image_gallery"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createImageGallery: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["image_gallery_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["image_gallery"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getImageGallery: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["image_gallery"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateImageGallery: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["image_gallery"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["image_gallery"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteImageGallery: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getImageGalleryReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listLink: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by url */ + url?: string; + /** @description Filter by linkName */ + linkName?: string; + /** @description Filter by name */ + name?: string; + /** @description Filter by newTab */ + newTab?: boolean; + /** @description Filter by icon */ + icon?: string; + /** @description Filter by description */ + description?: string; + /** @description Filter by alt */ + alt?: string; + /** @description Filter by color */ + color?: string; + /** @description Filter by external */ + external?: boolean; + /** @description Filter by internal */ + internal?: string; + /** @description Filter by showText */ + showText?: boolean; + /** @description Filter by author */ + author?: string; + /** @description Filter by date */ + date?: string; + /** @description Filter by source */ + source?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["link"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createLink: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["link_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["link"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getLink: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["link"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateLink: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["link"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["link"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteLink: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getLinkReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listLinkList: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by headline */ + headline?: string; + /** @description Filter by links */ + links?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["link_list"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createLinkList: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["link_list_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["link_list"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getLinkList: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["link_list"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateLinkList: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["link_list"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["link_list"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteLinkList: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getLinkListReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listList: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by item */ + item?: string; + /** @description Filter by internal */ + internal?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["list"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createList: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["list_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["list"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getList: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["list"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateList: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["list"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["list"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteList: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getListReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listMarkdown: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by name */ + name?: string; + /** @description Filter by content */ + content?: string; + /** @description Filter by alignment */ + alignment?: string; + /** @description Filter by layout */ + layout?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["markdown"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createMarkdown: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["markdown_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["markdown"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getMarkdown: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["markdown"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateMarkdown: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["markdown"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["markdown"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteMarkdown: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getMarkdownReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listNavgroup: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by label */ + label?: string; + /** @description Filter by url */ + url?: string; + /** @description Filter by links */ + links?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["navgroup"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createNavgroup: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["navgroup_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["navgroup"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getNavgroup: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["navgroup"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateNavgroup: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["navgroup"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["navgroup"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteNavgroup: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getNavgroupReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listNavigation: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by name */ + name?: string; + /** @description Filter by links */ + links?: string; + /** @description Filter by internal */ + internal?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["navigation"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createNavigation: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["navigation_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["navigation"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getNavigation: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["navigation"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateNavigation: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["navigation"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["navigation"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteNavigation: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getNavigationReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listOpnform: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by id */ + id?: string; + /** @description Filter by formId */ + formId?: string; + /** @description Filter by baseUrl */ + baseUrl?: string; + /** @description Filter by iframeTitle */ + iframeTitle?: string; + /** @description Filter by layout */ + layout?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["opnform"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createOpnform: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["opnform_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["opnform"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getOpnform: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["opnform"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateOpnform: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["opnform"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["opnform"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteOpnform: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getOpnformReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listOrganisation: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by badge */ + badge?: string; + /** @description Filter by description */ + description?: string; + /** @description Filter by link */ + link?: string; + /** @description Filter by logo */ + logo?: string; + /** @description Filter by name */ + name?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["organisation"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createOrganisation: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["organisation_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["organisation"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getOrganisation: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["organisation"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateOrganisation: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["organisation"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["organisation"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteOrganisation: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getOrganisationReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listOrganisations: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by headline */ + headline?: string; + /** @description Filter by description */ + description?: string; + /** @description Filter by presentation */ + presentation?: string; + /** @description Filter by addOrganisationTitle */ + addOrganisationTitle?: string; + /** @description Filter by addOrganisationMarkdown */ + addOrganisationMarkdown?: string; + /** @description Filter by addOrganisationLink */ + addOrganisationLink?: string; + /** @description Filter by allowedBadges */ + allowedBadges?: string; + /** @description Filter by organisations */ + organisations?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["organisations"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createOrganisations: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["organisations_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["organisations"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getOrganisations: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["organisations"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateOrganisations: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["organisations"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["organisations"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteOrganisations: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getOrganisationsReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listPage: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by row1JustifyContent */ + row1JustifyContent?: string; + /** @description Filter by row1AlignItems */ + row1AlignItems?: string; + /** @description Filter by row1Content */ + row1Content?: string; + /** @description Filter by row2JustifyContent */ + row2JustifyContent?: string; + /** @description Filter by row2AlignItems */ + row2AlignItems?: string; + /** @description Filter by row2Content */ + row2Content?: string; + /** @description Filter by row3JustifyContent */ + row3JustifyContent?: string; + /** @description Filter by row3AlignItems */ + row3AlignItems?: string; + /** @description Filter by row3Content */ + row3Content?: string; + /** @description Filter by seoTitle */ + seoTitle?: string; + /** @description Filter by seoDescription */ + seoDescription?: string; + /** @description Filter by seoMetaRobots */ + seoMetaRobots?: string; + /** @description Filter by slug */ + slug?: string; + /** @description Filter by name */ + name?: string; + /** @description Filter by linkName */ + linkName?: string; + /** @description Filter by icon */ + icon?: string; + /** @description Filter by headline */ + headline?: string; + /** @description Filter by subheadline */ + subheadline?: string; + /** @description Filter by topFullwidthBanner */ + topFullwidthBanner?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["page"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createPage: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["page_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["page"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getPage: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["page"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updatePage: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["page"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["page"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deletePage: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getPageReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listPageConfig: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by blogPostsPageHeadline */ + blogPostsPageHeadline?: string; + /** @description Filter by blogPostsPageSubHeadline */ + blogPostsPageSubHeadline?: string; + /** @description Filter by blogTagPageHeadline */ + blogTagPageHeadline?: string; + /** @description Filter by footerText1 */ + footerText1?: string; + /** @description Filter by logo */ + logo?: string; + /** @description Filter by postCommentSlot */ + postCommentSlot?: string; + /** @description Filter by seoDescription */ + seoDescription?: string; + /** @description Filter by seoTitle */ + seoTitle?: string; + /** @description Filter by siteName */ + siteName?: string; + /** @description Filter by website */ + website?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["page_config"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createPageConfig: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["page_config_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["page_config"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getPageConfig: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["page_config"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updatePageConfig: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["page_config"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["page_config"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deletePageConfig: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getPageConfigReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listPost: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by row1JustifyContent */ + row1JustifyContent?: string; + /** @description Filter by row1AlignItems */ + row1AlignItems?: string; + /** @description Filter by row1Content */ + row1Content?: string; + /** @description Filter by row2JustifyContent */ + row2JustifyContent?: string; + /** @description Filter by row2AlignItems */ + row2AlignItems?: string; + /** @description Filter by row2Content */ + row2Content?: string; + /** @description Filter by row3JustifyContent */ + row3JustifyContent?: string; + /** @description Filter by row3AlignItems */ + row3AlignItems?: string; + /** @description Filter by row3Content */ + row3Content?: string; + /** @description Filter by seoTitle */ + seoTitle?: string; + /** @description Filter by seoDescription */ + seoDescription?: string; + /** @description Filter by seoMetaRobots */ + seoMetaRobots?: string; + /** @description Filter by content */ + content?: string; + /** @description Filter by created */ + created?: string; + /** @description Filter by eventDate */ + eventDate?: string; + /** @description Filter by eventLocation */ + eventLocation?: string; + /** @description Filter by excerpt */ + excerpt?: string; + /** @description Filter by headline */ + headline?: string; + /** @description Filter by hideFromListing */ + hideFromListing?: boolean; + /** @description Filter by icon */ + icon?: string; + /** @description Filter by important */ + important?: boolean; + /** @description Filter by isEvent */ + isEvent?: boolean; + /** @description Filter by linkName */ + linkName?: string; + /** @description Filter by postImage */ + postImage?: string; + /** @description Filter by postTag */ + postTag?: string; + /** @description Filter by showCommentSection */ + showCommentSection?: boolean; + /** @description Filter by slug */ + slug?: string; + /** @description Filter by subheadline */ + subheadline?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["post"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createPost: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["post_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["post"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getPost: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["post"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updatePost: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["post"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["post"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deletePost: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getPostReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listPostOverview: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by row1JustifyContent */ + row1JustifyContent?: string; + /** @description Filter by row1AlignItems */ + row1AlignItems?: string; + /** @description Filter by row1Content */ + row1Content?: string; + /** @description Filter by row2JustifyContent */ + row2JustifyContent?: string; + /** @description Filter by row2AlignItems */ + row2AlignItems?: string; + /** @description Filter by row2Content */ + row2Content?: string; + /** @description Filter by row3JustifyContent */ + row3JustifyContent?: string; + /** @description Filter by row3AlignItems */ + row3AlignItems?: string; + /** @description Filter by row3Content */ + row3Content?: string; + /** @description Filter by seoTitle */ + seoTitle?: string; + /** @description Filter by seoDescription */ + seoDescription?: string; + /** @description Filter by seoMetaRobots */ + seoMetaRobots?: string; + /** @description Filter by id */ + id?: string; + /** @description Filter by headline */ + headline?: string; + /** @description Filter by text */ + text?: string; + /** @description Filter by allPosts */ + allPosts?: boolean; + /** @description Filter by filterByTag */ + filterByTag?: string; + /** @description Filter by posts */ + posts?: string; + /** @description Filter by numberItems */ + numberItems?: number; + /** @description Filter by design */ + design?: string; + /** @description Filter by layout */ + layout?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["post_overview"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createPostOverview: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["post_overview_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["post_overview"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getPostOverview: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["post_overview"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updatePostOverview: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["post_overview"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["post_overview"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deletePostOverview: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getPostOverviewReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listProduct: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by sku */ + sku?: string; + /** @description Filter by title */ + title?: string; + /** @description Filter by price */ + price?: number; + /** @description Filter by category */ + category?: string; + /** @description Filter by description */ + description?: string; + /** @description Filter by images */ + images?: string; + /** @description Filter by in_stock */ + in_stock?: boolean; + /** @description Filter by rating */ + rating?: number; + /** @description Filter by created_at */ + created_at?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["product"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createProduct: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["product_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["product"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getProduct: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["product"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateProduct: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["product"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["product"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteProduct: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getProductReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listQuote: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by quote */ + quote?: string; + /** @description Filter by author */ + author?: string; + /** @description Filter by variant */ + variant?: string; + /** @description Filter by layout */ + layout?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["quote"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createQuote: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["quote_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["quote"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getQuote: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["quote"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateQuote: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["quote"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["quote"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteQuote: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getQuoteReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listSearchableText: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by id */ + id?: string; + /** @description Filter by textFragments */ + textFragments?: string; + /** @description Filter by title */ + title?: string; + /** @description Filter by tagWhitelist */ + tagWhitelist?: string; + /** @description Filter by description */ + description?: string; + /** @description Filter by layout */ + layout?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["searchable_text"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createSearchableText: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["searchable_text_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["searchable_text"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getSearchableText: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["searchable_text"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateSearchableText: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["searchable_text"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["searchable_text"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteSearchableText: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getSearchableTextReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listSeo: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by seoTitle */ + seoTitle?: string; + /** @description Filter by seoDescription */ + seoDescription?: string; + /** @description Filter by seoMetaRobots */ + seoMetaRobots?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["seo"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createSeo: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["seo_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["seo"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getSeo: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["seo"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateSeo: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["seo"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["seo"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteSeo: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getSeoReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listTag: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by name */ + name?: string; + /** @description Filter by icon */ + icon?: string; + /** @description Filter by color */ + color?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["tag"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createTag: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["tag_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["tag"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getTag: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["tag"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateTag: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["tag"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["tag"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteTag: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getTagReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listTextFragment: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by id */ + id?: string; + /** @description Filter by title */ + title?: string; + /** @description Filter by text */ + text?: string; + /** @description Filter by tags */ + tags?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["text_fragment"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createTextFragment: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["text_fragment_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["text_fragment"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getTextFragment: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["text_fragment"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateTextFragment: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["text_fragment"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["text_fragment"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteTextFragment: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getTextFragmentReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listTopBanner: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by id */ + id?: string; + /** @description Filter by text */ + text?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["top_banner"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createTopBanner: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["top_banner_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["top_banner"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getTopBanner: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["top_banner"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateTopBanner: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["top_banner"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["top_banner"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteTopBanner: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getTopBannerReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listTranslationBundle: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by strings */ + strings?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["translation_bundle"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createTranslationBundle: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["translation_bundle_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["translation_bundle"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getTranslationBundle: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["translation_bundle"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateTranslationBundle: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["translation_bundle"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["translation_bundle"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteTranslationBundle: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getTranslationBundleReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listYoutubeVideo: { + parameters: { + query?: { + /** @description Field name to sort by */ + _sort?: string; + /** @description Sort order (default: asc) */ + _order?: "asc" | "desc"; + /** @description Page number (1-indexed). Ignored if _limit/_offset is set. */ + _page?: number; + /** @description Items per page (max 1000). Ignored if _limit/_offset is set. */ + _per_page?: number; + /** @description Maximum number of items to return (max 1000). Takes precedence over _per_page. */ + _limit?: number; + /** @description Number of items to skip. Takes precedence over _page. */ + _offset?: number; + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + /** @description Filter by youtubeId */ + youtubeId?: string; + /** @description Filter by title */ + title?: string; + /** @description Filter by description */ + description?: string; + /** @description Filter by params */ + params?: string; + /** @description Filter by layout */ + layout?: string; + /** @description Filter by id */ + id?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Paginated list of entries */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + items?: components["schemas"]["youtube_video"][]; + page?: number; + per_page?: number; + total?: number; + total_pages?: number; + }; + }; + }; + }; + }; + createYoutubeVideo: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["youtube_video_input"]; + }; + }; + responses: { + /** @description Entry created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["youtube_video"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getYoutubeVideo: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The entry */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["youtube_video"]; + }; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + updateYoutubeVideo: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["youtube_video"]; + }; + }; + responses: { + /** @description Entry updated */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["youtube_video"]; + }; + }; + /** @description Validation error */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteYoutubeVideo: { + parameters: { + query?: { + /** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */ + _resolve?: string; + /** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */ + _locale?: string; + }; + header?: never; + path: { + /** @description Entry identifier (filename without extension) */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Entry deleted */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Entry not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getYoutubeVideoReferrers: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entry slug */ + slug: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of referrers (collection, slug, field, locale) */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description Collection of the referring entry */ + collection?: string; + /** @description Field that holds the reference */ + field?: string; + /** @description Locale of the referring entry if applicable */ + locale?: string | null; + /** @description Slug of the referring entry */ + slug?: string; + }[]; + }; + }; + }; + }; + listEnvironments: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Environment list */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + default?: string | null; + environments?: string[]; + }; + }; + }; + }; + }; + createEnvironment: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** @description Optional override. Omit to inherit global default. */ + locales?: string[] | null; + name: string; + }; + }; + }; + responses: { + /** @description Space created */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid name or locales */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Space already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + deleteEnvironment: { + parameters: { + query?: never; + header?: never; + path: { + name: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Space deleted */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Cannot delete the last remaining space */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Space not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + renameEnvironment: { + parameters: { + query?: never; + header?: never; + path: { + name: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + name: string; + }; + }; + }; + responses: { + /** @description Space renamed */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Space not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Target name already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + duplicateEnvironment: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Source space */ + name: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** @description Target space name */ + name: string; + }; + }; + }; + responses: { + /** @description Space duplicated */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Source space not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Target name already exists */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + getEnvironmentLocales: { + parameters: { + query?: never; + header?: never; + path: { + name: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Locale configuration for the space */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["EnvironmentLocales"]; + }; + }; + /** @description Space not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + putEnvironmentLocales: { + parameters: { + query?: never; + header?: never; + path: { + name: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + locales?: string[] | null; + }; + }; + }; + responses: { + /** @description Override applied */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + locales?: string[]; + on_disk?: string[]; + override?: boolean; + updated?: string; + }; + }; + }; + /** @description Invalid body or locale value */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Space not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + listLocales: { + parameters: { + query?: { + _environment?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Locale list */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + default?: string | null; + locales?: string[]; + }; + }; + }; + }; + }; + transformImage: { + parameters: { + query: { + /** @description External image URL */ + url: string; + /** @description Target width (alias: width) */ + w?: number; + /** @description Target height (alias: height) */ + h?: number; + /** @description Aspect ratio before resize, e.g. 1:1 or 16:9 (center crop) */ + ar?: string; + /** @description fill = exact w×h, contain = fit inside, cover = fill with crop */ + fit?: "fill" | "contain" | "cover"; + /** @description Output format */ + format?: "jpeg" | "png" | "webp" | "avif"; + /** @description Quality 1–100 for JPEG and WebP (lossy) */ + quality?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Transformed image */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "image/avif": string; + "image/jpeg": string; + "image/png": string; + "image/webp": string; + }; + }; + /** @description Invalid URL or not a valid image */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Failed to fetch or process image */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; +} diff --git a/src/lib/cms.ts b/src/lib/cms.ts new file mode 100644 index 0000000..3e7fd99 --- /dev/null +++ b/src/lib/cms.ts @@ -0,0 +1,672 @@ +/** + * RustyCMS-Client: OpenAPI-Spec laden, Page-Content abrufen. + * Basis-URL über Umgebungsvariable PUBLIC_CMS_URL (z.B. http://localhost:3000). + * + * Konvention: slug = URL (für Links/Pfade), _slug = API/interne ID (für GET-Requests). + * Typen für Page und API-Antworten kommen aus der generierten OpenAPI-Spec. + * Nach Schema-Änderungen im CMS: `npm run generate:api-types` (RustyCMS muss laufen). + */ + +import type { components, operations } from "./cms-api.generated"; +import { env } from "$env/dynamic/public"; + +const getBaseUrl = (): string => { + const url = env.PUBLIC_CMS_URL || import.meta.env.PUBLIC_CMS_URL || "http://localhost:3000"; + return (typeof url === "string" && url.trim() ? url : "http://localhost:3000").replace(/\/$/, ""); +}; + +/** Page-Eintrag aus der API (aus OpenAPI-Spec generiert). */ +export type PageEntry = components["schemas"]["page"]; + +/** Antwort von GET /api/content/page (aus OpenAPI-Spec generiert). */ +export type PageListResponse = + operations["listPage"]["responses"][200]["content"]["application/json"]; + +/** Page-Config (Site-Einstellungen, wie in windwiderstand). Optional: homePage für Startseiten-Slug. */ +export type PageConfigEntry = components["schemas"]["page_config"] & { + /** Referenz auf die Page für die Startseite (Slug oder { _slug }). */ + homePage?: string | { _slug?: string }; +}; +export type PageConfigListResponse = + operations["listPageConfig"]["responses"][200]["content"]["application/json"]; + +export type OpenApiSpec = { + openapi: string; + info: { title: string; version: string }; + paths: Record; + components?: { schemas?: Record }; +}; + +let openApiCache: OpenApiSpec | null = null; + +/** + * TTL-Cache pro Collection (ms). Webhooks purgen bei Mutation → hohe TTL unkritisch. + * Override via PUBLIC_CMS_CACHE_TTL_MS_ falls nötig. + */ +const CACHE_TTL: Record = { + page: 5 * 60_000, + page_config: 10 * 60_000, + navigation: 10 * 60_000, + footer: 10 * 60_000, + post: 60_000, + tag: 5 * 60_000, + text_fragment: 5 * 60_000, + fullwidth_banner: 5 * 60_000, + calendar: 60_000, + calendar_item: 60_000, + translation: 5 * 60_000, + translation_bundle: 5 * 60_000, + openapi: 10 * 60_000, + default: 60_000, +}; + +type CacheEntry = { value: T; expires: number }; +const cache = new Map>(); +const inflight = new Map>(); + +function ttlFor(collection: string): number { + return CACHE_TTL[collection] ?? CACHE_TTL.default; +} + +/** + * Cached fetch mit TTL + in-flight dedup. Key-Format: "::". + * Bei Fehler wird nichts gecacht. + */ +async function cached( + collection: string, + key: string, + fn: () => Promise, +): Promise { + const hit = cache.get(key); + if (hit && hit.expires > Date.now()) return hit.value as T; + const pending = inflight.get(key) as Promise | undefined; + if (pending) return pending; + const promise = (async () => { + try { + const value = await fn(); + cache.set(key, { value, expires: Date.now() + ttlFor(collection) }); + return value; + } finally { + inflight.delete(key); + } + })(); + inflight.set(key, promise); + return promise; +} + +/** Purge Cache für eine Collection (z.B. nach Webhook). */ +export function invalidateCollection(collection: string): number { + let n = 0; + for (const k of cache.keys()) { + if (k.startsWith(`${collection}:`)) { + cache.delete(k); + n++; + } + } + return n; +} + +/** Purge kompletter Cache. */ +export function invalidateAll(): void { + cache.clear(); + openApiCache = null; +} + +/** Stats/Debug. */ +export function cacheStats(): { size: number; keys: string[] } { + return { size: cache.size, keys: [...cache.keys()] }; +} + +/** + * Lädt die OpenAPI-Spezifikation von GET /api-docs/openapi.json. + * Wird gecacht (einmal pro Request/Build). + */ +export async function fetchOpenApi(): Promise { + if (openApiCache) return openApiCache; + const base = getBaseUrl(); + const res = await fetch(`${base}/api-docs/openapi.json`); + if (!res.ok) { + throw new Error( + `RustyCMS OpenAPI fetch failed: ${res.status} ${res.statusText}. Is the CMS running at ${base}?`, + ); + } + const spec = (await res.json()) as OpenApiSpec; + openApiCache = spec; + return spec; +} + +/** + * Alle Page-Einträge (GET /api/content/page). TTL-gecacht. + */ +export async function getPages(): Promise { + return cached("page", "page:list:", async () => { + const base = getBaseUrl(); + const res = await fetch(`${base}/api/content/page`); + if (!res.ok) { + throw new Error( + `RustyCMS list page failed: ${res.status}. Is the CMS running at ${base}?`, + ); + } + const data = (await res.json()) as PageListResponse; + return data.items ?? []; + }); +} + +/** + * Alle page_config-Einträge (GET /api/content/page_config). + */ +export async function getPageConfigs(options?: { + locale?: string; + per_page?: number; +}): Promise { + const locale = options?.locale ?? ""; + const per = options?.per_page ?? 50; + const key = `page_config:list:${locale}:${per}`; + return cached("page_config", key, async () => { + const base = getBaseUrl(); + const url = new URL(`${base}/api/content/page_config`); + if (locale) url.searchParams.set("_locale", locale); + url.searchParams.set("_per_page", String(per)); + const res = await fetch(url.toString()); + if (!res.ok) { + throw new Error( + `RustyCMS list page_config failed: ${res.status}. Is the CMS running at ${base}?`, + ); + } + const data = (await res.json()) as PageConfigListResponse; + return (data.items ?? []) as PageConfigEntry[]; + }); +} + +/** + * Page-Config anhand Slug (z. B. "default"). Gecacht pro Request (Key: slug + options). + */ +export async function getPageConfigBySlug( + slug: string, + options?: { locale?: string; resolve?: string }, +): Promise { + const opts = options ?? {}; + const key = `page_config:slug:${slug}:${opts.locale ?? ""}:${opts.resolve ?? ""}`; + return cached("page_config", key, async () => { + const base = getBaseUrl(); + const url = new URL( + `${base}/api/content/page_config/${encodeURIComponent(slug)}`, + ); + if (opts.locale) url.searchParams.set("_locale", opts.locale); + if (opts.resolve) url.searchParams.set("_resolve", opts.resolve); + const res = await fetch(url.toString()); + if (res.status === 404) return null; + if (!res.ok) { + throw new Error( + `RustyCMS get page_config failed: ${res.status} for slug "${slug}".`, + ); + } + return (await res.json()) as PageConfigEntry; + }); +} + +/** + * Startseiten-Slug aus page_config. + */ +export async function getHomePageSlugFromConfig(options?: { + locale?: string; +}): Promise { + const config = + (await getPageConfigBySlug("page-config-default", options)) ?? + (await getPageConfigBySlug("default", options)) ?? + (await getPageConfigs({ locale: options?.locale, per_page: 1 }))[0] ?? + null; + if (!config?.homePage) return null; + const raw = config.homePage; + if (typeof raw === "string") return raw.trim() || null; + const slug = (raw as { _slug?: string })?._slug?.trim(); + return slug ?? null; +} + +/** Optionen für Content-Get (z. B. _resolve, _locale). */ +export type ContentGetOptions = { + locale?: string; + /** Felder, deren Referenzen aufgelöst werden (z. B. ["row1Content", "row2Content", "row3Content"]). */ + resolve?: string[]; +}; + +/** Führenden Slash entfernen (CMS kann "slug": "/about" liefern). */ +function normalizePageSlug(s: string | undefined): string { + return (s ?? "").replace(/^\//, "").trim(); +} + +/** + * Ein Page-Eintrag nach Slug (GET /api/content/page/:slug). + */ +export async function getPageBySlug( + slug: string, + options?: ContentGetOptions, +): Promise { + const resolveKey = options?.resolve?.join(",") ?? ""; + const key = `page:slug:${slug}:${options?.locale ?? ""}:${resolveKey}`; + return cached("page", key, async () => { + const base = getBaseUrl(); + const trySlug = async (s: string): Promise => { + const u = new URL(`${base}/api/content/page/${encodeURIComponent(s)}`); + if (options?.locale) u.searchParams.set("_locale", options.locale); + if (options?.resolve?.length) + u.searchParams.set("_resolve", options.resolve.join(",")); + return fetch(u.toString()); + }; + let res = await trySlug(slug); + if (res.status === 404 && !slug.startsWith("/")) { + res = await trySlug("/" + slug); + } + if (res.status === 404) { + const items = await getPages(); + const norm = normalizePageSlug(slug); + const match = items.find( + (p) => + normalizePageSlug(p.slug) === norm || + normalizePageSlug(p._slug) === norm || + p._slug === slug || + p.slug === slug, + ); + if (match?._slug) { + res = await trySlug(match._slug); + } + } + if (res.status === 404) return null; + if (!res.ok) { + throw new Error( + `RustyCMS get page failed: ${res.status} for slug "${slug}".`, + ); + } + return (await res.json()) as PageEntry; + }); +} + +/** Für Page-URLs wird `slug` bevorzugt (nicht _slug). Führender Slash wird ignoriert. */ +export async function getPageSlugs(): Promise { + const items = await getPages(); + return items.map((p) => normalizePageSlug(p.slug ?? p._slug)).filter(Boolean); +} + +/** Navigation (Single Source of Truth: RustyCMS OpenAPI). */ +export type NavigationEntry = components["schemas"]["navigation"]; + +/** Ein Eintrag aus navigation.links (Referenz { _slug, _type } oder Slug-String). */ +export type NavLinkEntry = NavigationEntry["links"] extends (infer L)[] + ? L + : never; + +/** Antwort von GET /api/content/navigation (paginiert). */ +export type NavigationListResponse = + operations["listNavigation"]["responses"][200]["content"]["application/json"]; + +/** + * Alle Navigation-Einträge (GET /api/content/navigation). Gecacht pro Request. + */ +export async function getNavigations(options?: { + locale?: string; + page?: number; + per_page?: number; + resolve?: string; +}): Promise<{ + items: NavigationEntry[]; + page: number; + per_page: number; + total: number; + total_pages: number; +}> { + const opts = options ?? {}; + const key = `navigation:list:${opts.locale ?? ""}:${opts.page ?? 1}:${opts.per_page ?? 50}:${opts.resolve ?? ""}`; + return cached("navigation", key, async () => { + const base = getBaseUrl(); + const url = new URL(`${base}/api/content/navigation`); + if (opts.locale) url.searchParams.set("_locale", opts.locale); + if (opts.resolve) url.searchParams.set("_resolve", opts.resolve); + url.searchParams.set("_page", String(opts.page ?? 1)); + url.searchParams.set("_per_page", String(opts.per_page ?? 50)); + const res = await fetch(url.toString()); + if (!res.ok) { + throw new Error( + `RustyCMS list navigation failed: ${res.status}. Is the CMS running at ${base}?`, + ); + } + const data = (await res.json()) as NavigationListResponse; + return { + items: data.items ?? [], + page: data.page ?? 1, + per_page: data.per_page ?? 50, + total: data.total ?? 0, + total_pages: data.total_pages ?? 1, + }; + }); +} + +/** Keys für Navigation. */ +export const NavigationKeys = { + header: "navigation-header", + socialMedia: "navigation-social-media", + footer: "navigation-footer", +} as const; + +/** + * Navigation anhand Key/Slug aus der Liste holen. + */ +export async function getNavigationByKey( + key: string, + options?: { locale?: string; resolve?: string }, +): Promise { + const { items } = await getNavigations({ + locale: options?.locale ?? "de", + per_page: 50, + resolve: options?.resolve, + }); + const entry = items.find( + (n) => + (n as { _slug?: string; internal?: string })._slug === key || + (n as { _slug?: string; internal?: string }).internal === key, + ); + return entry ?? null; +} + +/** + * Navigation anhand des Slugs holen. + */ +export async function getNavigationBySlug( + slug: string, + options?: { locale?: string }, +): Promise { + const byKey = await getNavigationByKey(slug, options); + if (byKey) return byKey; + const key = `navigation:slug:${slug}:${options?.locale ?? ""}`; + return cached("navigation", key, async () => { + const base = getBaseUrl(); + const url = new URL( + `${base}/api/content/navigation/${encodeURIComponent(slug)}`, + ); + if (options?.locale) url.searchParams.set("_locale", options.locale); + const res = await fetch(url.toString()); + if (res.status === 404) return null; + if (!res.ok) return null; + return (await res.json()) as NavigationEntry; + }); +} + +/** Footer (Single Source of Truth: RustyCMS OpenAPI). */ +export type FooterEntry = components["schemas"]["footer"]; + +/** + * Footer anhand des Slugs holen (z. B. "default"). + */ +export async function getFooterBySlug( + slug: string, + options?: ContentGetOptions, +): Promise { + const resolveKey = options?.resolve?.join(",") ?? ""; + const key = `footer:slug:${slug}:${options?.locale ?? ""}:${resolveKey}`; + return cached("footer", key, async () => { + const base = getBaseUrl(); + const url = new URL(`${base}/api/content/footer/${encodeURIComponent(slug)}`); + if (options?.locale) url.searchParams.set("_locale", options.locale); + if (options?.resolve?.length) + url.searchParams.set("_resolve", options.resolve.join(",")); + const res = await fetch(url.toString()); + if (res.status === 404) return null; + if (!res.ok) { + throw new Error( + `RustyCMS get footer failed: ${res.status} for slug "${slug}".`, + ); + } + return (await res.json()) as FooterEntry; + }); +} + +/** Post-Eintrag (Single Source of Truth: RustyCMS OpenAPI). */ +export type PostEntry = components["schemas"]["post"]; + +/** Normalisiert Post-Slug für URL (führenden Slash entfernen). */ +function normalizePostSlug(s: string | undefined): string { + return (s ?? "").replace(/^\//, "").trim(); +} + +/** + * Post nach Slug (GET /api/content/post/:slug). + */ +export async function getPostBySlug( + slug: string, + options?: ContentGetOptions, +): Promise { + const resolveKey = options?.resolve?.join(",") ?? ""; + const key = `post:slug:${slug}:${options?.locale ?? ""}:${resolveKey}`; + return cached("post", key, async () => { + const base = getBaseUrl(); + const trySlug = async (s: string): Promise => { + const u = new URL(`${base}/api/content/post/${encodeURIComponent(s)}`); + if (options?.locale) u.searchParams.set("_locale", options.locale); + if (options?.resolve?.length) + u.searchParams.set("_resolve", options.resolve.join(",")); + return fetch(u.toString()); + }; + let res = await trySlug(slug); + if (res.status === 404 && !slug.startsWith("/")) { + res = await trySlug("/" + slug); + } + if (res.status === 404) { + const items = await getPosts(); + const norm = normalizePostSlug(slug); + const match = items.find( + (p) => + normalizePostSlug(p.slug) === norm || + normalizePostSlug(p._slug) === norm || + p._slug === slug || + p.slug === slug, + ); + if (match?._slug) { + res = await trySlug(match._slug); + } + } + if (res.status === 404) return null; + if (!res.ok) { + throw new Error( + `RustyCMS get post failed: ${res.status} for slug "${slug}".`, + ); + } + return (await res.json()) as PostEntry; + }); +} + +/** Für Post-URLs wird slug bevorzugt (nicht _slug). Führender Slash wird ignoriert. */ +export async function getPostSlugs(): Promise { + const items = await getPosts(); + return items.map((p) => normalizePostSlug(p.slug ?? p._slug)).filter(Boolean); +} + +/** Optionen für getPosts (Query-Parameter _sort, _order, _resolve). */ +export interface GetPostsOptions { + _sort?: string; + _order?: "asc" | "desc"; + /** Referenzen auflösen, z. B. "all" oder ["postImage", "postTag"] */ + resolve?: string | string[]; +} + +/** Alle Post-Einträge (GET /api/content/post). Gecacht pro Request. */ +export async function getPosts( + options?: GetPostsOptions, +): Promise { + const opts = options ?? {}; + const resolveVal = Array.isArray(opts.resolve) + ? opts.resolve.join(",") + : (opts.resolve ?? ""); + const key = `post:list:${opts._sort ?? ""}:${opts._order ?? ""}:${resolveVal}`; + return cached("post", key, async () => { + const base = getBaseUrl(); + const url = new URL(`${base}/api/content/post`); + url.searchParams.set("_per_page", "1000"); + if (opts._sort) url.searchParams.set("_sort", opts._sort); + if (opts._order) url.searchParams.set("_order", opts._order); + if (resolveVal) url.searchParams.set("_resolve", resolveVal); + const res = await fetch(url.toString()); + if (!res.ok) throw new Error("RustyCMS list post failed"); + const data = (await res.json()) as { items?: PostEntry[] }; + return data.items ?? []; + }); +} + +/** Tag-Eintrag (z. B. für Blog-Filter). */ +export type TagEntry = components["schemas"]["tag"]; + +/** Alle Tags (GET /api/content/tag). TTL-gecacht. */ +export async function getTags(): Promise { + return cached("tag", "tag:list:", async () => { + const base = getBaseUrl(); + const res = await fetch(`${base}/api/content/tag`); + if (!res.ok) return []; + const data = (await res.json()) as { items?: TagEntry[] }; + return data.items ?? []; + }); +} + +/** Text-Fragment (z. B. für searchable_text). */ +export type TextFragmentEntry = components["schemas"]["text_fragment"]; + +/** Text-Fragment anhand Slug (GET /api/content/text_fragment/:slug). */ +export async function getTextFragmentBySlug( + slug: string, + options?: { locale?: string }, +): Promise { + const key = `text_fragment:slug:${slug}:${options?.locale ?? ""}`; + return cached("text_fragment", key, async () => { + const base = getBaseUrl(); + const url = new URL( + `${base}/api/content/text_fragment/${encodeURIComponent(slug)}`, + ); + if (options?.locale) url.searchParams.set("_locale", options.locale); + const res = await fetch(url.toString()); + if (res.status === 404) return null; + if (!res.ok) { + throw new Error( + `RustyCMS get text_fragment failed: ${res.status} for slug "${slug}".`, + ); + } + return (await res.json()) as TextFragmentEntry; + }); +} + +/** Fullwidth-Banner (z. B. für Top-Banner mit Bild). */ +export type FullwidthBannerEntry = components["schemas"]["fullwidth_banner"]; + +/** Fullwidth-Banner anhand Slug (GET /api/content/fullwidth_banner/:slug). */ +export async function getFullwidthBannerBySlug( + slug: string, + options?: { locale?: string }, +): Promise { + const key = `fullwidth_banner:slug:${slug}:${options?.locale ?? ""}`; + return cached("fullwidth_banner", key, async () => { + const base = getBaseUrl(); + const url = new URL( + `${base}/api/content/fullwidth_banner/${encodeURIComponent(slug)}`, + ); + if (options?.locale) url.searchParams.set("_locale", options.locale); + const res = await fetch(url.toString()); + if (res.status === 404) return null; + if (!res.ok) { + throw new Error( + `RustyCMS get fullwidth_banner failed: ${res.status} for slug "${slug}".`, + ); + } + return (await res.json()) as FullwidthBannerEntry; + }); +} + +/** Translation-Eintrag (UI-Strings für i18n). Collection: translation. */ +export type TranslationEntry = { _slug?: string; text: string }; + +/** Translation anhand Slug (GET /api/content/translation/:slug). */ +export async function getTranslationBySlug( + slug: string, + options?: { locale?: string }, +): Promise { + const key = `translation:slug:${slug}:${options?.locale ?? ""}`; + return cached("translation", key, async () => { + const base = getBaseUrl(); + const url = new URL( + `${base}/api/content/translation/${encodeURIComponent(slug)}`, + ); + if (options?.locale) url.searchParams.set("_locale", options.locale); + const res = await fetch(url.toString()); + if (res.status === 404) return null; + if (!res.ok) return null; + return (await res.json()) as TranslationEntry; + }); +} + +/** Translation-Bundle: ein Objekt mit vielen Keys (String → String). Collection: translation_bundle. */ +export type TranslationBundleEntry = { + _slug?: string; + strings: Record; +}; + +/** + * Translation-Bundle anhand Slug (GET /api/content/translation_bundle/:slug). + */ +export async function getTranslationBundleBySlug( + slug: string, + options?: { locale?: string }, +): Promise { + const key = `translation_bundle:slug:${slug}:${options?.locale ?? ""}`; + return cached("translation_bundle", key, async () => { + const base = getBaseUrl(); + const url = new URL( + `${base}/api/content/translation_bundle/${encodeURIComponent(slug)}`, + ); + url.searchParams.set("_resolve", "all"); + if (options?.locale) url.searchParams.set("_locale", options.locale); + const res = await fetch(url.toString()); + if (res.status === 404) return null; + if (!res.ok) return null; + return (await res.json()) as TranslationBundleEntry; + }); +} + +/** Kalender-Eintrag (calendar) – aus OpenAPI-Spec. */ +export type CalendarEntry = components["schemas"]["calendar"]; + +/** Kalender-Item (calendar_item) – aus OpenAPI-Spec. */ +export type CalendarItemEntry = components["schemas"]["calendar_item"]; + +/** Kalender anhand Slug (GET /api/content/calendar/:slug). */ +export async function getCalendarBySlug( + slug: string, + options?: { locale?: string; resolve?: string }, +): Promise { + const key = `calendar:slug:${slug}:${options?.locale ?? ""}:${options?.resolve ?? ""}`; + return cached("calendar", key, async () => { + const base = getBaseUrl(); + const url = new URL( + `${base}/api/content/calendar/${encodeURIComponent(slug)}`, + ); + if (options?.locale) url.searchParams.set("_locale", options.locale); + if (options?.resolve) url.searchParams.set("_resolve", options.resolve); + const res = await fetch(url.toString()); + if (res.status === 404) return null; + if (!res.ok) return null; + return (await res.json()) as CalendarEntry; + }); +} + +/** Einzelnes calendar_item anhand Slug (GET /api/content/calendar_item/:slug). */ +export async function getCalendarItemBySlug( + slug: string, + options?: { locale?: string }, +): Promise { + const key = `calendar_item:slug:${slug}:${options?.locale ?? ""}`; + return cached("calendar_item", key, async () => { + const base = getBaseUrl(); + const url = new URL( + `${base}/api/content/calendar_item/${encodeURIComponent(slug)}`, + ); + if (options?.locale) url.searchParams.set("_locale", options.locale); + const res = await fetch(url.toString()); + if (res.status === 404) return null; + if (!res.ok) return null; + return (await res.json()) as CalendarItemEntry; + }); +} diff --git a/src/lib/components/Accordion.svelte b/src/lib/components/Accordion.svelte new file mode 100644 index 0000000..dbe15c1 --- /dev/null +++ b/src/lib/components/Accordion.svelte @@ -0,0 +1,29 @@ + + +
+ + + {label} + +
+ {@render children()} +
+
diff --git a/src/lib/components/Badge.svelte b/src/lib/components/Badge.svelte new file mode 100644 index 0000000..1399bd7 --- /dev/null +++ b/src/lib/components/Badge.svelte @@ -0,0 +1,22 @@ + + + + {@render children?.()} + diff --git a/src/lib/components/BlogOverview.svelte b/src/lib/components/BlogOverview.svelte new file mode 100644 index 0000000..c59c225 --- /dev/null +++ b/src/lib/components/BlogOverview.svelte @@ -0,0 +1,301 @@ + + +
+ {#if searchIndex} +
+ + {#if availableYears.length > 0} + + {/if} +
+ {/if} + + {#if !isFiltering && upcomingEvents.length > 0} +
+

+ + {t(T.blog_upcoming_events)} +

+ +
+ {/if} + + {#if isFiltering} +
+ + {t(T.blog_results_count, { count: filteredResults.length })} + {#if query}{t(T.blog_results_for, { query })}{/if} + {#if year}{t(T.blog_results_in_year, { year })}{/if} + + +
+ {#if filteredResults.length > 0} + + {:else} +
+ {t(T.blog_no_results)} +
+ {/if} + {:else} + {#if tags.length > 0} +
+ +
+ {/if} + + + +
+ {#each posts as post} + + {/each} +
+ +
+ +
+
+
+ {#if totalCount > 0} + {t(T.blog_count, { + visible: posts.length, + total: totalCount, + current: currentPage, + totalPages, + })} + {:else} + {t(T.blog_count, { + visible: 0, + total: 0, + current: currentPage, + totalPages, + })} + {/if} +
+
+
+ + + {/if} +
diff --git a/src/lib/components/Card.svelte b/src/lib/components/Card.svelte new file mode 100644 index 0000000..c8e2c1e --- /dev/null +++ b/src/lib/components/Card.svelte @@ -0,0 +1,32 @@ + + +{#if href} + + {@render children?.()} + +{:else} +
+ {@render children?.()} +
+{/if} diff --git a/src/lib/components/CmsImage.svelte b/src/lib/components/CmsImage.svelte new file mode 100644 index 0000000..1619945 --- /dev/null +++ b/src/lib/components/CmsImage.svelte @@ -0,0 +1,45 @@ + + + diff --git a/src/lib/components/ContentRows.svelte b/src/lib/components/ContentRows.svelte new file mode 100644 index 0000000..abab0ff --- /dev/null +++ b/src/lib/components/ContentRows.svelte @@ -0,0 +1,154 @@ + + +
+ {#each rows as row} + {#if row.content.length > 0} +
+ {#each row.content as item} + {#if isResolvedBlock(item)} + {#snippet blockContent()} + {#if blockType(item) === "markdown"} + + {:else if blockType(item) === "headline"} + + {:else if blockType(item) === "html"} + + {:else if blockType(item) === "iframe"} + + {:else if blockType(item) === "image"} + + {:else if blockType(item) === "image_gallery"} + + {:else if blockType(item) === "youtube_video"} + + {:else if blockType(item) === "quote"} + + {:else if blockType(item) === "link_list"} + + {:else if blockType(item) === "post_overview"} + + {:else if blockType(item) === "searchable_text"} + + {:else if blockType(item) === "calendar"} + + {:else if blockType(item) === "organisations"} + + {:else if blockType(item) === "opnform"} + + {:else} +
+ Unbekannter Block: {blockType(item)} +
+ {/if} + {/snippet} + {#if isBlockLayoutBreakout((item as { layout?: BlockLayout }).layout)} + {@const rowBlockType = blockType(item)} +
+
+
+ {@render blockContent()} +
+
+
+ {:else} + {@render blockContent()} + {/if} + {/if} + {/each} +
+ {/if} + {/each} +
diff --git a/src/lib/components/EventBadges.svelte b/src/lib/components/EventBadges.svelte new file mode 100644 index 0000000..c4af70a --- /dev/null +++ b/src/lib/components/EventBadges.svelte @@ -0,0 +1,49 @@ + + +{#if dateLabel || locationText} +
+ {#if dateLabel} + + + {/if} + {#if locationText} + {#if locationHref} + + + {:else} + + + {/if} + {/if} +
+{/if} diff --git a/src/lib/components/EventMap.svelte b/src/lib/components/EventMap.svelte new file mode 100644 index 0000000..236ff66 --- /dev/null +++ b/src/lib/components/EventMap.svelte @@ -0,0 +1,78 @@ + + + +
+ {#if embedUrl} +
+
+ + {#if overlayVisible} +
{ overlayVisible = false; }} + onkeydown={(e) => { if (e.key === 'Enter' || e.key === ' ') overlayVisible = false; }} + > +
+
+
+ {/if} +
+ {#if linkUrl} + + + {/if} +
+ {:else if linkUrl} + + + {/if} +
+
diff --git a/src/lib/components/Footer.svelte b/src/lib/components/Footer.svelte new file mode 100644 index 0000000..11acc97 --- /dev/null +++ b/src/lib/components/Footer.svelte @@ -0,0 +1,58 @@ + + +{#if footer} +
+
+ {#if hasRowContent} + + {:else} +

+ {t(T.footer_copyright) !== T.footer_copyright + ? t(T.footer_copyright) + : `© ${new Date().getFullYear()} Windwiderstand`} +

+ {/if} +
+
+{/if} diff --git a/src/lib/components/Header.svelte b/src/lib/components/Header.svelte new file mode 100644 index 0000000..0e34326 --- /dev/null +++ b/src/lib/components/Header.svelte @@ -0,0 +1,248 @@ + + +
+
+ + + + + + +
+ + +
+
+ + + + + {#if menuOpen} + + {/if} +
diff --git a/src/lib/components/HeaderOverlay.svelte b/src/lib/components/HeaderOverlay.svelte new file mode 100644 index 0000000..8abb2e0 --- /dev/null +++ b/src/lib/components/HeaderOverlay.svelte @@ -0,0 +1,21 @@ + + +{#if $overlayOpen} + +{/if} diff --git a/src/lib/components/Pagination.svelte b/src/lib/components/Pagination.svelte new file mode 100644 index 0000000..0230569 --- /dev/null +++ b/src/lib/components/Pagination.svelte @@ -0,0 +1,76 @@ + + +{#if showPagination} +
+
+ {#if hasPrev} + + + {/if} + {#each pageNumbers as num} + + {num} + + {/each} + {#if hasNext} + + + {/if} +
+
+{/if} diff --git a/src/lib/components/PostCard.svelte b/src/lib/components/PostCard.svelte new file mode 100644 index 0000000..a6f860b --- /dev/null +++ b/src/lib/components/PostCard.svelte @@ -0,0 +1,78 @@ + + + +
+ {#if resolvedImg} + {post.headline + {:else} +
+ +
+ {/if} + {#if eventDate} +
+ +
+ {/if} +
+
+ +
+
+ {post.headline ?? post.linkName ?? post.slug ?? post._slug} +
+ {#if post.subheadline} +
+ {post.subheadline} +
+ {/if} + {#if post.excerpt} +

+ {post.excerpt} +

+ {/if} +
+
+
diff --git a/src/lib/components/PostMeta.svelte b/src/lib/components/PostMeta.svelte new file mode 100644 index 0000000..3494578 --- /dev/null +++ b/src/lib/components/PostMeta.svelte @@ -0,0 +1,29 @@ + + +
+ {#if date} + + {/if} +
+ +
+
diff --git a/src/lib/components/RustyImage.svelte b/src/lib/components/RustyImage.svelte new file mode 100644 index 0000000..66a01a6 --- /dev/null +++ b/src/lib/components/RustyImage.svelte @@ -0,0 +1,25 @@ + + + diff --git a/src/lib/components/Search.svelte b/src/lib/components/Search.svelte new file mode 100644 index 0000000..e7eb30b --- /dev/null +++ b/src/lib/components/Search.svelte @@ -0,0 +1,166 @@ + + +{#if open} +
+
+ + +
+ {#if loading} +

Lade Suchindex…

+ {:else if loadError} +

Suche nicht verfügbar: {loadError}

+ {:else if normalizedQuery.length < 2} +

Mindestens 2 Zeichen eingeben.

+ {:else if results.length === 0} +

Keine Treffer.

+ {:else} + + {/if} +
+
+
+{/if} diff --git a/src/lib/components/Tag.svelte b/src/lib/components/Tag.svelte new file mode 100644 index 0000000..1a05de5 --- /dev/null +++ b/src/lib/components/Tag.svelte @@ -0,0 +1,118 @@ + + +{#if href} + + {#if icon} + +{:else if onclick} + +{:else} + + {#if icon} + +{/if} diff --git a/src/lib/components/Tags.svelte b/src/lib/components/Tags.svelte new file mode 100644 index 0000000..c7ac3c2 --- /dev/null +++ b/src/lib/components/Tags.svelte @@ -0,0 +1,59 @@ + + +{#each (tags ?? []) as t} + {@const name = displayName(t)} + {#if name} + + {/if} +{/each} diff --git a/src/lib/components/TopBanner.svelte b/src/lib/components/TopBanner.svelte new file mode 100644 index 0000000..b2c4e8b --- /dev/null +++ b/src/lib/components/TopBanner.svelte @@ -0,0 +1,80 @@ + + +{#if showBanner} +
+ {#if hasImage} +
+ {banner?.headline + {#if hasPageTitle} +
+
+ {#if headlineHtml} +

{@html headlineHtml}

+ {/if} +
+ {#if subheadlineHtml} +

{@html subheadlineHtml}

+ {/if} +
+
+ {/if} +
+ {:else if hasPageTitle} +
+ {#if headlineHtml} +

{@html headlineHtml}

+ {/if} + {#if subheadlineHtml} +

{@html subheadlineHtml}

+ {/if} +
+ {/if} + {#if hasText} +
+
+
{banner!.text}
+
+
+ {/if} +
+{/if} diff --git a/src/lib/components/TranslationProvider.svelte b/src/lib/components/TranslationProvider.svelte new file mode 100644 index 0000000..af7e760 --- /dev/null +++ b/src/lib/components/TranslationProvider.svelte @@ -0,0 +1,25 @@ + + +{#if children} + {@render children()} +{/if} diff --git a/src/lib/components/blocks/CalendarBlock.svelte b/src/lib/components/blocks/CalendarBlock.svelte new file mode 100644 index 0000000..72107eb --- /dev/null +++ b/src/lib/components/blocks/CalendarBlock.svelte @@ -0,0 +1,349 @@ + + +
+ {#snippet eventCard(item: EventCardItem)} + {@const eventHref = getEventLinkHref(item.link)} +
  • +
    + {#if item.date} +
    + {item.date.toLocaleDateString("de-DE", { + weekday: "short", + day: "numeric", + month: "short", + })} +
    + {#if item.timeStr} + / + {/if} + {/if} + {#if item.timeStr} +
    + {item.timeStr} + {t(T.calendar_time_suffix)} +
    + {/if} +
    + {#if eventHref} + + {item.title} + + {:else} +
    {item.title}
    + {/if} + + {#if item.description} +

    + {item.description} +

    + {#if eventHref} + + {t(T.calendar_more_info)} + + {/if} + {:else if eventHref} + + {t(T.calendar_more_info)} + + {/if} +
  • + {/snippet} + + {#if block.title} +

    + {block.title} +

    + {/if} + +
    + +
    +
    + + {monthLabel} + +
    + +
    + {#each weekdays as w} +
    {w}
    + {/each} + {#each calendarDays as d} + {#if d === null} + + {:else} + {@const key = dayKey(d)} + {@const isCurrentMonth = d.getMonth() === month} + {@const events = eventsByDay.get(key) ?? []} + {@const hasEvents = events.length > 0} + {@const isSelected = selectedDay === key} + {@const isFuture = key >= todayKey} + {#if hasEvents} + + {:else} +
    + {d.getDate()} +
    + {/if} + {/if} + {/each} +
    +
    + + +
    +
    + {#if items.length === 0} +

    {t(T.calendar_no_events)}

    + {:else if selectedDay} +

    + {new Date(selectedDay + "T12:00:00").toLocaleDateString("de-DE", { + weekday: "long", + day: "numeric", + month: "long", + })} +

    +
      + {#each selectedDayEvents as item} + {@render eventCard(item)} + {/each} +
    + {:else if nextUpcomingEvents.length > 0} +

    + {t(T.calendar_next_events)} +

    +
      + {#each nextUpcomingEvents as item} + {@render eventCard(item)} + {/each} +
    + {:else} +

    {t(T.calendar_select_day)}

    + {/if} +
    +
    +
    +
    diff --git a/src/lib/components/blocks/HeadlineBlock.svelte b/src/lib/components/blocks/HeadlineBlock.svelte new file mode 100644 index 0000000..7f64a5b --- /dev/null +++ b/src/lib/components/blocks/HeadlineBlock.svelte @@ -0,0 +1,25 @@ + + +
    + + {block.text ?? ""} + +
    diff --git a/src/lib/components/blocks/HtmlBlock.svelte b/src/lib/components/blocks/HtmlBlock.svelte new file mode 100644 index 0000000..4783e2f --- /dev/null +++ b/src/lib/components/blocks/HtmlBlock.svelte @@ -0,0 +1,16 @@ + + +
    + {@html block.html ?? ""} +
    diff --git a/src/lib/components/blocks/IframeBlock.svelte b/src/lib/components/blocks/IframeBlock.svelte new file mode 100644 index 0000000..a24958a --- /dev/null +++ b/src/lib/components/blocks/IframeBlock.svelte @@ -0,0 +1,67 @@ + + +
    + {#if src} +
    + + {#if overlayActive} +
    e.key === "Enter" && activateMap()} + > +
    + {/if} +
    + {:else} +

    {t(T.iframe_missing)}

    + {/if} +
    diff --git a/src/lib/components/blocks/ImageBlock.svelte b/src/lib/components/blocks/ImageBlock.svelte new file mode 100644 index 0000000..b81990f --- /dev/null +++ b/src/lib/components/blocks/ImageBlock.svelte @@ -0,0 +1,77 @@ + + +
    + {#if rawSrc} +
    + + {#if block.caption} +
    {block.caption}
    + {/if} +
    + {:else} +

    Bild nicht verfügbar.

    + {/if} +
    diff --git a/src/lib/components/blocks/ImageGalleryBlock.svelte b/src/lib/components/blocks/ImageGalleryBlock.svelte new file mode 100644 index 0000000..74d8dd7 --- /dev/null +++ b/src/lib/components/blocks/ImageGalleryBlock.svelte @@ -0,0 +1,216 @@ + + +
    + {#if descriptionHtml} +
    + {@html descriptionHtml} +
    + {/if} + + {#if withUrl.length === 0} +

    {t(T.image_gallery_empty)}

    + {:else if withUrl.length === 1} +
    + + {#if withUrl[0].img.description} +
    {withUrl[0].img.description}
    + {/if} +
    + {:else} +
    +
    + {#key currentIndex} + {@const current = withUrl[currentIndex]} +
    + + {#if current.img.description} +
    + {current.img.description} +
    + {/if} +
    + {/key} +
    + + + + +
    + {#each withUrl as _, i} + + {/each} +
    +
    + {/if} +
    diff --git a/src/lib/components/blocks/LinkListBlock.svelte b/src/lib/components/blocks/LinkListBlock.svelte new file mode 100644 index 0000000..73f0a99 --- /dev/null +++ b/src/lib/components/blocks/LinkListBlock.svelte @@ -0,0 +1,37 @@ + + +
    + {#if block.headline} +

    {block.headline}

    + {/if} + +
    diff --git a/src/lib/components/blocks/MarkdownBlock.svelte b/src/lib/components/blocks/MarkdownBlock.svelte new file mode 100644 index 0000000..3449674 --- /dev/null +++ b/src/lib/components/blocks/MarkdownBlock.svelte @@ -0,0 +1,36 @@ + + +
    +
    + {@html html} +
    +
    diff --git a/src/lib/components/blocks/OpnFormBlock.svelte b/src/lib/components/blocks/OpnFormBlock.svelte new file mode 100644 index 0000000..43c44d0 --- /dev/null +++ b/src/lib/components/blocks/OpnFormBlock.svelte @@ -0,0 +1,99 @@ + + +
    + {#if iframeSrc} + + {:else} +

    OpnForm: formId fehlt.

    + {/if} +
    diff --git a/src/lib/components/blocks/OrganisationsBlock.svelte b/src/lib/components/blocks/OrganisationsBlock.svelte new file mode 100644 index 0000000..26821e8 --- /dev/null +++ b/src/lib/components/blocks/OrganisationsBlock.svelte @@ -0,0 +1,231 @@ + + +
    + {#if block.headline} +

    {block.headline}

    + {/if} +
    + {#each orgs as org, orgIndex} + {#if typeof org === "object" && org !== null} + {@const o = org as OrganisationEntry} + {@const linkUrl = + typeof o.link === "object" && + o.link !== null && + typeof o.link.url === "string" && + o.link.url.trim() !== "" + ? o.link.url.trim() + : undefined} + {@const logoSrc = organisationLogoSrc(o)} + {#if compact} + +
    + {#if logoSrc} + {organisationLogoAlt(o)} + {:else} + {@const fishMaskId = `org-logo-fallback-mask-c-${orgIndex}`} + + {/if} +
    +
    +
    {o.name ?? ""}
    + {#if o.description} +

    {o.description}

    + {/if} +
    +
    + {:else} + +
    + {#if logoSrc} + {organisationLogoAlt(o)} + {:else} + {@const fishMaskId = `org-logo-fallback-mask-${orgIndex}`} + + {/if} +
    + {#if o.badge && typeof o.badge === "object" && o.badge.label} +
    + {o.badge.label} +
    + {/if} +
    {o.name ?? ""}
    + {#if o.description} +

    {o.description}

    + {/if} +
    + {/if} + {/if} + {/each} + + {#if showAddOrganisationCard} + + {#if block.addOrganisationTitle} +
    + {block.addOrganisationTitle} +
    + {/if} + {#if ctaHtml} +
    + {@html ctaHtml} +
    + {/if} + {#if addOrganisationCtaLink} +

    + {addOrganisationCtaLink.linkName} +

    + {/if} +
    + {/if} +
    +
    diff --git a/src/lib/components/blocks/PostOverviewBlock.svelte b/src/lib/components/blocks/PostOverviewBlock.svelte new file mode 100644 index 0000000..a07e57e --- /dev/null +++ b/src/lib/components/blocks/PostOverviewBlock.svelte @@ -0,0 +1,59 @@ + + +
    + {#if block.headline} +

    {block.headline}

    + {/if} + {#if textHtml} +
    {@html textHtml}
    + {/if} + + {#if design === "list" && posts.length > 0} +
    + {#each posts as post} + + {/each} +
    + {:else if design === "cards" && posts.length > 0} +
    + {#each posts as post} + + {/each} +
    + {/if} + + {#if posts.length > 0} + + {/if} +
    diff --git a/src/lib/components/blocks/QuoteBlock.svelte b/src/lib/components/blocks/QuoteBlock.svelte new file mode 100644 index 0000000..990ead7 --- /dev/null +++ b/src/lib/components/blocks/QuoteBlock.svelte @@ -0,0 +1,18 @@ + + +
    +
    +

    "{block.quote ?? ""}"

    + {#if block.author} + — {block.author} + {/if} +
    +
    diff --git a/src/lib/components/blocks/SearchableTextBlock.svelte b/src/lib/components/blocks/SearchableTextBlock.svelte new file mode 100644 index 0000000..af2674f --- /dev/null +++ b/src/lib/components/blocks/SearchableTextBlock.svelte @@ -0,0 +1,324 @@ + + +
    +
    + {#if block.title} +

    + {block.title} +

    + {/if} + {#if descriptionHtml} +
    + {@html descriptionHtml} +
    + {/if} +
    + +
    +
    +
    + + + + (searchQuery = (e.target as HTMLInputElement).value)} + aria-label={t(T.searchable_text_search_aria)} + /> + {#if searchQuery} + + {/if} +
    + {#if allTags.length > 0} +
    +
    + (selectedTag = "all")} + /> + {#each allTags as tag} + (selectedTag = tag)} + /> + {/each} +
    +
    + {/if} +
    +
    + +
    + {#if visibleFragments.length === 0} + {t(T.searchable_text_no_results)} + {:else} + + {visibleFragments.length === fragments.length + ? t(T.searchable_text_count_all, { count: visibleFragments.length }) + : t(T.searchable_text_count_filtered, { + visible: visibleFragments.length, + total: fragments.length, + })} + + {/if} +
    + +
    + {#each visibleFragments as fragment, i} +
    + +
    +
    + {@html highlightInText( + fragment.title || t(T.searchable_text_untitled), + searchQuery.trim(), + )} +
    +
    + {#if fragment.tags.length > 0} + + + + {/if} +
    +
    +
    + +
    + {@html highlightInHtml(fragment.textHtml, searchQuery.trim())} +
    +
    + {/each} +
    +
    diff --git a/src/lib/components/blocks/YoutubeVideoBlock.svelte b/src/lib/components/blocks/YoutubeVideoBlock.svelte new file mode 100644 index 0000000..438a3a3 --- /dev/null +++ b/src/lib/components/blocks/YoutubeVideoBlock.svelte @@ -0,0 +1,36 @@ + + +
    + {#if block.youtubeId} +
    + +
    + {#if block.description} +
    {block.description}
    + {/if} + {:else} +
    {t(T.youtube_missing)}
    + {/if} +
    diff --git a/src/lib/constants.ts b/src/lib/constants.ts new file mode 100644 index 0000000..15915ff --- /dev/null +++ b/src/lib/constants.ts @@ -0,0 +1,38 @@ +/** + * Zentrale Konstanten für die Anwendung. + * URLs, CMS-Resolve-Arrays und Fallback-Werte. + */ + +/** Platzhalter-Bild für og:image / twitter:image, wenn weder Page/Post-Bild noch Logo gesetzt ist. */ +export const DEFAULT_SOCIAL_IMAGE_URL = + "https://images.ctfassets.net/xjxq6v7l1pfe/43yZHpF9OCnrBlEWHJSZMK/1ef20b265ea1e4e55317812ee5ae6b4c/simple-green-tree-illustrated-watercolor-with-gentle-shading-great-rural-scenery-farm-backdrops-naturethemed-designs-landsca.jpg"; + +/** Parameter für og:image / twitter:image (über /cms-images + Disk-Cache). */ +export const SOCIAL_IMAGE_TRANSFORM = { + width: 200, + height: 200, + fit: "cover" as const, + format: "webp" as const, +}; + +/** CMS Content-Rows für resolve (Footer, Pages, Posts). */ +export const ROW_RESOLVE: string[] = [ + "row1Content", + "row2Content", + "row3Content", +]; + +/** Resolve für Page-Requests: "all" = alle Referenzen inkl. verschachtelt (z. B. image_gallery.images). */ +export const PAGE_RESOLVE = ["all"]; + +/** Resolve für Post-Requests: "all" damit auch img in row1Content/Image-Blöcken aufgelöst wird (src), sonst nur Referenz. */ +export const POST_RESOLVE = ["all"]; + +/** Fallback-Slug für die Startseite, wenn page_config keine homePage liefert. */ +export const DEFAULT_HOME_PAGE_SLUG = "page-home"; + +/** Site-Name für og:site_name und JSON-LD (in Layout via PUBLIC_SITE_NAME überschreibbar). */ +export const SITE_NAME = "Windwiderstand"; + +/** Slug des Translation-Bundles im CMS (content/de/translation_bundle/{slug}.json5). Alle UI-Texte aus diesem Bundle. */ +export const TRANSLATION_BUNDLE_SLUG = "app"; diff --git a/src/lib/iconify-offline.ts b/src/lib/iconify-offline.ts new file mode 100644 index 0000000..c79a430 --- /dev/null +++ b/src/lib/iconify-offline.ts @@ -0,0 +1,12 @@ +/** + * Iconify Offline: MDI-Collection für Server und Client registrieren. + * Muss an zwei Stellen importiert werden (Side-Effect-Import), damit + * überall gleich rendert (kein Hydration-Mismatch): + * 1. Layout.astro (--- Block) → läuft beim SSR + * 2. Header.svelte (oder andere frühe client:load-Komponente) → läuft im Browser + * Danach können alle Svelte-Komponenten Icon ohne API nutzen. + */ +import { addCollection } from "@iconify/svelte"; +import { icons as mdiIcons } from "@iconify-json/mdi"; + +addCollection(mdiIcons); diff --git a/src/lib/image-cache.server.ts b/src/lib/image-cache.server.ts new file mode 100644 index 0000000..ab60f0f --- /dev/null +++ b/src/lib/image-cache.server.ts @@ -0,0 +1,211 @@ +/** + * Persistenter Disk-Cache für CMS-Bilder. + * Bilder werden einmal vom CMS geholt, auf Disk gespeichert und danach + * direkt von dort ausgeliefert – kein erneuter CMS-Request nötig. + * + * Zwei Ebenen: In-Memory (LRU) für häufig angefragte Bilder, + * Disk für Persistenz über Neustarts hinweg. + */ + +import { createHash } from 'node:crypto'; +import { existsSync, mkdirSync } from 'node:fs'; +import { readFile, readdir, unlink, writeFile } from 'node:fs/promises'; +import { join } from 'node:path'; + +const CACHE_DIR = process.env.IMAGE_CACHE_DIR?.trim() || '.cache/images'; +const MAX_MEMORY_ENTRIES = Number(process.env.IMAGE_CACHE_MAX_MEMORY) || 200; + +export interface CachedImage { + buffer: Buffer; + contentType: string; +} + +export interface ImageTransformParams { + w?: number; + h?: number; + q?: number; + format?: string; + fit?: string; + ar?: string; +} + +const memoryCache = new Map(); + +let resolvedDir: string | null = null; + +function ensureCacheDir(): string { + if (resolvedDir) return resolvedDir; + const dir = join(process.cwd(), CACHE_DIR); + if (!existsSync(dir)) mkdirSync(dir, { recursive: true }); + resolvedDir = dir; + return dir; +} + +/** + * Deterministischer Cache-Key aus src + allen Transform-Parametern. + * Gleiche Eingabe = gleicher Key, unabhängig von Reihenfolge. + */ +export function buildCacheKey(src: string, params: ImageTransformParams): string { + const parts = [src]; + if (params.w != null) parts.push(`w=${params.w}`); + if (params.h != null) parts.push(`h=${params.h}`); + if (params.q != null) parts.push(`q=${params.q}`); + if (params.format) parts.push(`f=${params.format}`); + if (params.fit) parts.push(`fit=${params.fit}`); + if (params.ar) parts.push(`ar=${params.ar}`); + return createHash('sha256').update(parts.join('|')).digest('hex').slice(0, 16); +} + +function extForContentType(ct: string): string { + if (ct.includes('webp')) return 'webp'; + if (ct.includes('avif')) return 'avif'; + if (ct.includes('png')) return 'png'; + if (ct.includes('svg')) return 'svg'; + if (ct.includes('gif')) return 'gif'; + return 'jpg'; +} + +/** Content-Type für HTTP-Header aus Dateiendung (eine Datei pro Cache-Eintrag). */ +export function contentTypeFromExtension(ext: string): string { + switch (ext.toLowerCase()) { + case 'webp': + return 'image/webp'; + case 'jpg': + case 'jpeg': + return 'image/jpeg'; + case 'png': + return 'image/png'; + case 'avif': + return 'image/avif'; + case 'gif': + return 'image/gif'; + case 'svg': + return 'image/svg+xml'; + default: + return 'image/jpeg'; + } +} + +const IMAGE_FILE_EXT = new Set(['webp', 'avif', 'png', 'jpg', 'jpeg', 'gif', 'svg']); + +function rememberInMemory(key: string, cached: CachedImage): CachedImage { + if (memoryCache.size >= MAX_MEMORY_ENTRIES) { + const oldest = memoryCache.keys().next().value; + if (oldest !== undefined) memoryCache.delete(oldest); + } + memoryCache.set(key, cached); + return cached; +} + +/** + * Liest einen Cache-Eintrag: eine Datei `{key}.{webp|jpg|…}` (ein I/O). + * Fallback: altes Paar `.meta` + `.bin`. Optional `params.format`, um die Endung vorab zu probieren. + */ +export async function getCachedImage( + key: string, + params?: ImageTransformParams, +): Promise { + const mem = memoryCache.get(key); + if (mem) return mem; + + const dir = ensureCacheDir(); + + const tryFile = async (ext: string): Promise => { + try { + const buf = await readFile(join(dir, `${key}.${ext}`)); + const cached: CachedImage = { + buffer: buf, + contentType: contentTypeFromExtension(ext), + }; + return rememberInMemory(key, cached); + } catch { + return null; + } + }; + + if (params?.format) { + const ext = resolveExtension(params); + const hit = await tryFile(ext); + if (hit) return hit; + if (ext === 'jpg') { + const hitJpeg = await tryFile('jpeg'); + if (hitJpeg) return hitJpeg; + } + } + + try { + const files = await readdir(dir); + const prefix = `${key}.`; + const imageName = files.find((f) => { + if (!f.startsWith(prefix)) return false; + const rest = f.slice(prefix.length).toLowerCase(); + if (rest === 'meta' || rest === 'bin') return false; + return IMAGE_FILE_EXT.has(rest); + }); + if (imageName) { + try { + const buf = await readFile(join(dir, imageName)); + const ext = imageName.slice(prefix.length); + return rememberInMemory(key, { + buffer: buf, + contentType: contentTypeFromExtension(ext), + }); + } catch { + // weiter zu Legacy + } + } + } catch { + // ignore + } + + const metaPath = join(dir, `${key}.meta`); + const dataPath = join(dir, `${key}.bin`); + try { + const [contentType, buf] = await Promise.all([ + readFile(metaPath, 'utf8'), + readFile(dataPath), + ]); + return rememberInMemory(key, { buffer: buf, contentType }); + } catch { + return null; + } +} + +export async function cacheImage( + key: string, + buffer: ArrayBuffer | Buffer, + contentType: string, +): Promise { + const dir = ensureCacheDir(); + const buf = Buffer.isBuffer(buffer) ? buffer : Buffer.from(buffer); + const ext = extForContentType(contentType); + const cached: CachedImage = { buffer: buf, contentType }; + + rememberInMemory(key, cached); + + const base = join(dir, key); + try { + const files = await readdir(dir); + const prefix = `${key}.`; + for (const f of files) { + if (!f.startsWith(prefix)) continue; + await unlink(join(dir, f)).catch(() => {}); + } + } catch { + await unlink(`${base}.meta`).catch(() => {}); + await unlink(`${base}.bin`).catch(() => {}); + } + + await writeFile(join(dir, `${key}.${ext}`), buf); + + return cached; +} + +/** + * Dateiendung aus den Transform-Parametern oder Content-Type ableiten. + */ +export function resolveExtension(params: ImageTransformParams, contentType?: string): string { + if (params.format) return params.format === 'jpeg' ? 'jpg' : params.format; + if (contentType) return extForContentType(contentType); + return 'jpg'; +} diff --git a/src/lib/overlay-store.ts b/src/lib/overlay-store.ts new file mode 100644 index 0000000..b32376f --- /dev/null +++ b/src/lib/overlay-store.ts @@ -0,0 +1,7 @@ +import { writable } from "svelte/store"; + +/** true = Backdrop über Content anzeigen (Menü oder Suche offen). */ +export const overlayOpen = writable(false); + +/** Callback zum Schließen (setzt im Header menuOpen/searchOpen auf false). */ +export const overlayClose = writable<(() => void) | null>(null); diff --git a/src/lib/rusty-image.ts b/src/lib/rusty-image.ts new file mode 100644 index 0000000..f05e59c --- /dev/null +++ b/src/lib/rusty-image.ts @@ -0,0 +1,203 @@ +/** + * Bild-URLs für SvelteKit: /cms-images mit persistentem Server-Disk-Cache. + * Der Endpoint holt bei Bedarf vom CMS /api/transform und legt Bytes unter IMAGE_CACHE_DIR ab. + */ + +/** + * Normalisiert CMS-Loopback-URLs (127.0.0.1) zur konfigurierten PUBLIC_CMS_URL. + * Für Browser-seitigen Code (kein Node.js/fs nötig). + */ +export function absoluteUrlFromCmsImageField(field: unknown): string | null { + if (typeof field === 'string') { + const s = field.trim(); + if (!s) return null; + return s.startsWith('//') ? `https:${s}` : s; + } + if (field && typeof field === 'object') { + const o = field as { src?: string; file?: { url?: string } }; + const u = + typeof o.src === 'string' && o.src.trim() + ? o.src + : typeof o.file?.url === 'string' && o.file.url.trim() + ? o.file.url + : undefined; + if (!u) return null; + return u.startsWith('//') ? `https:${u}` : u; + } + return null; +} + +export interface RustyImageTransformParams { + width?: number; + height?: number; + ar?: string; + fit?: 'fill' | 'contain' | 'cover'; + format?: 'jpeg' | 'png' | 'webp' | 'avif'; + quality?: number; +} + +/** + * Lokale Bild-URL: /cms-images?src=…&w=…&q=… + * `src` = volle Bild-URL oder CMS-Asset-Dateiname (wird serverseitig zu /api/assets/… aufgelöst). + */ +export function getCmsImageUrl(src: string, params: RustyImageTransformParams = {}): string { + const searchParams = new URLSearchParams(); + searchParams.set('src', src); + if (params.width != null) searchParams.set('w', String(params.width)); + if (params.height != null) searchParams.set('h', String(params.height)); + if (params.ar != null) searchParams.set('ar', params.ar); + if (params.fit != null) searchParams.set('fit', params.fit); + if (params.format != null) searchParams.set('format', params.format); + if (params.quality != null) searchParams.set('q', String(params.quality)); + return `/cms-images?${searchParams.toString()}`; +} + +/** + * @deprecated Bevorzuge getCmsImageUrl — gleiche Signatur, liefert /cms-images (Disk-Cache). + */ +export function getTransformUrl(url: string, params: RustyImageTransformParams = {}): string { + return getCmsImageUrl(url, params); +} + +/** Alias für Kompatibilität (z. B. rustyastro / Layout). */ +export async function ensureTransformedImage(url: string, params: RustyImageTransformParams = {}): Promise { + return getCmsImageUrl(url, params); +} + +type ImageArrayItem = string | { src?: string }; + +function toImageUrl(item: ImageArrayItem): string | null { + if (typeof item === 'string') return item.startsWith('//') ? `https:${item}` : item; + if (item && typeof item === 'object' && typeof item.src === 'string') + return item.src.startsWith('//') ? `https:${item.src}` : item.src; + return null; +} + +export async function resolveImageUrls(items: ImageArrayItem[], params: RustyImageTransformParams = {}): Promise { + return items + .map(toImageUrl) + .filter((u): u is string => u !== null && u.startsWith('http')) + .map((u) => getCmsImageUrl(u, params)); +} + +export interface RowContentLayoutLike { + row1Content?: unknown[]; + row2Content?: unknown[]; + row3Content?: unknown[]; +} + +const MARKDOWN_IMAGE_PARAMS: RustyImageTransformParams = { + width: 1200, + fit: 'contain', + format: 'webp', + quality: 85, +}; + +const IMG_SRC_REGEX = /]*?)src\s*=\s*["']([^"']+)["']([^>]*)>/gi; + +export async function processMarkdownHtmlImages(html: string, _baseUrl?: string, transformParams: RustyImageTransformParams = MARKDOWN_IMAGE_PARAMS): Promise { + const matches = [...html.matchAll(IMG_SRC_REGEX)]; + const replacements: { index: number; length: number; newBlock: string }[] = []; + for (const m of matches) { + const rawSrc = m[2]; + const url = rawSrc.startsWith('//') ? `https:${rawSrc}` : rawSrc; + if (!url.startsWith('http')) continue; + const transformedPath = getCmsImageUrl(url, transformParams); + const href = transformedPath; + const newImg = m[0].replace(rawSrc, transformedPath); + const newBlock = `${newImg}`; + replacements.push({ index: m.index ?? 0, length: m[0].length, newBlock }); + } + if (replacements.length === 0) return html; + replacements.sort((a, b) => b.index - a.index); + let out = html; + for (const r of replacements) { + out = out.slice(0, r.index) + r.newBlock + out.slice(r.index + r.length); + } + return out; +} + +export async function resolveContentImages(layout: RowContentLayoutLike, transformParamsOrOptions: RustyImageTransformParams | { transformParams?: RustyImageTransformParams; baseUrl?: string } = {}): Promise { + const options = transformParamsOrOptions && 'baseUrl' in transformParamsOrOptions + ? (transformParamsOrOptions as { transformParams?: RustyImageTransformParams; baseUrl?: string }) + : { transformParams: transformParamsOrOptions as RustyImageTransformParams }; + const transformParams = options.transformParams ?? {}; + + const rows = [layout.row1Content, layout.row2Content, layout.row3Content].filter((r): r is unknown[] => Array.isArray(r)); + + const galleryParams: RustyImageTransformParams = { + width: 1280, + fit: 'contain', + format: 'webp', + quality: 80, + ...transformParams, + }; + + const orgLogoParams: RustyImageTransformParams = { + width: 256, + fit: 'contain', + format: 'webp', + quality: 85, + ...transformParams, + }; + + const { marked } = await import('marked'); + marked.setOptions({ gfm: true }); + + for (const content of rows) { + for (const item of content) { + if (typeof item !== 'object' || item === null) continue; + const block = item as { + _type?: string; + content?: string; + image?: unknown; + img?: unknown; + images?: Array<{ src?: string; file?: { url?: string }; resolvedSrc?: string }>; + organisations?: Array; + resolvedImageSrc?: string; + resolvedContent?: string; + }; + + if (block._type === 'markdown' && typeof block.content === 'string' && block.content.trim()) { + const html = marked.parse(block.content) as string; + block.resolvedContent = await processMarkdownHtmlImages(html, undefined, { + ...MARKDOWN_IMAGE_PARAMS, + ...transformParams, + }); + continue; + } + + if (block._type === 'image') { + const raw = block.image ?? block.img; + const url = absoluteUrlFromCmsImageField(raw); + if (url) { + block.resolvedImageSrc = getCmsImageUrl(url, transformParams); + } + continue; + } + + if (block._type === 'image_gallery' && Array.isArray(block.images)) { + for (const img of block.images) { + if (!img || typeof img !== 'object') continue; + const url = absoluteUrlFromCmsImageField(img); + if (url) { + (img as { resolvedSrc?: string }).resolvedSrc = getCmsImageUrl(url, galleryParams); + } + } + continue; + } + + if (block._type === 'organisations' && Array.isArray(block.organisations)) { + for (const org of block.organisations) { + if (!org || typeof org !== 'object') continue; + const o = org as { logo?: unknown; resolvedLogoSrc?: string }; + const url = absoluteUrlFromCmsImageField(o.logo); + if (url) { + o.resolvedLogoSrc = getCmsImageUrl(url, orgLogoParams); + } + } + continue; + } + } + } +} diff --git a/src/lib/transform-cache.ts b/src/lib/transform-cache.ts new file mode 100644 index 0000000..aed1944 --- /dev/null +++ b/src/lib/transform-cache.ts @@ -0,0 +1,123 @@ +/** + * Server-seitiger Cache für /api/transform (Bilder vom CMS). + * Reduziert Aufrufe zum CMS; gleiche Parameter = gleiche Antwort (immutable). + * + * - In-Memory: LRU-artig, begrenzt auf TRANSFORM_CACHE_MAX_ENTRIES (Default 100). + * - Optional Datei-Cache: TRANSFORM_CACHE_DIR setzen (z. B. .cache/transform). + */ + +const MAX_ENTRIES = Number(process.env.TRANSFORM_CACHE_MAX_ENTRIES) || 100; +const CACHE_DIR = process.env.TRANSFORM_CACHE_DIR?.trim() || ''; + +interface CachedImage { + buffer: ArrayBuffer; + contentType: string; +} + +const memoryCache = new Map(); + +/** Cache-Key aus Query-String (eindeutig pro URL + Parameter). */ +function cacheKey(params: string): string { + return params; +} + +/** In-Memory: ältesten Eintrag entfernen (Map behält Einfüge-Reihenfolge). */ +function evictOldest(): void { + const first = memoryCache.keys().next(); + if (first.value !== undefined) memoryCache.delete(first.value); +} + +/** Prüft, ob Datei-Cache verfügbar ist (nur Server mit fs). */ +async function getCacheDir(): Promise { + if (!CACHE_DIR) return null; + try { + const { existsSync, mkdirSync } = await import('node:fs'); + const { join } = await import('node:path'); + const dir = join(process.cwd(), CACHE_DIR); + if (!existsSync(dir)) mkdirSync(dir, { recursive: true }); + return dir; + } catch { + return null; + } +} + +/** Sicheren Dateinamen aus Key erzeugen (Hash). */ +function fileKey(key: string): string { + let h = 0; + for (let i = 0; i < key.length; i++) + h = (Math.imul(31, h) + key.charCodeAt(i)) | 0; + return Math.abs(h).toString(36) + key.length.toString(36); +} + +/** Aus Datei-Cache lesen. */ +async function getFromFile(key: string): Promise { + const dir = await getCacheDir(); + if (!dir) return null; + try { + const { readFile } = await import('node:fs/promises'); + const { join } = await import('node:path'); + const base = fileKey(key); + const metaPath = join(dir, `${base}.meta`); + const dataPath = join(dir, `${base}.bin`); + const [ct, buf] = await Promise.all([ + readFile(metaPath, 'utf8').catch(() => null), + readFile(dataPath).catch(() => null), + ]); + if (ct && buf) + return { + buffer: buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength), + contentType: ct, + }; + } catch { + // ignore + } + return null; +} + +/** In Datei-Cache schreiben. */ +async function setInFile(key: string, value: CachedImage): Promise { + const dir = await getCacheDir(); + if (!dir) return; + try { + const { writeFile } = await import('node:fs/promises'); + const { join } = await import('node:path'); + const base = fileKey(key); + await Promise.all([ + writeFile(join(dir, `${base}.meta`), value.contentType), + writeFile(join(dir, `${base}.bin`), Buffer.from(value.buffer)), + ]); + } catch { + // ignore + } +} + +/** + * Transform-Ergebnis aus Cache holen (Memory zuerst, dann Datei). + */ +export async function getCachedTransform(params: string): Promise { + const key = cacheKey(params); + const mem = memoryCache.get(key); + if (mem) return mem; + const file = await getFromFile(key); + if (file) { + if (memoryCache.size >= MAX_ENTRIES) evictOldest(); + memoryCache.set(key, file); + return file; + } + return null; +} + +/** + * Transform-Ergebnis cachen (Memory + optional Datei). + */ +export async function setCachedTransform( + params: string, + buffer: ArrayBuffer, + contentType: string, +): Promise { + const key = cacheKey(params); + const value: CachedImage = { buffer, contentType }; + if (memoryCache.size >= MAX_ENTRIES) evictOldest(); + memoryCache.set(key, value); + await setInFile(key, value); +} diff --git a/src/lib/translations.ts b/src/lib/translations.ts new file mode 100644 index 0000000..48891e9 --- /dev/null +++ b/src/lib/translations.ts @@ -0,0 +1,153 @@ +/** + * Zentrale Übersetzungen (i18n-ähnlich). + * Quelle: CMS translation_bundle (API, hooks.server.ts setzt event.locals.translations). + * Wird in +layout.server.ts geladen und über TranslationProvider/Svelte-Context bereitgestellt. + */ + +import { getContext } from "svelte"; + +export type Translations = Record; + +/** Context-Key für die t-Funktion (von TranslationProvider gesetzt). */ +export const T_CONTEXT_KEY = Symbol("translations.t"); + +/** Platzhalter für Ersetzung: z. B. { name: "Max" } ersetzt {{name}} im Übersetzungstext. */ +export type TranslationReplacements = Record; + +/** t(key) oder t(key, { placeholder: value }) – mit optionalen Ersetzungen für {{placeholder}}. */ +export type TFunction = ( + key: string, + replacements?: TranslationReplacements, +) => string; + +/** + * Ersetzt {{name}} im Text durch replacements[name]; fehlende Keys bleiben als {{name}}. + */ +export function replacePlaceholders( + text: string, + replacements?: TranslationReplacements | null, +): string { + if (!replacements || typeof text !== "string") return text; + return text.replace(/\{\{(\w+)\}\}/g, (_, name: string) => { + const val = replacements[name]; + return val !== undefined && val !== null ? String(val) : `{{${name}}}`; + }); +} + +/** + * t-Funktion aus Svelte-Context holen. + * Zuverlässig innerhalb des TranslationProvider-Baums. + */ +export function useTranslate(): TFunction { + const fromContext = getContext(T_CONTEXT_KEY); + if (fromContext) return fromContext; + return (key: string, replacements?: TranslationReplacements): string => { + return replacePlaceholders(key, replacements); + }; +} + +/** Bekannte Übersetzungs-Keys – nur hier eintragen, Nutzung über T.xy (Autocomplete, keine Tippfehler). */ +const TRANSLATION_KEYS = [ + "searchable_text_help", + "searchable_text_help_aria", + "searchable_text_placeholder", + "searchable_text_search_aria", + "searchable_text_clear_search", + "searchable_text_tag_all", + "searchable_text_no_results", + "searchable_text_count_all", + "searchable_text_count_filtered", + "searchable_text_copy_aria", + "searchable_text_copy_button", + "searchable_text_copied", + "searchable_text_untitled", + "footer_copyright", + "nav_start", + "nav_posts", + "nav_home", + "header_search_open", + "header_search_close", + "header_menu_open", + "header_menu_close", + "header_nav_aria", + "header_overlay_close", + "header_social_aria", + "site_name_fallback", + "pagination_prev", + "pagination_next", + "blog_tag_all", + "blog_filter_aria", + "blog_count", + "page_404_title", + "page_404_text", + "page_404_back", + "posts_title", + "posts_subtitle", + "posts_tag_title", + "posts_tag_subtitle", + "posts_cms_error", + "iframe_activate_aria", + "iframe_missing", + "image_gallery_swipe_aria", + "image_gallery_prev_aria", + "image_gallery_next_aria", + "image_gallery_position_aria", + "image_gallery_slide_aria", + "image_gallery_empty", + "youtube_missing", + "youtube_title_fallback", + "calendar_prev_month", + "calendar_next_month", + "calendar_weekday_mo", + "calendar_weekday_di", + "calendar_weekday_mi", + "calendar_weekday_do", + "calendar_weekday_fr", + "calendar_weekday_sa", + "calendar_weekday_so", + "calendar_more_info", + "calendar_no_events", + "calendar_time_suffix", + "calendar_select_day", + "calendar_next_events", + "calendar_show_more", + "calendar_show_less", + "post_overview_all", + "blog_search_label", + "blog_search_placeholder", + "blog_search_clear", + "blog_year_label", + "blog_year_all", + "blog_upcoming_events", + "blog_results_count", + "blog_results_for", + "blog_results_in_year", + "blog_filter_reset", + "blog_no_results", + "blog_rss_subscribe", + "post_map", + "post_map_activate", + "post_map_open_osm", + "post_comments", +] as const; + +export type TranslationKey = (typeof TRANSLATION_KEYS)[number]; + +/** Keys als Objekt: T.searchable_text_help → "searchable_text_help" (für t(T.xy)). */ +export const T: { [K in TranslationKey]: K } = Object.fromEntries( + TRANSLATION_KEYS.map((k) => [k, k]), +) as { [K in TranslationKey]: K }; + +/** + * Gibt den übersetzten Text für key zurück, optional mit Ersetzung von {{placeholder}}. + * Fallback: key selbst (damit fehlende Einträge im CMS erkennbar sind). + */ +export function t( + translations: Translations | null | undefined, + key: string, + replacements?: TranslationReplacements, +): string { + if (!key) return key; + const raw = translations?.[key] ?? key; + return replacePlaceholders(raw, replacements); +} diff --git a/src/lib/ui/Badge.svelte b/src/lib/ui/Badge.svelte new file mode 100644 index 0000000..3b95273 --- /dev/null +++ b/src/lib/ui/Badge.svelte @@ -0,0 +1,57 @@ + + +{#if href} + + {label} + +{:else if onclick} + +{:else} + {label} +{/if} diff --git a/src/lib/ui/Breadcrumbs.svelte b/src/lib/ui/Breadcrumbs.svelte new file mode 100644 index 0000000..09a1397 --- /dev/null +++ b/src/lib/ui/Breadcrumbs.svelte @@ -0,0 +1,41 @@ + + + diff --git a/src/lib/ui/Button.svelte b/src/lib/ui/Button.svelte new file mode 100644 index 0000000..3fec64d --- /dev/null +++ b/src/lib/ui/Button.svelte @@ -0,0 +1,46 @@ + + + diff --git a/src/lib/ui/Checkbox.svelte b/src/lib/ui/Checkbox.svelte new file mode 100644 index 0000000..470fe48 --- /dev/null +++ b/src/lib/ui/Checkbox.svelte @@ -0,0 +1,23 @@ + + + diff --git a/src/lib/ui/Radio.svelte b/src/lib/ui/Radio.svelte new file mode 100644 index 0000000..b3868c1 --- /dev/null +++ b/src/lib/ui/Radio.svelte @@ -0,0 +1,25 @@ + + + diff --git a/src/lib/ui/Select.svelte b/src/lib/ui/Select.svelte new file mode 100644 index 0000000..2484d6d --- /dev/null +++ b/src/lib/ui/Select.svelte @@ -0,0 +1,49 @@ + + +
    + {#if label} + + {/if} +
    + + +
    +
    diff --git a/src/lib/ui/SidebarNav.svelte b/src/lib/ui/SidebarNav.svelte new file mode 100644 index 0000000..4c55f29 --- /dev/null +++ b/src/lib/ui/SidebarNav.svelte @@ -0,0 +1,33 @@ + + + diff --git a/src/lib/ui/Slider.svelte b/src/lib/ui/Slider.svelte new file mode 100644 index 0000000..fe43d48 --- /dev/null +++ b/src/lib/ui/Slider.svelte @@ -0,0 +1,39 @@ + + +
    + {#if label} +
    + + {value} +
    + {/if} + +
    + {min} + {max} +
    +
    diff --git a/src/lib/ui/TabBar.svelte b/src/lib/ui/TabBar.svelte new file mode 100644 index 0000000..91b4204 --- /dev/null +++ b/src/lib/ui/TabBar.svelte @@ -0,0 +1,51 @@ + + +
    + {#each tabs as tab} + + {/each} +
    diff --git a/src/lib/ui/TextInput.svelte b/src/lib/ui/TextInput.svelte new file mode 100644 index 0000000..45f88d2 --- /dev/null +++ b/src/lib/ui/TextInput.svelte @@ -0,0 +1,57 @@ + + +
    + {#if label} + + {/if} + + {#if error} + + {:else if helpText} +

    + {helpText} +

    + {/if} +
    diff --git a/src/lib/ui/Textarea.svelte b/src/lib/ui/Textarea.svelte new file mode 100644 index 0000000..9928b6a --- /dev/null +++ b/src/lib/ui/Textarea.svelte @@ -0,0 +1,57 @@ + + +
    + {#if label} + + {/if} +