Files
Moduł Files to bucket plików tej instalacji modułu (od SDK 3.6.0). Rozwiązuje potrzebę trzymania obok danych w bazie także bajtów — logo, instrukcji PDF, wygenerowanej miniatury — bez własnego magazynu plików i bez wystawiania ich publicznie.
const { Files } = require('@orbito/api-lib');
Bucket należy do instancji, nie do kodu modułu
Tak samo jak kolekcje {instanceId}_* w bazie — trzy instalacje tego samego modułu mają trzy niezależne buckety. Tożsamość instancji rdzeń bierze z połączenia, więc żadna metoda Files nie przyjmuje instanceId: moduł nie ma jak sięgnąć do cudzego bucketu. Odinstalowanie instalacji kasuje jej bucket razem z resztą danych; disable/enable i aktualizacja wersji go nie ruszają.
Zapis i odczyt
| Metoda | Opis |
|---|---|
Files.upload(source, options?) | Wgrywa plik pod nazwą options.name (domyślnie nazwa pliku ze ścieżki). source to ścieżka na dysku modułu albo Buffer — Buffer wymaga podania name |
Files.get(name) | Zwraca { buffer, name, sha256, size, mime } albo null, gdy instancja nie ma pliku o tej nazwie |
Files.list(prefix?) | Lista plików instancji, opcjonalnie tylko tych, których nazwa zaczyna się od prefix |
Files.exists(name) | Czy plik istnieje — bez pobierania treści |
Files.remove(name) | Usuwa plik; false, gdy nie było czego kasować |
const { Files } = require('@orbito/api-lib');
await Files.upload('./assets/logo.png'); // name = "logo.png"
await Files.upload('./assets/manual.pdf', { name: 'docs/manual.pdf' });
await Files.upload(thumbBuffer, { name: `miniatures/${productId}`, mime: 'image/jpeg' });
await Files.list('miniatures/'); // [{ name, sha256, size, mime, createdAt, updatedAt }]
await Files.get('logo.png'); // { buffer, name, sha256, size, mime } albo null
await Files.exists('logo.png'); // bool, bez pobierania treści
await Files.remove(`miniatures/${productId}`); // bool
Nazwa jest kluczem
Wgranie pliku pod nazwą, która już istnieje w buckecie, podmienia jej treść — to nie jest dodanie kolejnego pliku. Ukośniki w nazwie (miniatures/65ab12ff) to tylko konwencja porządkująca — bucket nie ma katalogów, a Files.list(prefix) filtruje po przedrostku nazwy.
Dozwolone znaki w nazwie
Nazwa pliku trafia wprost do adresu HTTP, pod którym plik jest serwowany, dlatego podlega twardemu ograniczeniu: wyłącznie znaki [a-zA-Z0-9._/-], bez .., bez wiodącego ukośnika, maksymalnie 255 znaków. Nazwa z polskimi znakami, spacją albo innym znakiem specjalnym zostanie odrzucona — SDK sprawdza to lokalnie i zgłasza błąd z nazwą pliku od razu przy wywołaniu, zanim cokolwiek pójdzie do rdzenia (który i tak waliduje niezależnie).
Deduplikacja bajtów
Zawartość pliku jest przechowywana przez rdzeń raz, pod sumą kontrolną (sha256) — niezależnie od tego, ile instalacji i ile firm trzyma pod swoją nazwą dokładnie te same bajty. Dzięki temu:
- to samo logo modułu zainstalowanego w dziesięciu firmach zajmuje miejsce w bazie jeden raz,
Files.uploadwywołane przy każdym starcie modułu (patrz niżej) nie przesyła treści ponownie — SDK liczy sha256 lokalnie i najpierw próbuje podpiąć znaną już zawartość pod nazwę; transfer całych bajtów następuje tylko wtedy, gdy rdzeń jeszcze ich nie zna.
Plik znika z magazynu dopiero, gdy straci ostatnią referencję (np. Files.remove na ostatniej instalacji, która go używała, albo odinstalowanie tej instalacji).
Dwa typowe zastosowania
Plik statyczny wgrywany przy starcie modułu — logo, ikona, instrukcja. Wgrywaj go bezwarunkowo przy każdym uruchomieniu; dedup i tak sprawi, że transfer treści nastąpi tylko raz:
Core.onEnabled(async () => {
await Files.upload('./assets/how-to-connect.jpg'); // za każdym startem, transfer tylko raz
});
Plik dynamiczny zapisywany w chwili powstania — miniatura produktu, wygenerowany PDF:
await Files.upload(thumbnailBuffer, { name: `miniatures/${productId}`, mime: 'image/jpeg' });
Pokazanie pliku w interfejsie
Plik z bucketu pokazuje widok OVE typu image — wskazuje się go nazwą oraz kodem modułu albo instanceId, bez budowania adresu ręcznie (zobacz dokumentację widoków OVE):
type: image
src:
module: core/orders
name: how-to-connect.jpg
Brak publicznych adresów i limitów rozmiaru
Pliki nie są publiczne
Każde pobranie pliku przechodzi przez autoryzację firmy — nie ma adresu, pod którym plik byłby dostępny bez zalogowania. Jeśli potrzebujesz linku do wysłania poza Orbito (np. w mailu), użyj Files.get(name) i dołącz treść jako załącznik zamiast adresu.
W tej wersji nie ma limitów rozmiaru pliku ani dzielenia transferu na części — cały plik idzie jedną wiadomością RPC.
