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
  • Pierwsze kroki

    • Pierwsze kroki
    • Struktura modułu
    • Zależności npm
    • Kontekst firmy i instancji

Kontekst firmy i instancji

Orbito to platforma wielofirmowa (multi-tenant) – na jednej instancji może działać wiele niezależnych firm. Twój moduł nie musi jednak zarządzać tym kontekstem samodzielnie: platforma izoluje firmy na poziomie infrastruktury.

Jeden kontener = jedna instancja modułu = jedna firma

Każda instalacja modułu działa jako osobny kontener, który obsługuje wyłącznie tę jedną instalację jednej firmy. Kontener uwierzytelnia się tokenem przekazanym przy starcie, a Orbito na podstawie tego tokenu ustala tożsamość połączenia.

Firma może zainstalować ten sam moduł wiele razy – np. trzy sklepy Prestashop albo dwa konta kurierskie. Każda taka instalacja to osobna instancja (instanceId) z własnym kontenerem, własną konfiguracją i własnymi danymi. Instancje tego samego modułu nie widzą nawzajem swoich kolekcji ani ustawień.

Moduł a instancja

  • moduł (moduleCode, np. core/prestashop) – co zostało zainstalowane,
  • instancja (instanceId) – konkretna instalacja modułu u konkretnej firmy.

Adresowanie danych, blokad i konfiguracji odbywa się po instanceId.

Tożsamość modułu

Modułu nie interesuje, skąd bierze się jego tożsamość – odczytuje ją z platformy:

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

Core.getCompanyId();   // firma obsługiwana przez ten kontener
Core.getInstanceId();  // identyfikator TEJ instalacji modułu
Core.getModuleInfo();  // { instanceId, companyId, code, version }

Obie wartości są stałe przez cały cykl życia procesu i pochodzą wyłącznie z tokenu połączenia. Moduł nigdy ich nie wysyła i nie może ich podmienić.

Dane firmy

Core.getCompanyId() zwraca tylko identyfikator. Pełne dane firmy (nazwa, NIP, adres, strefa czasowa) moduł pobiera przez Core.getCompany() – patrz Core.getCompany.

Handlery metod

Handler zarejestrowanej metody otrzymuje wyłącznie params i ctx:

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

Core.registerMethod('search', async (params, ctx) => {
  Log.info('Wywołano search', { params });

  // Operujesz automatycznie na danych swojej firmy
  const results = await MySchema.find(params);

  return results;
});

Parametry handlera

ParametrTypOpis
paramsobjectArgumenty przekazane przez wywołującego
ctxobjectKontekst żądania – dane sesji, uprawnienia, ctx.caller

Hooki

Handlery hooków również nie otrzymują companyId – dostają wyłącznie argumenty przekazane przez wywołującego:

Core.registerHook('core.shipping.getCarrier', async (order) => {
  const config = await ShippingConfig.findOne({});
  return config?.carrier ?? null;
});

Kto mnie wywołał – caller

Przy ruchu moduł → moduł (wywołania metod i hooki) platforma dokłada tożsamość wywołującego:

{
  instanceId,    // identyfikator instancji, która wywołała
  moduleCode,    // kod modułu, np. 'core/prestashop'
  instanceName   // nazwa nadana przy instalacji (np. 'Sklep PL'), może być null
}

Jest ona budowana przez platformę z tożsamości połączenia – wywołujący nie może jej podrobić. Gdy wywołanie pochodzi od samej platformy (akcja użytkownika, automatyzacja), caller jest null.

W handlerze metody dostajesz ją w ctx.caller, a w handlerze hooka jako this.caller – hook nie dostaje kontekstu jako argumentu, bo liczba argumentów hooka należy do wywołującego:

// nie potrzebuję kontekstu – funkcja strzałkowa
Core.registerHook('event:order:created', async (order) => {
  await saveOrder(order);
});

// potrzebuję kontekstu – zwykła function
Core.registerHook('event:order:created', async function (order) {
  await saveOrder(order, { sourceInstanceId: this.caller?.instanceId });
});

Dzięki temu moduł magazynowy odbierający zdarzenia z trzech sklepów wie, z którego sklepu przyszło zamówienie, bez zgadywania po treści danych.

bind() wygrywa z kontekstem

Jeśli zarejestrujesz handler jako obj.handler.bind(obj) albo jako metodę-pole ze strzałką, this.caller będzie undefined – wiązanie bind ma pierwszeństwo. Potrzebujesz kontekstu → rejestruj zwykłą function.

Izolacja danych

Orbito automatycznie nadaje kolekcjom namespace per instancja modułu – moduł posługuje się surową, logiczną nazwą kolekcji (np. orders), a platforma tłumaczy ją na fizyczną kolekcję danej instalacji. Dwie instancje tego samego modułu w jednej firmie mają rozłączne dane.

Dlatego nie dodawaj pola companyId do schematów ani do warunków zapytań:

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

const OrdersSchema = new DB.Schema('orders', {
  orderNumber: { type: 'string' },
  // ...
});

// ✅ Dobrze – zwróci wyłącznie zamówienia Twojej firmy
const orders = await OrdersSchema.find({});

// ❌ Źle – companyId nie jest już polem dokumentu, filtr nic nie znajdzie
const orders = await OrdersSchema.find({ companyId });

Migracja ze starszej wersji SDK

Jeśli Twój moduł powstał przed wprowadzeniem pełnej izolacji, usuń z niego:

  • argumenty companyId / instanceId z handlerów metod, hooków i stron,
  • companyId z wywołań Core.callModule, Core.execHook i Log.*,
  • pole companyId ze schematów, filtrów zapytań i indeksów,
  • ręczne prefiksowanie nazw kolekcji i identyfikatorów blokad.

Dodatkowo od SDK 3.0.0 (multi-instancja):

  • handlery hooków dostają wyłącznie argumenty wywołującego – jeśli Twój handler przyjmował kontekst jako pierwszy lub ostatni argument, przenieś odczyt na this.caller (i zamień funkcję strzałkową na function),
  • Core.callModule może rzucić błąd AMBIGUOUS_MODULE_TARGET, gdy firma ma kilka instalacji modułu docelowego – wtedy adresuj po instanceId przez Core.callInstanceMethod,
  • w automatyzacjach użytkownik wybiera instancję parametrem __instanceId wstrzykiwanym przez platformę – nazwa jest zarezerwowana, a Twoje akcje i triggery jej nie widzą (patrz Automation).

Indeksy w MongoDB

Ponieważ każda instancja ma własną kolekcję, indeksuj wyłącznie pola, po których faktycznie wyszukujesz – bez companyId:

DB.createIndex('orders', { orderNumber: 1 }, { unique: true });
Ostatnio zaktualizowano:: 6.10.2026, 12:34
Contributors: Wiktor Koźmiński, Claude Fable 5.1
Prev
Zależności npm