UI-slotok és az iframe-protokoll
Egy marketplace-app a manifest ui_extensions listájával jelenik meg a Vecton
felületén. Minden megjelenés egy slotra kerül, és kattintásra (vagy fülként)
a saját szervereden futó oldalt nyitja meg egy sandboxolt iframe-ben.
Slotok
| Slot | Hol | Típus |
|---|---|---|
order.detail.actions | a rendelés adatlapjának fejlécében, gombként | button, list_item |
order.detail.tabs | a rendelés adatlapján, saját füles kártyán | tab |
settings.shipping.methods | a fizetési és szállítási módok beállításánál, listasorként | button, list_item |
buttonéslist_item: kattintásra modális ablakban nyílik az iframe.tab: az iframe a fülön belül, csak az aktív fülön töltődik be; fülváltáskor a régi iframe lezárul.
{
"slot": "order.detail.actions",
"type": "button",
"label": "Acme címke",
"icon": "mdi-package-variant",
"entrypoint": "order_action"
}
Az entrypoint a manifest entrypoints blokkjának egy kulcsa — a
megjelenés nem hordoz nyers URL-t, így minden iframe-cím egy helyen, a review
által látott módon él.
Biztonsági keret
- Saját origin. Az app oldala mindig a saját domaineden fut, sosem a Vecton
originjén. Csak
https://cím fogadható el. - Rögzített originek. Telepítéskor a Vecton rögzíti a jóváhagyott manifest belépési pontjainak originjét. Ha egy későbbi manifest másik originre mutat, az csak újratelepítéssel (új hozzájárulással) lép életbe; addig az iframe nem jelenik meg.
- Sandbox
allow-same-originnélkül:sandbox="allow-scripts allow-forms allow-popups-to-escape-sandbox". Az iframe-ben futó oldal opaque originként viselkedik: nem éri el a Vecton sütijeit és tárolóit, és a sajátlocalStorage-a, sütijei sem megbízhatók benne — a munkamenetedet azinitüzenet tokenjére és a saját szervered állapotára építsd. referrerpolicy="no-referrer", és minden böngészőfunkció (kamera, mikrofon, helymeghatározás, …) tiltva.- A felhasználó Vecton-tokenje soha nem kerül az iframe-be — csak a rövid életű, az appra szűkített app-token.
A postMessage-protokoll
Mivel a sandboxolt dokumentum originje "null", az üzenetek hitelességét egy
nonce biztosítja. A Vecton minden betöltéskor újat generál, és az iframe
címének fragmentjébe teszi:
https://app.acme-szallitas.hu/vecton/order-action#vecton_nonce=<nonce>
A fragment nem megy ki a hálózatra és nem kerül a Refererbe. Az app olvassa ki induláskor, és minden üzenetébe tegye bele; a Vecton a nonce nélküli vagy eltérő nonce-ú üzenetet eldobja. Ha az app az iframe-en belül teljes oldalbetöltéssel navigál, a fragmentet magának kell továbbvinnie.
| Irány | type | Mezők | Mire való |
|---|---|---|---|
| app → Vecton | vecton:ready | nonce | az app betöltött, kéri az init-et |
| Vecton → app | vecton:init | locale, theme (light | dark), context, token, apiBaseUrl, nonce | kontextus és app-token |
| app → Vecton | vecton:resize | height, nonce | a keret magasságának igazítása (képpontban, 4000 alatt) |
| app → Vecton | vecton:close | nonce | a modális ablak bezárása |
- A
contextcsak azonosítókat tartalmaz (például a rendelés azonosítóját), titkot soha. A részletes adatot az app a tokennel kérje le az API-ból. - A
tokenlehetnull— ilyenkor az app csak megjelenít, API-t nem hív. Fül típusnál a token az init után is érkezhet; ilyenkor a Vecton újvecton:init-et küld. - Az
apiBaseUrla szervezet címe; a modulok ennek/api/<modul>/…útvonalán érhetők el. - A Vecton üzenetei is hordozzák a nonce-ot: az app ellenőrizze, hogy
event.source === window.parent, és a nonce egyezik.
const nonce = new URLSearchParams(location.hash.slice(1)).get('vecton_nonce')
let init = null
window.addEventListener('message', event => {
if (event.source !== window.parent || event.data?.nonce !== nonce) return
if (event.data.type === 'vecton:init') {
init = event.data
render(init)
}
})
window.parent.postMessage({ type: 'vecton:ready', nonce }, '*')
function fit() {
window.parent.postMessage({ type: 'vecton:resize', height: document.body.scrollHeight, nonce }, '*')
}
Ha az app egy ideig nem küld vecton:ready-t, a Vecton betöltési hibát mutat a
felhasználónak.