Core
Moduł Core jest centrum komunikacji między modułem a platformą Orbito. Pozwala rejestrować metody i hooki wywoływane przez platformę, wywoływać metody innych modułów oraz wykonywać wychodzące zapytania HTTP.
Tożsamość modułu
Kontener obsługuje dokładnie jedną instalację modułu (instancję) jednej firmy. Obie wartości pochodzą z tokenu połączenia, są stałe przez cały cykl życia procesu i moduł nigdy ich nie wysyła samodzielnie.
const { Core } = require('@orbito/api-lib');
Core.getCompanyId(); // 'string' – firma obsługiwana przez ten kontener
Core.getInstanceId(); // 'string' – identyfikator TEJ instalacji modułu
Core.getModuleInfo(); // { instanceId, companyId, code, version }
| Metoda | Zwraca | Opis |
|---|---|---|
getCompanyId() | string | null | Firma, w kontekście której działa kontener |
getInstanceId() | string | null | Identyfikator instalacji modułu (instanceId) |
getModuleInfo() | object | { instanceId, companyId, code, version } |
Wartości są null, dopóki moduł nie zakończy rejestracji w platformie.
Po co mi instanceId
Firma może zainstalować ten sam moduł wielokrotnie (np. trzy sklepy). instanceId pozwala innym modułom wywołać konkretnie tę instalację przez Core.callInstanceMethod oraz porównać się z ctx.caller.instanceId. Szczegóły w Kontekst firmy i instancji.
Core.registerMethod
Rejestruje metodę, którą platforma Orbito lub inne moduły mogą wywołać przez Core.callModule.
Metoda obsługuje dwie formy rejestracji:
Forma podstawowa
Core.registerMethod(name, handler)
| Parametr | Typ | Opis |
|---|---|---|
name | string | Nazwa metody, np. 'search', 'config.get' |
handler | Function | Asynchroniczny handler metody |
Forma opisowa (zalecana)
Core.registerMethod(name, {
params: { /* schemat fastest-validator */ },
returns: { /* schemat fastest-validator */ },
handler: async (params, ctx) => { ... }
})
| Pole | Typ | Opis |
|---|---|---|
params | object | Schemat parametrów wejściowych w formacie fastest-validator |
returns | object | Schemat wartości zwracanej w formacie fastest-validator |
handler | Function | Asynchroniczny handler metody |
Dzięki opisaniu params i returns platforma może automatycznie walidować dane oraz w przyszłości generować dokumentację API.
Sygnatura handlera:
async (params, ctx) => { ... }
| Argument | Typ | Opis |
|---|---|---|
params | object | Argumenty przekazane przez wywołującego |
ctx | object | Kontekst żądania – dane sesji, uprawnienia, ctx.caller |
ctx.caller to tożsamość wywołującej instancji ({ instanceId, moduleCode, instanceName }) przy ruchu moduł → moduł, albo null, gdy metodę wywołała sama platforma (użytkownik, automatyzacja). Ten sam obiekt jest dostępny w handlerze jako this – this.caller działa więc identycznie w metodach i w hookach.
Brak companyId w sygnaturze
Handler nie otrzymuje companyId ani własnego instanceId. Kontener modułu obsługuje dokładnie jedną instalację jednej firmy, a platforma ustala ją na podstawie tożsamości połączenia – potrzebne wartości weź z Core.getCompanyId() / Core.getInstanceId(). Szczegóły w Kontekst firmy i instancji.
Przykład – forma podstawowa:
const { Core } = require('@orbito/api-lib');
Core.registerMethod('config.get', async (params, ctx) => {
const config = await ConfigSchema.findOne({});
return config ?? {};
});
Przykład – forma opisowa:
const { Core } = require('@orbito/api-lib');
Core.registerMethod('search', {
params: {
query: { type: 'string', min: 1 },
page: { type: 'number', integer: true, optional: true, default: 1 },
},
returns: {
items: { type: 'array' },
total: { type: 'number' },
},
handler: async (params, ctx) => {
const results = await ProductsSchema.find({
name: new RegExp(params.query, 'i'),
});
return { items: results, total: results.length };
},
});
Konwencja nazewnictwa
Dla metod z wieloma akcjami zaleca się notację z kropką: encja.akcja, np. order.search, order.create, config.get, config.save.
Core.registerHook
Rejestruje moduł jako implementację danego hooka. Gdy inny moduł wywoła execHook z tą nazwą, Orbito wywoła wszystkie zarejestrowane handlery.
Core.registerHook(hookName, handler)
Core.registerHook('core.shipping.getCarrier', async (order) => {
const config = await ShippingConfig.findOne({});
if (!config?.enabled) return null;
return {
carrierId: 'dpd',
label: 'DPD',
price: config.flatRate
};
});
Handler dostaje wyłącznie argumenty wywołującego. Tożsamość instancji, która odpaliła hook, trafia do handlera jako this.caller – żeby z niej skorzystać, napisz handler jako zwykłą function:
Core.registerHook('event:order:created', async function (order) {
// this.caller = { instanceId, moduleCode, instanceName } albo null (odpaliła platforma)
await saveOrder(order, { sourceInstanceId: this.caller?.instanceId });
});
Szczegółowa dokumentacja systemu hooków znajduje się w sekcji Komunikacja → Hooki.
Core.callModule
Wywołuje metodę zarejestrowaną w innym module. Wywołanie jest synchroniczne z punktu widzenia kodu (zwraca Promise), ale faktycznie przechodzi przez serwer Orbito.
await Core.callModule(moduleId, methodName, params)
| Parametr | Typ | Opis |
|---|---|---|
moduleId | string | Identyfikator modułu docelowego, np. 'core/orders' |
methodName | string | Nazwa metody do wywołania |
params | object | Argumenty przekazywane do metody |
Wywołanie trafia wyłącznie do modułu tej samej firmy – platforma ustala kontekst na podstawie tożsamości połączenia, więc companyId nie jest przekazywane.
Przykład:
const { Core } = require('@orbito/api-lib');
Core.registerMethod('getOrderStatus', async (params, ctx) => {
// Wywołanie metody w module core/orders
const result = await Core.callModule(
'core/orders',
'status.search',
{ orderId: params.orderId }
);
return result;
});
Obsługa błędów
Core.callModule rzuci wyjątek, jeśli moduł docelowy nie jest zainstalowany, metoda nie istnieje lub handler zwrócił błąd. Zawsze opakuj wywołanie w try/catch.
Core.callInstanceMethod
Wywołuje metodę konkretnej instalacji modułu – wariant callModule dla modułów, które firma może zainstalować wielokrotnie.
await Core.callInstanceMethod(targetInstanceId, methodName, params)
| Parametr | Typ | Opis |
|---|---|---|
targetInstanceId | string | Identyfikator instancji modułu docelowego |
methodName | string | Nazwa metody do wywołania |
params | object | Argumenty przekazywane do metody |
Gdy firma ma więcej niż jedną aktywną instalację modułu docelowego, Core.callModule odrzuca wywołanie błędem z err.code === 'AMBIGUOUS_MODULE_TARGET' – wtedy wskaż instancję jawnie:
const { Core } = require('@orbito/api-lib');
try {
await Core.callModule('core/prestashop', 'syncOrders', {});
} catch (err) {
if (err.code !== 'AMBIGUOUS_MODULE_TARGET') throw err;
await Core.callInstanceMethod(shopInstanceId, 'syncOrders', {});
}
Platforma weryfikuje, że wskazana instancja należy do tej samej firmy. Pełny opis wraz z przykładami: Komunikacja → Core.callModule.
Core.getUser
Pobiera podstawowe dane użytkownika firmy na podstawie jego identyfikatora. Handlery metod dostają w kontekście wyłącznie ctx.userId – ta metoda pozwala zamienić je na dane do wyświetlenia (np. „Utworzył: Jan Kowalski”).
const user = await Core.getUser(userId)
| Parametr | Typ | Opis |
|---|---|---|
userId | string | Identyfikator użytkownika Orbito, np. ctx.userId |
Zwraca obiekt z danymi użytkownika albo null:
{
id: '64a...', // identyfikator użytkownika
firstname: 'Jan',
lastname: 'Kowalski',
email: 'jan@firma.pl',
isDisabled: false, // czy konto jest zablokowane
isOwner: false, // czy użytkownik jest właścicielem firmy
profile: { // profil użytkownika W TEJ firmie, `null` gdy nie przypisano
id: '64c...',
name: 'sprzedawca',
isAdmin: false
}
}
Platforma nigdy nie zwraca danych wrażliwych – hasła, uprawnień, przestrzeni plików ani listy pozostałych firm użytkownika.
Przykład:
const { Core } = require('@orbito/api-lib');
Core.registerMethod('describeOrder', async (params, ctx) => {
const author = await Core.getUser(ctx.userId);
return {
...params.order,
authorName: author ? `${author.firstname} ${author.lastname}` : null
};
});
Zakres i brak rozróżnienia przyczyny
Wyszukiwanie jest zawężone przez platformę do firmy obsługiwanej przez ten kontener – użytkownika z innej firmy nie da się odczytać. Gdy użytkownik nie istnieje, został usunięty albo nie należy do tej firmy, metoda zwraca tak samo null, bez wskazania przyczyny. Dzięki temu moduł nie może wyliczać użytkowników Orbito.
Core.getCompany
Pobiera profil firmy obsługiwanej przez ten kontener: dane prawne i kontaktowe oraz strefę czasową (od SDK 4.3.0).
const company = await Core.getCompany()
Metoda nie przyjmuje parametrów – firma pochodzi z tożsamości połączenia, więc moduł nie może odczytać innej firmy. Zwraca obiekt:
| Pole | Typ | Opis |
|---|---|---|
id | string | Identyfikator firmy |
name | string | Nazwa firmy |
timezone | string | Strefa czasowa firmy (nazwa IANA), zawsze wypełniona, domyślnie Europe/Warsaw |
country | string | Kraj |
address | string | Adres |
city | string | Miejscowość |
postCode | string | Kod pocztowy |
taxNo | string | NIP |
legalForm | string | null | Forma prawna |
regon | string | null | REGON |
krs | string | null | KRS |
website | string | null | Strona internetowa |
contactPhone | string | null | Telefon kontaktowy |
contactEmail | string | null | E-mail kontaktowy |
Pola opcjonalne mają wartość null, gdy firma ich nie uzupełniła.
Przykład:
const { Core } = require('@orbito/api-lib');
Core.registerMethod('company.header', async () => {
const company = await Core.getCompany();
return {
title: company.name,
taxNo: company.taxNo,
phone: company.contactPhone ?? '-',
timezone: company.timezone // np. 'Europe/Warsaw'
};
});
Brak cache i powiadomień
SDK niczego nie cache'uje, a rdzeń nie powiadamia modułu o zmianie ustawień firmy – każde wywołanie pyta rdzeń, więc odpowiedź odzwierciedla bieżące ustawienia. Pobieraj dane wtedy, kiedy ich potrzebujesz (np. na początku handlera), zamiast trzymać kopię w zmiennej modułu.
Metoda odrzuca Promise przy błędzie. W odróżnieniu od Core.getUser nie zwraca null: moduł zawsze należy do istniejącej firmy, więc jej brak jest awarią. Do operacji na datach w strefie firmy użyj Time.
Core.fetch
Jedyna dozwolona metoda wykonywania wychodzących zapytań HTTP. Żądanie przechodzi przez serwer Orbito, który weryfikuje, czy domena docelowa jest na liście zatwierdzonych domen firmy.
const response = await Core.fetch(url, options)
Interfejs jest zgodny z natywnym fetch (Web Fetch API):
| Parametr | Typ | Opis |
|---|---|---|
url | string | Pełny URL docelowego zasobu |
options | object | Opcje zgodne z fetch: method, headers, body (string, Buffer lub Uint8Array), timeout |
Zwracany obiekt nie jest natywnym Response:
| Pole | Typ | Opis |
|---|---|---|
status | number | Kod statusu HTTP (brak pola ok – sprawdzaj status) |
headers | object | Nagłówki odpowiedzi jako zwykły obiekt, klucze małymi literami |
data | Buffer | Surowa treść odpowiedzi |
text() | () => string | Treść jako tekst – synchronicznie, bez await |
json() | () => any | Treść sparsowana jako JSON – synchronicznie, bez await |
Przykłady:
const { Core } = require('@orbito/api-lib');
// GET
const res = await Core.fetch('https://api.example.com/products');
const data = res.json();
// POST z JSON
const res = await Core.fetch('https://api.example.com/orders', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({ orderId: '123' })
});
if (res.status < 200 || res.status >= 300) {
throw new Error(`HTTP ${res.status}: ${res.text()}`);
}
const result = res.json();
// PUT z binarną treścią (np. PDF) – od SDK 3.11.0
const pdf = require('fs').readFileSync('faktura.pdf');
const upload = await Core.fetch('https://api.example.com/documents/123', {
method: 'PUT',
headers: { 'Content-Type': 'application/pdf' },
body: pdf
});
Binarne body
body typu Buffer lub Uint8Array jest przesyłane do serwera Orbito bez zmian, bajt w bajt (od SDK 3.11.0). Starsze wersje SDK przesyłały je jako JSON, przez co docelowy serwer dostawał tekst {"type":"Buffer","data":[...]} zamiast pliku.
Timeout
Nie można używać natywnego AbortSignal.timeout(time) – instancja AbortSignal nie jest serializowalna i nie może zostać przekazana przez serwer Orbito. Aby ustawić timeout, przekaż klucz timeout (w milisekundach) bezpośrednio w opcjach:
const res = await Core.fetch('https://api.example.com/data', {
timeout: 1000
});
Bezpośrednie zapytania HTTP są zablokowane
Kontener modułu nie ma dostępu do sieci. Każde bezpośrednie połączenie (axios, node-fetch, https.get itp.) zakończy się błędem sieciowym. Używaj wyłącznie Core.fetch.
