Napojení a token
Šablona se na patro napojuje jedním tokenem. Není v tom žádná registrace aplikace, žádný OAuth a žádné ID webu v adrese — token sám určuje, čí obsah dostanete.
Odkud se token bere
Sekce “Odkud se token bere”Vydá ho vlastník webu v administraci patra (Administrace → API tokeny; editor
tam nemá přístup). Dostane podobu pat_… a ukáže se jen jednou, při vydání —
patro si z něj drží jen otisk a začátek, takže znovu ho vypsat nejde. Když se
ztratí, vydá se nový a starý se zruší.
Ten začátek (pat_ a osm znaků) je v seznamu vidět a je tam kvůli jediné
otázce: který řádek odpovídá klíči nasazenému na kterém webu. K tokenu se dá při
vydání nastavit i platnost; bez ní nevyprší.
Token nese identitu webu (v žargonu patra „tenanta“). Odtud plyne to podstatné:
- do dotazů se nikdy neposílá ID webu — server si ho odvodí z tokenu;
- token z jednoho webu nemá jak sáhnout na obsah jiného, i kdyby se o to pokusil, protože se dotaz omezuje na serveru, ne v klientovi;
- kdo má token, ten webu vidí do publikovaného obsahu.
Je to tajemství, ne veřejný klíč
Sekce “Je to tajemství, ne veřejný klíč”Token patří k serverové části vaší šablony a nesmí se dostat do prohlížeče. Prakticky to znamená dvě věci:
- Ukládá se jako secret, ne jako proměnná v konfiguraci. Na Cloudflare
wrangler secret put PATRO_TENANT_TOKEN, lokálně do.dev.vars. - Nikdy se nepředává komponentě, která má
client:*direktivu. Astro props ostrůvků serializuje do HTML stránky, takže by token skončil ve zdrojovém kódu, který si přečte kdokoli.
Když potřebuje něco odeslat prohlížeč (typicky formulář komentáře), nechodí do patra přímo — jde na endpoint vaší šablony a ten to s tokenem přepošle. Hotový prostředník na to v balíku je a popisuje ho kapitola o blocích.
Co token umí — celý rozsah, žádné zúžení
Sekce “Co token umí — celý rozsah, žádné zúžení”Buďme přesní, protože je to bezpečnostní téma. Token nejde vydat užší. Není volba „jen pro čtení“: kdo ho má, umí kromě čtení i těch pár zápisů, které veřejné API má:
- nahlásit nenalezené adresy a zásahy přesměrování (
client.reportRedirects), - ohlásit, které oblasti widgetů šablona kreslí (
client.declareWidgetAreas), - poslat komentář prostředníkem.
Všechny tři zapisují výhradně do dat toho webu, kterému token patří, a mají vlastní stropy (velikost dávky, počet oblastí, délky).
Praktický závěr: hranici drží příslušnost k webu, ne rozsah oprávnění. Token z jednoho webu na cizí obsah nedosáhne, ale uvnitř svého webu ho nic dál nezužuje — počítejte s tím při rozhodování, kam ho uložíte a komu ho dáte.
Postavení klienta
Sekce “Postavení klienta”import { env } from "cloudflare:workers"import { createPatroClient, type PatroClient } from "@patro/render"
export function getPatroClient(): PatroClient { return createPatroClient({ baseUrl: env.PUBLIC_API_BASE, token: env.PATRO_TENANT_TOKEN, })}Klient se staví při každém požadavku, ne jednou při startu. Na Cloudflare je
env proxy, která se vyhodnocuje až za běhu požadavku — kdyby se hodnota
přečetla při načtení modulu, byla by prázdná. Ze stejného důvodu se do funkcí,
které klienta potřebují později (middleware, oblasti widgetů), předává továrna
getPatroClient, ne hotový klient.
Konfigurace
Sekce “Konfigurace”createPatroClient({ baseUrl: "https://patro.priklad.cz", // koncové lomítko se ořeže token: "pat_…", fetch: mujFetch, // volitelné — vlastní runtime nebo test timeoutMs: 5_000, // volitelné — výchozí PATRO_REQUEST_TIMEOUT_MS})timeoutMs stojí za jednu větu navíc. Cloudflare žádný strop na podřízené
dotazy nemá — pomalé (ne padající) patro by se propsalo přímo do doby, kterou
návštěvník čeká na stránku, a nic by to nezastavilo. Výchozích pět sekund je
kompromis: dost na studený start patra, málo na to, aby se kvůli výpadku zasekla
stránka.
Proměnné prostředí
Sekce “Proměnné prostředí”| Jméno | Druh | K čemu |
|---|---|---|
PUBLIC_API_BASE |
var | Adresa patra, např. https://patro.priklad.cz |
PATRO_TENANT_TOKEN |
secret | Token webu |
Pojmenování je jen konvence našeho pilotního webu — klient bere hodnoty parametrem, takže si je můžete číst odkudkoli.
Jak klient hlásí, že se něco nepovedlo
Sekce “Jak klient hlásí, že se něco nepovedlo”Tohle je jediná konvence, kterou je potřeba znát dřív, než se napíše první stránka. Klient rozlišuje tři výsledky, ne dva:
Hodnota — povedlo se.
null — legitimní odpověď „tohle tu není“ nebo „beze změny“. Není to chyba
a nemá se z toho dělat pětistovka:
client.getEntryBySlugvrátínullu slugu, který v daném jazyce publikovaný není → vaše 404;client.getMenuvrátínullu menu, které web nemá → vykreslete stránku bez navigace;- metody s
knownVersion(client.getRedirects,client.listWidgetAreas,client.getComments) vrátínull, když se od vámi držené podoby nic nezměnilo → nechte si, co máte.
Pozor na rozdíl mezi null a prázdným seznamem. Prázdné pole znamená „existuje
to a je to prázdné“; null znamená „to konkrétní, na co ses ptal, tu není“.
Odmítnutý příslib — všechno ostatní: špatný token (401), výpadek patra,
překročený strop. Klient nikdy nevrací tiché null místo chyby, takže se
rozbité napojení nemůže projevit jako prázdná stránka.
Výpadek patra
Sekce “Výpadek patra”Odmítnutí musí někdo chytit a rozhodnout, jestli se stránka ještě dá vykreslit. Balík na to má trojici, kterou stačí zapojit:
---import { isOutage, loadContent, outageResponse } from "@patro/render"import { getPatroClient } from "../lib/patro"
const client = getPatroClient()const patroDown = (error: unknown): void => { console.error("patro: obsah stránky — ", error)}
// Volání schované do proměnné schválně: `astro check` výraz vracený// z hlavičky stránky nekontroluje, takže tady se ověří, a v `return`// pak zbývá `outage()`, kde se není čeho chytit.const outage = (): Response => outageResponse()
const tenant = await loadContent(() => client.getTenant(), patroDown)if (isOutage(tenant)) return outage()---outageResponse odpoví 503 s hlavičkou Retry-After a čitelnou stránkou,
ne pětistovkou — pro vyhledávače je to „zkus to za chvíli“, ne „tahle stránka je
rozbitá“.
Obal patří jen kolem volání patra. Chyba ve vlastním kódu se nemá vydávat za výpadek patra; ta patří na vaši chybovou stránku.
A platí to jen pro obsah. Navigace, oblasti widgetů a dopočet výpisových bloků se ošetřují tolerantně samy — nedostupné patro u nich znamená stránku bez té ozdoby, ne 503.