@jensweigel/puny-kit (0.1.0)
Installation
@jensweigel:registry=https://gitea.jensweigel.com/api/packages/jensweigel/npm/npm install @jensweigel/puny-kit@0.1.0"@jensweigel/puny-kit": "0.1.0"About this package
@jensweigel/puny-kit
Internes SvelteKit-Paket für das puny CMS: API-Client, gemeinsame TypeScript-Typen, ein Uploads-Proxy und eine Hooks-Integration. Wird über die private Gitea npm Registry verteilt und in den SvelteKit-Frontends genutzt.
Warum
@jensweigel/…? Die Gitea-Registry routet über den Scope: npm schickt Installs von@jensweigel/*an deine Gitea-Instanz, ohne die globale Default-Registry zu ändern. Der Paketname ist deshalb scoped, auch wenn wir intern von „puny-kit" sprechen.
- Node ≥ 22.12
- SvelteKit 2.x (Peer-Dependency)
- Reines TypeScript, ESM
Umgebungsvariablen
| Variable | Zweck | Pflicht |
|---|---|---|
PUNY_BACKEND_URL |
Basis-URL des puny-Backends (ohne /api/cms) |
ja |
PUNY_API_KEY |
Site-API-Schlüssel, wird als X-API-Key gesendet |
ja¹ |
¹ Für den reinen Uploads-Proxy reicht PUNY_BACKEND_URL. Der API-Client
braucht zusätzlich PUNY_API_KEY.
Beide Werte lassen sich auch direkt im Code übergeben (siehe unten) — praktisch,
wenn du sie aus $env/dynamic/private beziehen willst.
Installation im Frontend
1. Registry für den Scope hinterlegen
.npmrc im Frontend-Projekt (bzw. ~/.npmrc):
@jensweigel:registry=https://gitea.jensweigel.com/api/packages/jensweigel/npm/
//gitea.jensweigel.com/api/packages/jensweigel/npm/:_authToken=${GITEA_TOKEN}
GITEA_TOKEN ist ein Gitea Access Token (Scope: read:package). In der
Shell / im Coolify-Build als Umgebungsvariable bereitstellen — so landet das
Token nicht im Repo.
2. Paket installieren
npm install @jensweigel/puny-kit
Nutzung
API-Client
import { PunyClient } from '@jensweigel/puny-kit'
// Konfiguration aus PUNY_BACKEND_URL / PUNY_API_KEY:
const puny = new PunyClient()
// … oder explizit (z. B. mit $env/dynamic/private):
import { env } from '$env/dynamic/private'
const puny2 = new PunyClient({
backendUrl: env.PUNY_BACKEND_URL,
apiKey: env.PUNY_API_KEY
})
// src/routes/[...slug]/+page.server.ts
import { error } from '@sveltejs/kit'
import { PunyClient } from '@jensweigel/puny-kit'
export const load = async ({ params, fetch }) => {
const puny = new PunyClient({ fetch }) // event.fetch durchreichen
const page = await puny.getScope(params.slug)
if (!page) throw error(404)
return { page }
}
Verfügbare Methoden (alle geben bei 404 null zurück, werfen bei anderen
Fehlern einen PunyError):
| Methode | Endpoint |
|---|---|
getScope(slug) |
GET /api/cms/scopes/{slug} |
getScopes() |
GET /api/cms/scopes |
getScopeChildren(slug) |
GET /api/cms/scopes/{slug}/children |
getNavigation(slug = 'mainnav') |
GET /api/cms/scopes/{slug} |
getContent(slug) |
GET /api/cms/contents/{slug} |
getGlobals() |
GET /api/cms/globals |
getGallery(slug) |
GET /api/cms/galleries/{slug} |
getTermine() |
GET /api/cms/termine |
getSeminare() |
GET /api/cms/seminare |
search(q) |
GET /api/cms/search?q= |
submitForm(slug, formData) |
POST /api/cms/forms/{slug}/submit |
Alle Methoden nehmen optionale { preview, fetch, query }-Optionen. Preview:
const page = await puny.getScope(params.slug, {
preview: url.searchParams.get('preview')
})
Fehlerbehandlung:
import { PunyError } from '@jensweigel/puny-kit'
try {
await puny.getScopes()
} catch (e) {
if (e instanceof PunyError) console.error(e.status, e.url, e.message)
}
Hooks-Integration
Legt pro Request einen konfigurierten Client unter event.locals.puny ab:
// src/hooks.server.ts
import { createPunyHandle } from '@jensweigel/puny-kit/hooks'
export const handle = createPunyHandle()
// src/app.d.ts
import type { PunyClient } from '@jensweigel/puny-kit'
declare global {
namespace App {
interface Locals {
puny: PunyClient
}
}
}
export {}
// danach in jeder load-Funktion:
export const load = async ({ locals, params }) => {
return { page: await locals.puny.getScope(params.slug) }
}
Mehrere Hooks kombinieren mit sequence:
import { sequence } from '@sveltejs/kit/hooks'
import { createPunyHandle } from '@jensweigel/puny-kit/hooks'
export const handle = sequence(createPunyHandle() /*, weitereHandle */)
Uploads-Proxy
Kopiere die Vorlage aus src/routes/uploads/[...path]/+server.ts dieses Repos
in dein Frontend nach src/routes/uploads/[...path]/+server.ts:
import { createUploadsProxy } from '@jensweigel/puny-kit/proxy'
const proxy = createUploadsProxy()
export const GET = proxy
export const HEAD = proxy
Damit werden /uploads/* an ${PUNY_BACKEND_URL}/uploads/* weitergeleitet
(Backend-URL bleibt für den Client verborgen) und mit
Cache-Control: public, max-age=31536000, immutable ausgeliefert. Bilder-URLs
aus der API (image.url) zeigen dann auf den eigenen /uploads-Pfad, sofern
das Backend relative bzw. proxy-fähige URLs liefert.
Optionen: createUploadsProxy({ cacheControl, pathPrefix, backendUrl, fetch }).
Typen
import type { PunyScope, PunyContent, PunyImage } from '@jensweigel/puny-kit'
Veröffentlichen (Gitea Registry)
-
Access Token in Gitea erstellen (Einstellungen → Anwendungen → Token generieren) mit Scope
write:package. -
Token für die Publish-Registry hinterlegen — im Paket-Repo als
.npmrc(nicht committen!) oder global://gitea.jensweigel.com/api/packages/jensweigel/npm/:_authToken=${GITEA_TOKEN}Die Ziel-Registry steht bereits in
package.jsonunterpublishConfig.registry. -
Bauen und veröffentlichen:
npm version patch # Version erhöhen (patch/minor/major) npm publish # baut vorher via prepublishOnlyprepublishOnlyruftnpm run buildauf; es wird nurdist/gepackt (siehefiles).
Neue Version im Frontend ziehen: npm update @jensweigel/puny-kit (bzw. die
Version in package.json anheben und npm install).
Entwicklung
npm install # Dev-Abhängigkeiten
npm run build # tsc → dist/ (JS + .d.ts)
npm run check # Typprüfung ohne Emit
Quellcode in src/lib/:
| Datei | Inhalt |
|---|---|
client.ts |
PunyClient, PunyError |
types.ts |
gemeinsame TypeScript-Interfaces |
proxy.ts |
createUploadsProxy |
hooks.ts |
createPunyHandle |
index.ts |
Sammel-Export |
src/routes/ enthält nur die Vorlage für die Uploads-Route und wird nicht
gebaut/veröffentlicht.
Dependencies
Development Dependencies
| ID | Version |
|---|---|
| @sveltejs/kit | ^2.0.0 |
| @types/node | ^22.10.0 |
| typescript | ^5.6.0 |
Peer Dependencies
| ID | Version |
|---|---|
| @sveltejs/kit | ^2.0.0 |