@czlonkowski/n8n-nodes-librus 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/LICENSE +21 -0
- package/NOTICE.md +7 -0
- package/README.md +152 -0
- package/SECURITY.md +15 -0
- package/dist/credentials/LibrusSessionApi.credentials.d.ts +8 -0
- package/dist/credentials/LibrusSessionApi.credentials.js +32 -0
- package/dist/credentials/LibrusSessionApi.credentials.js.map +1 -0
- package/dist/nodes/Librus/Librus.node.d.ts +10 -0
- package/dist/nodes/Librus/Librus.node.js +225 -0
- package/dist/nodes/Librus/Librus.node.js.map +1 -0
- package/dist/nodes/Librus/LibrusClient.d.ts +67 -0
- package/dist/nodes/Librus/LibrusClient.js +393 -0
- package/dist/nodes/Librus/LibrusClient.js.map +1 -0
- package/dist/nodes/Librus/LibrusTrigger.node.d.ts +10 -0
- package/dist/nodes/Librus/LibrusTrigger.node.js +90 -0
- package/dist/nodes/Librus/LibrusTrigger.node.js.map +1 -0
- package/dist/nodes/Librus/librus.png +0 -0
- package/dist/nodes/Librus/pollState.d.ts +4 -0
- package/dist/nodes/Librus/pollState.js +46 -0
- package/dist/nodes/Librus/pollState.js.map +1 -0
- package/dist/nodes/Librus/transport.d.ts +4 -0
- package/dist/nodes/Librus/transport.js +33 -0
- package/dist/nodes/Librus/transport.js.map +1 -0
- package/docs/architecture.md +53 -0
- package/docs/live-verification.md +23 -0
- package/docs/logo.md +11 -0
- package/docs/verification.md +41 -0
- package/package.json +76 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 — Unreleased
|
|
4
|
+
|
|
5
|
+
- Scaffold an MIT-licensed, unofficial self-hosted n8n community node.
|
|
6
|
+
- Add browser-session credentials and a credential connection test.
|
|
7
|
+
- Add Message → Get Many with bounded pagination and optional decoded content.
|
|
8
|
+
- Validate redirects, isolate cookies, sanitize errors and bound session recovery.
|
|
9
|
+
- Add synthetic transport, pagination and n8n boundary tests.
|
|
10
|
+
- Document unverified live behaviours and the notification workflow roadmap.
|
|
11
|
+
- Add an original book-and-message logo with a coral unread indicator.
|
|
12
|
+
- Keep the development profile outside the repository to prevent recursive symlink scans.
|
|
13
|
+
- Accept the successful Synergia OAuth callback and include redacted authentication-stage diagnostics in verification errors.
|
|
14
|
+
- Upgrade legacy HTTP redirects to HTTPS for exact trusted Librus hosts before sending any request.
|
|
15
|
+
- Add explicit Preview / Full Message content selection and identify the selected source in output.
|
|
16
|
+
- Fetch full message bodies after list selection, with a 50-message cap and strict detail validation.
|
|
17
|
+
- Add All / Unread / Read filtering before result limits and full-content requests.
|
|
18
|
+
- Add Get Content by message ID with bounded authentication recovery.
|
|
19
|
+
- Add Librus Trigger with silent initial baseline, manual sample, account-scoped bounded ID history and preview-only polling.
|
|
20
|
+
- Preserve unread selections during full-body session recovery to avoid dropping messages whose detail reads changed their status.
|
|
21
|
+
- Document polling, cursor persistence, downstream retry semantics and unsupported mark-unread operations in Polish.
|
|
22
|
+
- Use the public npm scope @czlonkowski/n8n-nodes-librus to avoid the previous unrelated unscoped package.
|
|
23
|
+
- Add a manual release script with a dry run, checks, archive inspection and authenticated public publishing.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Romuald Członkowski
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/NOTICE.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Notices
|
|
2
|
+
|
|
3
|
+
This is an independent community integration, not an official LIBRUS product. LIBRUS and Synergia names belong to their respective owners. The book-and-message icon was generated for this project using OpenAI image generation. It is an independent community symbol and is not the LIBRUS logo.
|
|
4
|
+
|
|
5
|
+
Protocol research consulted FlakM/librus-rs (MIT) and Mati365/librus-api (MIT); exact revisions are linked in docs/architecture.md. Neither is included as a runtime dependency. Authentication and message handling were implemented independently using those observations. Public JavaScript assets served by the Librus messages website were inspected for protocol and UI capabilities; no frontend code was copied.
|
|
6
|
+
|
|
7
|
+
The scaffold was generated by the official @n8n/create-node tool. Runtime cookie handling uses tough-cookie (BSD-3-Clause); its package includes its license. n8n-workflow is supplied by the n8n host.
|
package/README.md
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
<img src="nodes/Librus/librus.png" alt="Logo integracji Librus: otwarta książka, koperta i kropka oznaczająca nową wiadomość" width="112" height="112">
|
|
2
|
+
|
|
3
|
+
# @czlonkowski/n8n-nodes-librus
|
|
4
|
+
|
|
5
|
+
Nieoficjalna paczka węzłów społecznościowych n8n do odczytywania wiadomości z dziennika Librus Synergia. Otwarty kod źródłowy, licencja MIT.
|
|
6
|
+
|
|
7
|
+
**Projekt jest na etapie eksperymentalnym.** Na rzeczywistym koncie sprawdzono logowanie, pobranie danych jednej wiadomości oraz jej treści z modułu szczegółów. Do zweryfikowania pozostają: zachowanie statusu nieprzeczytanych wiadomości, kompletność treści w różnych typach wiadomości, pobieranie kolejnych stron skrzynki oraz działanie przy cyklicznym uruchamianiu.
|
|
8
|
+
|
|
9
|
+
## Dostępne funkcje
|
|
10
|
+
|
|
11
|
+
Operacja **Librus → Message → Get Many** loguje się do Librusa, otwiera sesję modułu wiadomości i zwraca każdą wiadomość jako osobny element danych n8n.
|
|
12
|
+
|
|
13
|
+
Można pobrać określoną liczbę wiadomości albo całą skrzynkę, strona po stronie. **Read Status** pozwala wybrać wszystkie (**All**), tylko nieprzeczytane (**Unread**) lub przeczytane (**Read**). Filtr działa na dacie odczytania z listy: brak daty albo pusty tekst oznacza wiadomość nieprzeczytaną. **Limit dotyczy pasujących wiadomości**. Węzeł przegląda metadane kolejnych stron lokalnie, więc znalezienie starszych nieprzeczytanych może wymagać zwiększenia Maximum Pages. Pełną treść pobiera dopiero dla wiadomości wybranych przez filtr i limit. Wynik zawiera identyfikator wiadomości zapisany jako tekst, dane nadawcy, temat, daty w oryginalnym formacie, datę odczytania, informację o załącznikach i tagi. Opcja **Include Content** dołącza treść, a **Content Source** określa jej źródło:
|
|
14
|
+
|
|
15
|
+
| Content Source | Zawartość pola `content` |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| **Preview** — domyślnie | Skrót z listy wiadomości. Może urwać się w środku zdania. |
|
|
18
|
+
| **Full Message** | Treść pobrana osobno ze szczegółów każdej wiadomości. |
|
|
19
|
+
|
|
20
|
+
W obu trybach treść jest dekodowana z base64 do UTF-8, z zachowaniem HTML. Pole `contentSource` w wyniku ma wartość `preview` albo `full`. Przy wyłączonym **Include Content** oba pola są pomijane.
|
|
21
|
+
|
|
22
|
+
**Aby otrzymać pełną treść, włącz Include Content i wybierz Content Source → Full Message.** Samo włączenie Include Content zachowuje dotychczasowe działanie — podgląd z listy. W próbie na rzeczywistym koncie podgląd miał 95 znaków, a odpowiedź ze szczegółów tej samej wiadomości zawierała 463 znaki i zaczynała się od całego podglądu.
|
|
23
|
+
|
|
24
|
+
Pobranie szczegółów **może oznaczyć wiadomość jako przeczytaną w Librusie**. Nie sprawdzono jeszcze tego efektu na nieprzeczytanej wiadomości; próbę wykonano na wiadomości już przeczytanej. Wybierz Full Message świadomie, szczególnie w przepływach uruchamianych automatycznie.
|
|
25
|
+
|
|
26
|
+
**Librus → Message → Get Content** pobiera pełną treść pojedynczej wiadomości po **Message ID** i zwraca `messageId`, `content` oraz `contentSource: "full"`. Można przekazać ID z triggera wyrażeniem `{{ $json.messageId }}`. Metadane pozostają dostępne w danych poprzedniego węzła. Także ta operacja może oznaczyć wiadomość jako przeczytaną.
|
|
27
|
+
|
|
28
|
+
Paczka nie udostępnia wysyłania, usuwania, pobierania załączników ani osobnych operacji **Mark as Read / Mark as Unread**. W zbadanym interfejsie nowego modułu wiadomości Librusa nie znaleziono operacji przywracania statusu nieprzeczytanej; dlatego nie deklarujemy jej obsługi. Nadal trzeba sprawdzić, czy samo pobranie listy przez Librusa zmienia status odczytania.
|
|
29
|
+
|
|
30
|
+
Dla każdego elementu wejściowego powstaje nowa sesja oparta na ciasteczkach. Nie ma jeszcze trwałego przechowywania sesji ani obsługi tokena odświeżającego. Jeśli podczas pobierania wiadomości zostanie rozpoznane wygaśnięcie sesji, węzeł może zalogować się ponownie jeden raz. Błędne dane logowania, brak dostępu, ograniczenie liczby żądań i błędy serwera nie uruchamiają pętli logowania.
|
|
31
|
+
|
|
32
|
+
## Uruchomienie lokalne
|
|
33
|
+
|
|
34
|
+
Wymagane są **Node.js 24 LTS** i npm. Testowano na Node.js 24.20.0.
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
git clone https://github.com/czlonkowski/n8n-nodes-librus.git
|
|
38
|
+
cd n8n-nodes-librus
|
|
39
|
+
npm ci
|
|
40
|
+
npm run check
|
|
41
|
+
N8N_LISTEN_ADDRESS=127.0.0.1 N8N_PORT=5689 npm run dev
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Edytor n8n będzie dostępny pod adresem **http://localhost:5689**.
|
|
45
|
+
|
|
46
|
+
Przed uruchomieniem sprawdź `node --version`: potrzebna jest wersja 24 lub nowsza. Plik `.nvmrc` nie przełącza wersji Node.js automatycznie. Jeśli używasz nvm, wykonaj najpierw `nvm use`.
|
|
47
|
+
|
|
48
|
+
Projekt korzysta z oficjalnego narzędzia `@n8n/node-cli` do budowania paczki, sprawdzania kodu i uruchamiania środowiska deweloperskiego. Skrypt `dev` przechowuje osobny profil n8n w katalogu **`../.n8n-librus-dev`**, poza repozytorium. Nie przenoś profilu do środka projektu: narzędzie tworzy w nim dowiązanie do repozytorium, co prowadziłoby do zapętlenia skanowania katalogów i błędu `ENAMETOOLONG`.
|
|
49
|
+
|
|
50
|
+
Nie dodawaj do repozytorium profilu n8n ani danych konta. Testy automatyczne korzystają wyłącznie z fikcyjnych odpowiedzi HTTP — nie łączą się z Librusem i nie wymagają prawdziwych danych logowania.
|
|
51
|
+
|
|
52
|
+
Szczegóły techniczne opisano w dokumentach: [architektura](docs/architecture.md), [testy na rzeczywistym koncie](docs/live-verification.md), [wyniki weryfikacji](docs/verification.md) i [bezpieczeństwo](SECURITY.md). Te dokumenty techniczne są obecnie po angielsku.
|
|
53
|
+
|
|
54
|
+
## Instalacja we własnej instancji n8n
|
|
55
|
+
|
|
56
|
+
**Paczka nie została jeszcze opublikowana w npm.** Aby przygotować archiwum do instalacji, wykonaj w katalogu projektu:
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
npm ci
|
|
60
|
+
npm run check
|
|
61
|
+
npm pack
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Zainstaluj powstały plik `.tgz` w katalogu węzłów społecznościowych swojej **testowej instancji n8n**, a następnie uruchom ją ponownie. Przy standardowym profilu jest to katalog `~/.n8n/nodes`. Jeśli korzystasz z kontenera, skopiuj archiwum do kontenera i zadbaj o trwały wolumen z danymi użytkownika n8n. Pomocna jest [instrukcja ręcznej instalacji n8n](https://docs.n8n.io/integrations/community-nodes/installation-and-management/manual-installation/).
|
|
65
|
+
|
|
66
|
+
Do czasu publikacji paczki nie używaj polecenia `npm install @czlonkowski/n8n-nodes-librus`.
|
|
67
|
+
|
|
68
|
+
Projekt jest przeznaczony do **samodzielnie hostowanego n8n jako niezweryfikowany węzeł społecznościowy**. Biblioteka `tough-cookie` zapewnia obsługę ciasteczek z uwzględnieniem ich domen i ścieżek. Ta zależność wyklucza obecną wersję z weryfikacji n8n Cloud według wymogu braku zależności uruchomieniowych, dlatego `n8n.strict` ma wartość `false`.
|
|
69
|
+
|
|
70
|
+
Zgodnie z konwencją paczek n8n pole `peerDependencies` zawiera `n8n-workflow: "*"`. Nie oznacza to zgodności ze wszystkimi wersjami n8n. Typy używane podczas budowania pochodzą z `n8n-workflow` 2.38.1; próbę na rzeczywistym koncie przeprowadzono w n8n 2.37.10.
|
|
71
|
+
|
|
72
|
+
## Konfiguracja i pierwszy test
|
|
73
|
+
|
|
74
|
+
1. W interfejsie n8n utwórz dane uwierzytelniające typu **Librus Session API**. Podaj login i hasło akceptowane przez formularz Synergii — login może różnić się od adresu e-mail konta LIBRUS. n8n szyfruje te dane swoim kluczem instancji.
|
|
75
|
+
2. W dzienniku zanotuj, które z ostatnich wiadomości są nieprzeczytane, bez otwierania ich. Zrób to przed testem połączenia: test danych logowania również pobiera jeden wpis z listy wiadomości, choć nie zwraca jego zawartości.
|
|
76
|
+
3. Utwórz przepływ **Manual Trigger → Librus**. Wybierz **Message → Get Many**, wyłącz **Return All**, ustaw **Limit: 10** i pozostaw **Include Content** wyłączone.
|
|
77
|
+
4. Uruchom węzeł i porównaj wyniki z dziennikiem. Odśwież listę w Librusie i sprawdź, czy status nieprzeczytanych wiadomości się nie zmienił.
|
|
78
|
+
5. Włącz **Include Content**, wybierz **Content Source → Full Message** i porównaj treść wiadomości wcześniej przeczytanej w dzienniku. Sprawdź także polskie znaki i formatowanie. Na pierwszą próbę ustaw **Limit: 1**.
|
|
79
|
+
|
|
80
|
+
Parametr **Maximum Pages** domyślnie wynosi 20, a jego maksymalna wartość to 50. Jedno żądanie pobiera do 50 wpisów. Po osiągnięciu limitu stron, żądań lub czasu węzeł zgłasza błąd zamiast zwracać niepełny wynik. Daty pozostają w formacie źródłowym, ponieważ interpretacja strefy czasowej nie została jeszcze zweryfikowana.
|
|
81
|
+
|
|
82
|
+
Tryb **Full Message** obsługuje do **50 wiadomości na wykonanie**. Szczegóły są pobierane kolejno, w tej samej sesji, dopiero po zakończeniu pobierania listy, zastosowaniu limitu i usunięciu duplikatów identyfikatorów. Jeśli wynik zawiera więcej niż 50 wiadomości, węzeł zgłosi `FULL_CONTENT_LIMIT` przed pobraniem szczegółów. Wyłącz wtedy Return All i ustaw Limit na 50 lub mniej.
|
|
83
|
+
|
|
84
|
+
Błąd pobrania szczegółów zatrzymuje wykonanie — węzeł nie zastępuje brakującej pełnej treści skrótem. Nie zwraca też częściowego wyniku, choć wcześniejsze żądania szczegółów mogły już wpłynąć na status odczytania w Librusie. Pole `readDate` pochodzi z listy pobranej przed odczytem szczegółów. Przy filtrze Unread i odnowieniu wygasłej sesji zachowywany jest już wybrany zestaw identyfikatorów, aby wcześniejszy odczyt szczegółów nie usunął ich z bieżącego wyniku.
|
|
85
|
+
|
|
86
|
+
Po włączeniu **Include Content** treść wiadomości trafia do zwykłych danych wykonania n8n. Jej przechowywanie zależy od ustawień zapisywania i usuwania historii wykonań. Podgląd dołączany przez trigger i treść z Get Content również trafiają do danych wykonania. Jeśli wyświetlasz zwrócony HTML w innej aplikacji, potraktuj go jako niezaufaną treść.
|
|
87
|
+
|
|
88
|
+
## Librus Trigger — nowa wiadomość
|
|
89
|
+
|
|
90
|
+
Osobny węzeł **Librus Trigger** cyklicznie sprawdza skrzynkę i uruchamia przepływ dla nowych identyfikatorów `messageId`. Jest to odpytywanie Librusa według harmonogramu; opóźnienie zależy od **Poll Times**.
|
|
91
|
+
|
|
92
|
+
1. Dodaj **Librus Trigger**, wybierz zapisane dane **Librus Session API** i zdarzenie **New Message**.
|
|
93
|
+
2. Ustaw **Poll Times** na **Every X → 5 → Minutes** lub rzadziej. n8n domyślnie ustawia minutę, więc zmień ten parametr. Bezpieczna częstotliwość dla Librusa nadal wymaga sprawdzenia.
|
|
94
|
+
3. Użyj ręcznego testu triggera: zwróci jedną bieżącą wiadomość jako próbkę, niezależnie od jej wieku i statusu. Pusta skrzynka nie zwróci próbki. Test nie zmienia historii wykrytych wiadomości.
|
|
95
|
+
4. Połącz kolejne kroki i zapisz przepływ. Przykład: **Librus Trigger → Librus (Get Content, Message ID: `{{ $json.messageId }}`) → wybrany kanał powiadomień**. Do powiadomienia z samym tematem i podglądem wystarczy bezpośrednie wyjście triggera.
|
|
96
|
+
5. Po opublikowaniu/aktywacji przepływu pierwsze automatyczne sprawdzenie zapamięta całą obecną skrzynkę i nie uruchomi dalszych kroków. Dopiero kolejne sprawdzenia zwrócą nowe wiadomości. Zwykłe zapisanie nieaktywnego workflow nie uruchamia harmonogramu.
|
|
97
|
+
|
|
98
|
+
Trigger sprawdza zarówno przeczytane, jak i nieprzeczytane wiadomości. Wiadomość odczytana w aplikacji przed kolejnym sprawdzeniem nadal zostanie wykryta. Zmiana statusu starej wiadomości nie jest nowym zdarzeniem. **Include Preview** domyślnie dołącza skróconą treść; trigger nie pobiera szczegółów wiadomości. Możesz wyłączyć podgląd i otrzymywać same metadane.
|
|
99
|
+
|
|
100
|
+
Stan triggera jest przechowywany przez n8n osobno dla węzła: wersja formatu, skrót identyfikujący konto i identyfikatory wykrytych wiadomości. Nie zawiera hasła, ciasteczek ani treści. Przy zachowaniu tego stanu restart nie odtwarza historii. Zmiana konta lub utworzenie nowego triggera ustala nowy stan początkowy. Utrata bazy n8n oznacza utratę tej historii.
|
|
101
|
+
|
|
102
|
+
Każde automatyczne sprawdzenie musi ukończyć przegląd całej skrzynki w granicach **Maximum Pages** (domyślnie 20, maksymalnie 50), 100 żądań i 120 sekund. Niepełny skan kończy się błędem i nie zmienia historii. Historia mieści do **10 000 identyfikatorów**; po przekroczeniu limitu pojawi się błąd. Utworzenie nowego triggera rozpocznie historię od aktualnej skrzynki bez odtwarzania starych zdarzeń. Wiadomość usunięta lub przeniesiona poza skrzynkę pomiędzy sprawdzeniami może pozostać niewykryta.
|
|
103
|
+
|
|
104
|
+
**Błąd dalszego kroku nie cofa historii triggera.** Jeżeli np. wysyłka powiadomienia się nie powiedzie, ponów nieudane wykonanie w n8n. Samo następne sprawdzenie nie wyśle tej wiadomości ponownie. Przy równoległych wykonaniach lub wielu instancjach możliwe są duplikaty. Gdy potrzebujesz gwarancji dostarczenia i deduplikacji także przy awariach, zapisuj zdarzenia w trwałej kolejce z kluczem konto + `messageId` i osobno potwierdzaj udaną wysyłkę.
|
|
105
|
+
|
|
106
|
+
Testy automatyczne obejmują stan początkowy, restart, zmianę statusu, błędy skanowania i równoległe sprawdzenia. Działanie harmonogramu na rzeczywistym koncie, skutki ponownego logowania i zachowanie statusu odczytania wymagają jeszcze próby. Paczka nie aktywuje workflow automatycznie.
|
|
107
|
+
|
|
108
|
+
## Zgłaszanie błędów i rozwój
|
|
109
|
+
|
|
110
|
+
Błędy i propozycje zmian zgłaszaj w [GitHub Issues](https://github.com/czlonkowski/n8n-nodes-librus/issues). Przed przesłaniem zmian uruchom `npm run check` oraz `npm pack --dry-run`. Do testów dodawaj wyłącznie fikcyjne dane. Opisz sposób odtworzenia problemu, usuwając dane osobowe; nie publikuj loginów, haseł, ciasteczek ani treści prawdziwych wiadomości.
|
|
111
|
+
|
|
112
|
+
## Ręczna publikacja w npm
|
|
113
|
+
|
|
114
|
+
Paczka używa nazwy **`@czlonkowski/n8n-nodes-librus`**. Niescopowana nazwa `n8n-nodes-librus` była wcześniej używana przez innego autora. Repozytorium GitHub zachowuje dotychczasową nazwę.
|
|
115
|
+
|
|
116
|
+
Przy Node.js 24 lub nowszym najpierw wykonaj próbę bez publikacji:
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
npm run release -- --dry-run
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Skrypt instaluje zależności zgodnie z lockfile, uruchamia lint, kompilację i testy, przygotowuje archiwum oraz sprawdza jego zawartość. Tryb próbny nie wymaga zalogowania do npm. Oba tryby wymagają połączenia z rejestrem npm.
|
|
123
|
+
|
|
124
|
+
Pierwsza publikacja przygotowanej wersji:
|
|
125
|
+
|
|
126
|
+
```sh
|
|
127
|
+
npm login --registry=https://registry.npmjs.org
|
|
128
|
+
npm whoami
|
|
129
|
+
npm run release
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Użyj konta **czlonkowski**. Przed właściwą publikacją wszystkie zmiany muszą być zapisane w commicie. npm może poprosić o potwierdzenie logowania/publikacji w przeglądarce lub kod 2FA — wykonaj ten krok bezpośrednio w npm. Nie zapisuj kodów ani tokenów w repozytorium.
|
|
133
|
+
|
|
134
|
+
Skrypt publikuje dokładnie sprawdzone archiwum jako paczkę publiczną. Wersje stabilne otrzymują tag `latest`, a wersje z sufiksem (np. `0.2.0-beta.1`) — `next`. Nie tworzy tagów Git ani GitHub Release i nie korzysta z GitHub Actions do publikacji. Jeżeli npm zgłosi błąd po wysłaniu paczki, sprawdź rejestr przed ponowieniem; opublikowanej wersji nie można nadpisać:
|
|
135
|
+
|
|
136
|
+
```sh
|
|
137
|
+
npm view @czlonkowski/n8n-nodes-librus version
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Dla kolejnego wydania zwiększ wersję, uzupełnij `CHANGELOG.md`, zapisz i wypchnij commit, a potem uruchom skrypt:
|
|
141
|
+
|
|
142
|
+
```sh
|
|
143
|
+
npm version patch --no-git-tag-version
|
|
144
|
+
# Uzupełnij CHANGELOG.md, następnie zapisz zmiany w Git.
|
|
145
|
+
npm run release
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Po publikacji w samodzielnie hostowanym n8n wejdź w **Settings → Community nodes → Install** i podaj **`@czlonkowski/n8n-nodes-librus`**. Paczka pozostaje niezweryfikowanym węzłem społecznościowym; publikacja w npm nie oznacza dostępności w n8n Cloud.
|
|
149
|
+
|
|
150
|
+
## Licencja i autorstwo
|
|
151
|
+
|
|
152
|
+
Kod udostępniono na [licencji MIT](LICENSE). Projekt nie jest powiązany z firmą LIBRUS ani przez nią zatwierdzony. Informacje o źródłach wykorzystanych do poznania sposobu działania integracji znajdują się w [NOTICE.md](NOTICE.md).
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Security
|
|
2
|
+
|
|
3
|
+
Do not submit real credentials, cookies, message contents, student names or account identifiers in public issues or test fixtures. Use synthetic examples. Until a public security-reporting channel is established, contact the maintainer privately through an existing trusted channel.
|
|
4
|
+
|
|
5
|
+
This package logs into Librus using the user's credentials stored in n8n. Protect the instance encryption key and backups. Metadata and optional body content are normal workflow output: configure execution retention accordingly.
|
|
6
|
+
|
|
7
|
+
The client validates redirect destinations and scopes cookies per URL; it never logs requests or raw response bodies. Errors are fixed, sanitized messages. Transport, response validation and node-boundary redaction have offline tests. This does not replace live compatibility checks.
|
|
8
|
+
|
|
9
|
+
The production dependency audit reported zero known vulnerabilities when bootstrapped on 2026-09-07. The official development-tool dependency tree reported 10 moderate advisories after updating the development n8n-workflow dependency to 2.38.1, including transitive LangChain-related packages; these are not shipped as this package's runtime dependencies. Recheck with `npm audit` and `npm audit --omit=dev` before release. No automatic force-upgrade was applied across the pinned n8n toolchain.
|
|
10
|
+
|
|
11
|
+
Full Message is an explicit opt-in because reading message details may mark messages as read in Librus. Its 50-message cap is checked before detail requests. A later error suppresses partial node output but cannot undo any unread-state changes caused by earlier detail requests.
|
|
12
|
+
|
|
13
|
+
Manual publication uses an inspected archive with explicit allowed paths. The release script rejects environment files, npm authentication configuration, n8n profiles, common private-key files and databases even if nested inside a permitted directory. The credential class shipped in the package defines empty, masked input fields; it does not contain a user's saved credentials.
|
|
14
|
+
|
|
15
|
+
On 2026-09-07, Gitleaks 8.30.1 scanned all 8 existing Git commits and the actual 29-file npm archive with full redaction enabled: no secrets were detected. The browser-session client was also reviewed for password destinations, per-URL cookie scoping and sanitized error output. Pattern scanning is supporting evidence, not a guarantee against every possible secret format. The private n8n profile and its credential values were not read for this audit.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ICredentialType, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare class LibrusSessionApi implements ICredentialType {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
documentationUrl: string;
|
|
6
|
+
icon: "file:../nodes/Librus/librus.png";
|
|
7
|
+
properties: INodeProperties[];
|
|
8
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LibrusSessionApi = void 0;
|
|
4
|
+
class LibrusSessionApi {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'librusSessionApi';
|
|
7
|
+
this.displayName = 'Librus Session API';
|
|
8
|
+
this.documentationUrl = 'https://portal.librus.pl/rodzina/synergia/loguj';
|
|
9
|
+
this.icon = 'file:../nodes/Librus/librus.png';
|
|
10
|
+
this.properties = [
|
|
11
|
+
{
|
|
12
|
+
displayName: 'Synergia Login',
|
|
13
|
+
name: 'username',
|
|
14
|
+
type: 'string',
|
|
15
|
+
typeOptions: { password: true },
|
|
16
|
+
default: '',
|
|
17
|
+
required: true,
|
|
18
|
+
description: 'The login accepted by the Synergia login form, which may differ from your LIBRUS account email',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
displayName: 'Password',
|
|
22
|
+
name: 'password',
|
|
23
|
+
type: 'string',
|
|
24
|
+
typeOptions: { password: true },
|
|
25
|
+
default: '',
|
|
26
|
+
required: true,
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.LibrusSessionApi = LibrusSessionApi;
|
|
32
|
+
//# sourceMappingURL=LibrusSessionApi.credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LibrusSessionApi.credentials.js","sourceRoot":"","sources":["../../credentials/LibrusSessionApi.credentials.ts"],"names":[],"mappings":";;;AAEA,MAAa,gBAAgB;IAA7B;QACC,SAAI,GAAG,kBAAkB,CAAC;QAC1B,gBAAW,GAAG,oBAAoB,CAAC;QACnC,qBAAgB,GAAG,iDAAiD,CAAC;QACrE,SAAI,GAAG,iCAA0C,CAAC;QAClD,eAAU,GAAsB;YAC/B;gBACC,WAAW,EAAE,gBAAgB;gBAC7B,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EACV,gGAAgG;aACjG;YACD;gBACC,WAAW,EAAE,UAAU;gBACvB,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;aACd;SACD,CAAC;IACH,CAAC;CAAA;AAzBD,4CAyBC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ICredentialTestFunctions, ICredentialsDecrypted, IExecuteFunctions, INodeCredentialTestResult, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
|
2
|
+
export declare class Librus implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
methods: {
|
|
5
|
+
credentialTest: {
|
|
6
|
+
librusConnectionTest(this: ICredentialTestFunctions, credential: ICredentialsDecrypted): Promise<INodeCredentialTestResult>;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Librus = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const LibrusClient_1 = require("./LibrusClient");
|
|
6
|
+
const transport_1 = require("./transport");
|
|
7
|
+
class Librus {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.description = {
|
|
10
|
+
displayName: 'Librus',
|
|
11
|
+
name: 'librus',
|
|
12
|
+
icon: 'file:librus.png',
|
|
13
|
+
group: ['input'],
|
|
14
|
+
version: 1,
|
|
15
|
+
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
|
16
|
+
description: 'Read messages from Librus Synergia',
|
|
17
|
+
defaults: { name: 'Librus' },
|
|
18
|
+
inputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
19
|
+
outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
20
|
+
credentials: [{ name: 'librusSessionApi', required: true, testedBy: 'librusConnectionTest' }],
|
|
21
|
+
properties: [
|
|
22
|
+
{
|
|
23
|
+
displayName: 'Experimental integration using unofficial Librus routes. Live account compatibility and unread-state behaviour still require verification.',
|
|
24
|
+
name: 'experimentalNotice',
|
|
25
|
+
type: 'notice',
|
|
26
|
+
default: '',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
displayName: 'Resource',
|
|
30
|
+
name: 'resource',
|
|
31
|
+
type: 'options',
|
|
32
|
+
noDataExpression: true,
|
|
33
|
+
options: [{ name: 'Message', value: 'message' }],
|
|
34
|
+
default: 'message',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
displayName: 'Operation',
|
|
38
|
+
name: 'operation',
|
|
39
|
+
type: 'options',
|
|
40
|
+
noDataExpression: true,
|
|
41
|
+
displayOptions: { show: { resource: ['message'] } },
|
|
42
|
+
options: [
|
|
43
|
+
{
|
|
44
|
+
name: 'Get Content',
|
|
45
|
+
value: 'getContent',
|
|
46
|
+
description: 'Get the full body of a message by ID; may mark it as read',
|
|
47
|
+
action: 'Get message content',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: 'Get Many',
|
|
51
|
+
value: 'getAll',
|
|
52
|
+
description: 'Get inbox messages',
|
|
53
|
+
action: 'Get many messages',
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
default: 'getAll',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
displayName: 'Message ID',
|
|
60
|
+
name: 'messageId',
|
|
61
|
+
type: 'string',
|
|
62
|
+
default: '',
|
|
63
|
+
required: true,
|
|
64
|
+
displayOptions: { show: { operation: ['getContent'] } },
|
|
65
|
+
description: 'Message identifier from Get Many or Librus Trigger',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
displayName: 'Fetching the full message may mark it as read in Librus.',
|
|
69
|
+
name: 'getContentNotice',
|
|
70
|
+
type: 'notice',
|
|
71
|
+
default: '',
|
|
72
|
+
displayOptions: { show: { operation: ['getContent'] } },
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
displayName: 'Read Status',
|
|
76
|
+
name: 'readStatus',
|
|
77
|
+
type: 'options',
|
|
78
|
+
default: 'all',
|
|
79
|
+
displayOptions: { show: { operation: ['getAll'] } },
|
|
80
|
+
options: [
|
|
81
|
+
{ name: 'All', value: 'all' },
|
|
82
|
+
{ name: 'Unread', value: 'unread' },
|
|
83
|
+
{ name: 'Read', value: 'read' },
|
|
84
|
+
],
|
|
85
|
+
description: 'Filter the inbox before applying Limit or fetching full content',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
displayName: 'Return All',
|
|
89
|
+
name: 'returnAll',
|
|
90
|
+
displayOptions: { show: { operation: ['getAll'] } },
|
|
91
|
+
type: 'boolean',
|
|
92
|
+
default: false,
|
|
93
|
+
description: 'Whether to return all results or only up to a given limit',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
displayName: 'Limit',
|
|
97
|
+
name: 'limit',
|
|
98
|
+
type: 'number',
|
|
99
|
+
default: 50,
|
|
100
|
+
typeOptions: { minValue: 1, maxValue: 1000 },
|
|
101
|
+
displayOptions: { show: { operation: ['getAll'], returnAll: [false] } },
|
|
102
|
+
description: 'Max number of results to return',
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
displayName: 'Maximum Pages',
|
|
106
|
+
name: 'maxPages',
|
|
107
|
+
displayOptions: { show: { operation: ['getAll'] } },
|
|
108
|
+
type: 'number',
|
|
109
|
+
default: 20,
|
|
110
|
+
typeOptions: { minValue: 1, maxValue: 50 },
|
|
111
|
+
description: 'Safety bound on pagination. An incomplete scan fails without emitting partial results.',
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
displayName: 'Include Content',
|
|
115
|
+
name: 'includeContent',
|
|
116
|
+
displayOptions: { show: { operation: ['getAll'] } },
|
|
117
|
+
type: 'boolean',
|
|
118
|
+
default: false,
|
|
119
|
+
description: 'Whether to include the message preview or fetch the full message body. Full messages may be marked as read by Librus.',
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
displayName: 'Content Source',
|
|
123
|
+
name: 'contentSource',
|
|
124
|
+
type: 'options',
|
|
125
|
+
noDataExpression: true,
|
|
126
|
+
displayOptions: { show: { operation: ['getAll'], includeContent: [true] } },
|
|
127
|
+
options: [
|
|
128
|
+
{
|
|
129
|
+
name: 'Preview',
|
|
130
|
+
value: 'preview',
|
|
131
|
+
description: 'Read the shortened content from the inbox listing',
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
name: 'Full Message',
|
|
135
|
+
value: 'full',
|
|
136
|
+
description: 'Fetch the full body for each message; this may mark it as read',
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
default: 'preview',
|
|
140
|
+
description: 'Where to retrieve message content. Full Message makes an additional request for each message.',
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
displayName: 'Fetching full messages may mark them as read in Librus. Up to 50 full messages can be fetched per execution.',
|
|
144
|
+
name: 'fullContentNotice',
|
|
145
|
+
type: 'notice',
|
|
146
|
+
default: '',
|
|
147
|
+
displayOptions: {
|
|
148
|
+
show: { operation: ['getAll'], includeContent: [true], contentSource: ['full'] },
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
};
|
|
153
|
+
this.methods = {
|
|
154
|
+
credentialTest: {
|
|
155
|
+
async librusConnectionTest(credential) {
|
|
156
|
+
try {
|
|
157
|
+
const data = credential.data;
|
|
158
|
+
if (typeof (data === null || data === void 0 ? void 0 : data.username) !== 'string' || typeof (data === null || data === void 0 ? void 0 : data.password) !== 'string')
|
|
159
|
+
throw new LibrusClient_1.LibrusError('INVALID_OPTIONS');
|
|
160
|
+
const client = new LibrusClient_1.LibrusClient((0, transport_1.createCredentialTestTransport)(this.helpers.request.bind(this.helpers)), { username: data.username, password: data.password });
|
|
161
|
+
await client.getMessages({
|
|
162
|
+
returnAll: false,
|
|
163
|
+
limit: 1,
|
|
164
|
+
maxPages: 1,
|
|
165
|
+
includeContent: false,
|
|
166
|
+
});
|
|
167
|
+
return {
|
|
168
|
+
status: 'OK',
|
|
169
|
+
message: 'Successfully authenticated and read the inbox listing.',
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
const safe = (0, LibrusClient_1.safeError)(error);
|
|
174
|
+
return { status: 'Error', message: `${safe.code}: ${safe.message}` };
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
async execute() {
|
|
181
|
+
const output = [];
|
|
182
|
+
for (let itemIndex = 0; itemIndex < this.getInputData().length; itemIndex++) {
|
|
183
|
+
try {
|
|
184
|
+
if (this.getNodeParameter('resource', itemIndex) !== 'message' ||
|
|
185
|
+
!['getAll', 'getContent'].includes(this.getNodeParameter('operation', itemIndex)))
|
|
186
|
+
throw new LibrusClient_1.LibrusError('INVALID_OPTIONS');
|
|
187
|
+
const credentials = await this.getCredentials('librusSessionApi', itemIndex);
|
|
188
|
+
if (typeof credentials.username !== 'string' || typeof credentials.password !== 'string')
|
|
189
|
+
throw new LibrusClient_1.LibrusError('INVALID_OPTIONS');
|
|
190
|
+
const client = new LibrusClient_1.LibrusClient((0, transport_1.createTransport)(this.helpers.httpRequest.bind(this.helpers)), { username: credentials.username, password: credentials.password });
|
|
191
|
+
if (this.getNodeParameter('operation', itemIndex) === 'getContent') {
|
|
192
|
+
const result = await client.getMessageContent(this.getNodeParameter('messageId', itemIndex));
|
|
193
|
+
output.push({ json: { ...result }, pairedItem: { item: itemIndex } });
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
const returnAll = this.getNodeParameter('returnAll', itemIndex);
|
|
197
|
+
const result = await client.getMessages({
|
|
198
|
+
returnAll,
|
|
199
|
+
readStatus: this.getNodeParameter('readStatus', itemIndex, 'all'),
|
|
200
|
+
limit: returnAll ? 50 : this.getNodeParameter('limit', itemIndex),
|
|
201
|
+
maxPages: this.getNodeParameter('maxPages', itemIndex),
|
|
202
|
+
includeContent: this.getNodeParameter('includeContent', itemIndex),
|
|
203
|
+
contentSource: this.getNodeParameter('contentSource', itemIndex, 'preview'),
|
|
204
|
+
});
|
|
205
|
+
output.push(...result.map((message) => ({ json: { ...message }, pairedItem: { item: itemIndex } })));
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
const safe = (0, LibrusClient_1.safeError)(error);
|
|
209
|
+
if (this.continueOnFail()) {
|
|
210
|
+
output.push({
|
|
211
|
+
json: { error: safe.message, code: safe.code },
|
|
212
|
+
pairedItem: { item: itemIndex },
|
|
213
|
+
});
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `${safe.code}: ${safe.message}`, {
|
|
217
|
+
itemIndex,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return [output];
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
exports.Librus = Librus;
|
|
225
|
+
//# sourceMappingURL=Librus.node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Librus.node.js","sourceRoot":"","sources":["../../../nodes/Librus/Librus.node.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export interface Request {
|
|
2
|
+
url: string;
|
|
3
|
+
method: 'GET' | 'POST';
|
|
4
|
+
headers: Record<string, string>;
|
|
5
|
+
body?: string;
|
|
6
|
+
timeout: number;
|
|
7
|
+
}
|
|
8
|
+
export interface Response {
|
|
9
|
+
statusCode: number;
|
|
10
|
+
headers: Record<string, string | string[] | undefined>;
|
|
11
|
+
body: string;
|
|
12
|
+
}
|
|
13
|
+
export type Transport = (request: Request) => Promise<Response>;
|
|
14
|
+
export interface Login {
|
|
15
|
+
username: string;
|
|
16
|
+
password: string;
|
|
17
|
+
}
|
|
18
|
+
export type ContentSource = 'preview' | 'full';
|
|
19
|
+
export type ReadStatus = 'all' | 'unread' | 'read';
|
|
20
|
+
export interface Scan {
|
|
21
|
+
returnAll: boolean;
|
|
22
|
+
limit: number;
|
|
23
|
+
maxPages: number;
|
|
24
|
+
includeContent: boolean;
|
|
25
|
+
contentSource?: ContentSource;
|
|
26
|
+
readStatus?: ReadStatus;
|
|
27
|
+
}
|
|
28
|
+
export interface Message {
|
|
29
|
+
messageId: string;
|
|
30
|
+
senderFirstName: string;
|
|
31
|
+
senderLastName: string;
|
|
32
|
+
senderName: string;
|
|
33
|
+
topic: string;
|
|
34
|
+
sendDate: string;
|
|
35
|
+
readDate: string | null;
|
|
36
|
+
isAnyFileAttached: boolean;
|
|
37
|
+
tags: string[];
|
|
38
|
+
category: string | null;
|
|
39
|
+
content?: string;
|
|
40
|
+
contentSource?: ContentSource;
|
|
41
|
+
}
|
|
42
|
+
type AuthStage = 'login entry' | 'credential submission' | 'authorization continuation' | 'messages initialization';
|
|
43
|
+
type AuthDestination = 'OAuth authorization' | 'Synergia OAuth callback' | 'Synergia login' | 'Synergia page' | 'messages service' | 'other allowed page';
|
|
44
|
+
export declare class LibrusError extends Error {
|
|
45
|
+
readonly code: string;
|
|
46
|
+
constructor(code: string, stage?: AuthStage, destination?: AuthDestination, rejection?: 'non-HTTPS destination' | 'URL credentials' | 'non-default port' | 'unrecognized hostname');
|
|
47
|
+
}
|
|
48
|
+
export declare function safeError(error: unknown): LibrusError;
|
|
49
|
+
export declare class LibrusClient {
|
|
50
|
+
private readonly transport;
|
|
51
|
+
private readonly login;
|
|
52
|
+
private jar;
|
|
53
|
+
private deadline;
|
|
54
|
+
private requests;
|
|
55
|
+
constructor(transport: Transport, login: Login);
|
|
56
|
+
private request;
|
|
57
|
+
private authenticate;
|
|
58
|
+
getMessages(options: Scan): Promise<Message[]>;
|
|
59
|
+
getMessageContent(messageId: string): Promise<{
|
|
60
|
+
messageId: string;
|
|
61
|
+
content: string;
|
|
62
|
+
contentSource: 'full';
|
|
63
|
+
}>;
|
|
64
|
+
private fullContent;
|
|
65
|
+
private scan;
|
|
66
|
+
}
|
|
67
|
+
export {};
|