Jens Weigel jensweigel

@jensweigel/puny-kit (0.1.0)

Published 2026-07-26 18:23:59 +00:00 by jensweigel

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

Client, Typen, Uploads-Proxy und Hooks für das puny CMS (SvelteKit-Frontends).

@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)

  1. Access Token in Gitea erstellen (Einstellungen → Anwendungen → Token generieren) mit Scope write:package.

  2. 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.json unter publishConfig.registry.

  3. Bauen und veröffentlichen:

    npm version patch      # Version erhöhen (patch/minor/major)
    npm publish            # baut vorher via prepublishOnly
    

    prepublishOnly ruft npm run build auf; es wird nur dist/ gepackt (siehe files).

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

Keywords

puny cms sveltekit headless
Details
npm
2026-07-26 18:23:59 +00:00
15
UNLICENSED
latest
14 KiB
Assets (1)
Versions (1) View all
0.1.0 2026-07-26