Orbito - Dokumentacja modułówOrbito - Dokumentacja modułów
Wprowadzenie
Pierwsze kroki
API
Komunikacja
Widoki
Wdrożenie
Społeczność
For AI agents
Wprowadzenie
Pierwsze kroki
API
Komunikacja
Widoki
Wdrożenie
Społeczność
For AI agents
  • API biblioteki

    • API biblioteki @orbito/api-lib
    • Core
    • Log
    • Utils
    • Pages
    • Strony publiczne
    • Automation
    • DB
    • Config
    • Files
    • Problems
    • History
    • OAuth
    • Time
    • Mail
    • Templates
    • Lock
    • Uprawnienia

Strony publiczne

Strona publiczna to widok OVE dostępny bez logowania, np. karta zamówienia dla klienta sklepu, do której prowadzi link z maila. Moduł rejestruje ją przez Pages.registerPublicPages (od SDK 4.5.0), a adres składa platforma:

https://orbi.do/p/<instanceId>/<pageCode>/?param=wartość
  • <instanceId> to identyfikator instancji modułu, która zarejestrowała stronę. Firma nie występuje w adresie — wynika z instancji.
  • <pageCode> to kod strony: jeden segment [a-z0-9-], do 40 znaków ('/track' w deklaracji to pageCode = 'track').
  • Dane wejściowe strona dostaje wyłącznie w query (w widoku {{ $page.urlParams.param }}). Parametrów w ścieżce nie ma.

Strona publiczna działa na osobnej domenie orbi.do, więc nie ma dostępu do sesji pracowników zalogowanych w panelu (my.orbi.do). Nie ma przełącznika w panelu firmy — strona działa od aktualizacji modułu, a po odinstalowaniu instancji znika.

const { Pages } = require('@orbito/api-lib');

Pages.registerPublicPages

Pages.registerPublicPages(pages)
ParametrTypOpis
pagesobjectMapa '/pageCode' → definicja strony (wiodący / jest opcjonalny)

Definicja strony:

PoleTypWymaganeOpis
namestring | object✔Nazwa strony w nagłówku: string albo mapa językowa { pl, en }
viewstring✔Ścieżka do pliku widoku .yaml/.yml/.json, jak w registerPages

placement i moduleDependencies są tu błędem — strona publiczna nie trafia do żadnego menu. Deklaracja strony nie wylicza metod: to, co strona może wywołać, określają flagi public: true na metodach (patrz niżej).

Rejestracja działa jak registerPages: można wołać wielokrotnie, platforma robi replace-set (strony, których moduł przestał deklarować, usuwa), a po reconnect zestaw idzie ponownie. Błędna definicja odrzuca całe wywołanie, zanim cokolwiek zmieni. Funkcja zwraca Promise<{ registered, removed }>.

Pages.registerPublicPages({
    '/track': {
        name: { pl: 'Twoje zamówienie', en: 'Your order' },
        view: 'pages/public/track.yaml'
    }
});

Metody publiczne

Strona publiczna woła zwykłe metody modułu, ale tylko te zarejestrowane z public: true w formie opisowej Core.registerMethod. Skrócona forma (sama funkcja) nigdy nie jest publiczna. Każde wywołanie innej metody kończy się odpowiedzią 403 z kodem METHOD_NOT_PUBLIC, zanim platforma dotknie modułu.

Metoda publiczna dostaje kontekst bez użytkownika:

ctx = {
    public: true,
    userId: null,
    permissions: [],
    caller: null,
    origin: null,
    publicPage: { instanceId, pageCode }
}

ctx.publicPage.pageCode pochodzi z nagłówka wysyłanego przez przeglądarkę i nie jest weryfikowany — nie opieraj na nim autoryzacji. Metody używające Core.hasPermission(code, ctx.permissions) odmówią same (puste uprawnienia).

Strona może wołać metody własnej instancji, a także metody publiczne innych instancji tej samej firmy (po kodzie modułu albo identyfikatorze instancji, jak w callMethod / callInstanceMethod). Instancja spoza firmy to 404.

Waliduj wejście i zwracaj minimum

Platforma nie waliduje params (schemat służy tylko dokumentacji), a metodę publiczną może wywołać każdy, kto zna adres — także z innymi parametrami niż te, które wysyła Twoja strona. Sprawdzaj każde wejście w handlerze i zwracaj zamkniętą listę pól przeznaczonych dla odbiorcy strony, nigdy całego dokumentu z bazy.

Klucz w adresie strony ma być losowy i nieodgadywalny — uuid v4 wygenerowany przy tworzeniu rekordu (np. order.uuid) albo długi token, a nie _id z bazy, bo sąsiednie ObjectId da się odgadnąć. Metoda waliduje format klucza przed zapytaniem do bazy i szuka po tym polu, a nie po _id. Zwraca zamkniętą listę pól bez danych osobowych, bo link bywa przekazywany dalej.

const { Core } = require('@orbito/api-lib');

const ORDER_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;

Core.registerMethod('public.getOrder', {
    description: 'Publiczna karta zamówienia dla klienta sklepu (bez danych osobowych).',
    public: true,
    params: { t: { type: 'string' } },
    handler: async ({ t } = {}) => {
        if (typeof t !== 'string' || !ORDER_UUID_RE.test(t)) {
            throw new Error('ORDER_NOT_FOUND');
        }
        const order = await Order.findOne({ uuid: t, isRemoved: { $ne: true } });
        if (!order) {
            throw new Error('ORDER_NOT_FOUND');
        }
        // tylko pola dla klienta: bez adresu, e-maila, telefonu, nazwiska i uwag
        return {
            number: order.name,
            status: { name: order.statusName, color: order.statusColor },
            total: order.summary?.gross,
            currency: order.currency || 'PLN'
        };
    }
});

Widok strony publicznej

Plik widoku to zwykły widok OVE. Parametr z adresu czytasz przez $page.urlParams, dane pobierasz metodą publiczną (dynamic z module i method). Fragment pages/public/track.yaml z core.orders:

type: dynamic
id: trackOrder
module: core/orders
method: public.getOrder
params:
  t: '{{ $page.urlParams.t }}'
loadingMessage: Ładowanie zamówienia...
failSoft: false
fetchErrorMessage: Nie znaleziono zamówienia. Sprawdź, czy link jest kompletny.
template:
  type: card
  title:
    type: text
    content: 'Zamówienie {{ trackOrder.number }}'
  content:
    - type: badge
      content: '{{ trackOrder.status.name }}'
      color: '{{ trackOrder.status.color }}'
      light: true
    - type: text
      content: 'Razem: {{ money trackOrder.total }} {{ trackOrder.currency }}'
      weight: bold
      align: end

Ograniczenia trybu publicznego

Strona publiczna jest renderowana w trybie ograniczonym:

  • widoki prezentacyjne i formularze działają normalnie; akcja callMethod wywołuje tylko metody public: true;
  • widoki plików (image, filePreview, filePicker) i pliki modułów są zablokowane, podobnie jak scope $global;
  • akcja navigate prowadzi wyłącznie do stron publicznych tej samej instancji; redirect na adres http(s) jest dozwolony;
  • zmienne strony nie są zapisywane w localStorage;
  • język wybiera parametr ?lang= (np. ?lang=en), a gdy go brak — język przeglądarki. Nazwa strony jako mapa { pl, en } jest tłumaczona; treść content w OVE nie przyjmuje map językowych, więc teksty widoku piszesz w jednym języku;
  • nagłówek strony to jej nazwa i nazwa firmy, bez logo; strony mają X-Robots-Tag: noindex.

Pages.publicUrl

Zwraca pełny adres strony zarejestrowanej w tej instancji. Adres składa platforma — moduł nie zna formatu ani domeny i nie powinien go składać ręcznie.

Pages.publicUrl(pageCode, query?)
ParametrTypOpis
pageCodestringKod strony, z wiodącym / albo bez ('/track', 'track')
queryobjectParametry query, np. { t: order.uuid }; wartości: string, liczba lub boolean

Zwraca Promise<string>, np. https://orbi.do/p/<instanceId>/track/?t=<uuid>. Promise jest odrzucany, gdy kod jest niepoprawny albo strona nie została zarejestrowana.

Typowe zastosowanie to zmienna szablonu wiadomości z linkiem do strony. Fragment z core.orders — brak adresu nie może wywrócić całej wiadomości, więc zmienna zostaje wtedy pusta:

async function trackingUrl(order) {
    try {
        return await Pages.publicUrl('/track', { t: order.uuid });
    } catch (err) {
        Log.warn('Nie udało się zbudować adresu strony zamówienia', { error: err.message });
        return '';
    }
}

Limity

Strony publiczne i ich metody są chronione limiterem w rdzeniu:

LimitWartość
Na adres IP klienta120 żądań / min
Na instancję600 żądań / min

Po przekroczeniu platforma odpowiada 429 RATE_LIMITED z nagłówkiem Retry-After. Strona jest wtedy chwilowo niedostępna — pamiętaj, że limit na instancję dzielą wszyscy odwiedzający, więc nie projektuj stron, które w tle odpytują metodę w pętli. Odpowiedzi mają Cache-Control: no-store.

Bezpieczeństwo

Identyfikator w adresie jest jedynym „kluczem"

Strona publiczna nie ma logowania — dostęp wyznacza wyłącznie znajomość adresu. Dlatego:

  • zwracaj minimum danych i żadnych danych osobowych (imię, adres, e-mail, telefon, uwagi klienta);
  • waliduj każdy parametr w metodzie publicznej i na nieistniejący lub niepoprawny identyfikator odpowiadaj tym samym błędem, żeby nie zdradzać, co istnieje;
  • nie używaj _id z bazy jako klucza w adresie — ObjectId jest odgadywalny (sąsiednie wartości różnią się nieznacznie); wstawiaj losowy klucz, patrz Metody publiczne. core.orders używa order.uuid pod parametrem t;
  • nie zakładaj, że publicPage.pageCode mówi, skąd przyszło wywołanie — zgłasza go klient.
Ostatnio zaktualizowano:: 27.10.2026, 12:49
Contributors: Wiktor Koźmiński, Claude Fable 5.1, Claude Opus 5.5
Prev
Pages
Next
Automation