Współdzielenie zasobów (shares) — API v1 i MCP | Nodea
Zasoby typu share pozwalają nadać innemu zarejestrowanemu kontu dostęp do odczytu Twojej strony, heartbeatu lub serwera. To odpowiednik strony /app/share/* w panelu, wystawiony jako REST API v1 oraz zestaw narzędzi MCP. Współdzielenie nie jest bramkowane flagą modułu (brak middleware features:, dokładnie jak sharing w panelu WWW) — wystarczy odpowiedni scope z grupy alerting.
Wszystkie endpointy działają pod ścieżką bazową /api/v1 (przykładowy host: https://app.nodea.io/api/v1). Uwierzytelnianie realizuje osobisty token dostępowy Passport przekazany w nagłówku Authorization: Bearer <token>. Obowiązuje limit throttle:api-v1 = 240 żądań/min. Wymagane scope'y: odczyt alerting:read, zapis alerting:write, usuwanie alerting:delete. Dostęp jest sprawdzany wierszowo w kontrolerze — obce lub nieznane share id zwracają 404.
API v1
| Metoda | Ścieżka | Scope | Opis |
|---|---|---|---|
GET | /shares | alerting:read | Lista współdzieleń w modelu trzech skrzynek. |
POST | /shares | alerting:write | Udostępnij własny zasób innemu kontu. |
POST | /shares/{share}/accept | alerting:write | Zaakceptuj oczekujące zaproszenie adresowane do Ciebie. |
POST | /shares/{share}/decline | alerting:write | Odrzuć oczekujące zaproszenie adresowane do Ciebie. |
DELETE | /shares/{share} | alerting:delete | Usuń współdzielenie: revoke (jako właściciel) lub leave (jako odbiorca). |
GET /shares — model trzech skrzynek
Listę porządkują trzy skrzynki, dokładnie jak strona /sharing w panelu. Parametr zapytania box przyjmuje jedną z wartości:
incoming_pending— zaproszenia adresowane do mnie, oczekujące na moją odpowiedź (obce wierszeFOREIGNz pustymaccepted_at).incoming_accepted— współdzielenia, które zaakceptowałem od innych.outbound— zaproszenia, które sam wysłałem (wierszeFOREIGNna zasobach, które posiadam), wraz z odbiorcą.
Gdy przekażesz box, zwracany jest jeden zestaw z prostą paginacją (per_page, domyślnie 20, maks. 100; page). Gdy pominiesz box, endpoint zwraca wszystkie trzy skrzynki w jednym obiekcie JSON (klucze incoming_pending, incoming_accepted, outbound), każda ograniczona do per_page wierszy — do stronicowania konkretnej skrzynki użyj parametru box.
curl -s https://app.nodea.io/api/v1/shares?box=incoming_pending \
-H "Authorization: Bearer $TOKEN"Każdy wiersz odpowiedzi (ShareResource) zawiera pola:
id— identyfikator współdzielenia.resource_type—website,heartbeatlubserver.resource— zwięzłe podsumowanie udostępnionego zasobu (id,name, dla stron dodatkowourl, dla serwerówip). Jestnull, jeśli zasób usunięto po utworzeniu współdzielenia.status—pendinglubaccepted.accepted_at,created_at— znaczniki czasu ISO 8601.recipient— konto, któremu zasób udostępniono (id,name,email).owner— właściciel zasobu bazowego (lubnull).
POST /shares — udostępnij zasób
Body wymaga trzech pól: resource_type (enum website | heartbeat | server), resource_id (id zasobu — strony i heartbeaty mają id całkowite, serwery UUID) oraz email zapraszanego konta (musi należeć do zarejestrowanego użytkownika).
Zasób musi być własnością wywołującego. Nieistniejące i obce id zwijają się do tego samego błędu 422, aby endpointu nie dało się użyć do wyliczania cudzych identyfikatorów. Próba udostępnienia zasobu samemu sobie również kończy się 422.
Dla stron i heartbeatów tworzone jest oczekujące zaproszenie (share w stanie pending) i wysyłane powiadomienie — chyba że odbiorca ma włączone auto-akceptowanie od nadawcy (wtedy od razu accepted). Udziały serwerów nie mają handshake'u i stają się aktywne natychmiast (accepted_at stemplowane od razu). Powodzenie zwraca 201 Created z reprezentacją share. Ponowne udostępnienie już współdzielonego zasobu zwraca 409 Conflict z kodem already_shared. Podpisane linki zaproszeń pozostają wyłącznie po stronie panelu WWW.
curl -s -X POST https://app.nodea.io/api/v1/shares \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"resource_type":"website","resource_id":"42","email":"collab@example.com"}'POST /shares/{share}/accept i /decline — handshake odbiorcy
Zaproszenie może zaakceptować lub odrzucić wyłącznie odbiorca oczekującego wiersza FOREIGN adresowanego do niego. Ktokolwiek inny — łącznie z właścicielem zasobu — otrzymuje 404 (to po prostu nie jest jego zaproszenie). accept stempluje accepted_at = now() i zwraca zaktualizowany zasób; decline usuwa wiersz i zwraca 204 No Content (właściciel może później wysłać nowe zaproszenie).
curl -s -X POST https://app.nodea.io/api/v1/shares/123/accept \
-H "Authorization: Bearer $TOKEN"DELETE /shares/{share} — revoke vs leave
Ten endpoint usuwa tylko wiersze FOREIGN (wiersz OWNER to księgowanie widoczności właściciela — jego usunięcie zwraca 404). Kontroler sam rozstrzyga rolę i znaczenie operacji:
- revoke — jeśli wywołujący jest właścicielem zasobu bazowego, odbiera odbiorcy dostęp.
- leave — jeśli wywołujący jest odbiorcą zaakceptowanego współdzielenia, sam z niego rezygnuje.
Oczekujące zaproszenie nie jest usuwane tutaj — do jego odrzucenia służy endpoint decline. Powodzenie zwraca 204 No Content. Brak uprawnień do wiersza (ani właściciel, ani odbiorca zaakceptowanego share) daje 404.
curl -s -X DELETE https://app.nodea.io/api/v1/shares/123 \
-H "Authorization: Bearer $TOKEN"Kody błędów
| Kod | Znaczenie |
|---|---|
401 | Brak lub nieprawidłowy token dostępowy. |
403 | Token nie ma wymaganego scope'a (alerting:read / write / delete). |
404 | Nieznany lub obcy share id — dostęp sprawdzany wierszowo. |
422 | Błąd walidacji: nieznany/obcy zasób, udostępnienie samemu sobie, zły box. |
MCP
Serwer MCP Nodea udostępnia pięć narzędzi do współdzielenia. Każde egzekwuje ten sam scope co odpowiadający mu endpoint REST. Tryb tylko-odczyt nie zmienia stanu; tryb destrukcyjny wymaga jawnego potwierdzenia confirm: true, aby agent nie odciął komuś dostępu na podstawie luźno zinterpretowanej instrukcji.
| Nazwa | Scope | Tryb | Opis |
|---|---|---|---|
shares-list | alerting:read | tylko-odczyt | Lista współdzieleń użytkownika z markerem box na każdym wierszu. |
share-create | alerting:write | zapis (idempotentny) | Udostępnij własny zasób innemu kontu po adresie e-mail. |
share-accept | alerting:write | zapis | Zaakceptuj oczekujące zaproszenie adresowane do Ciebie. |
share-decline | alerting:write | zapis | Odrzuć oczekujące zaproszenie (właściciel może wysłać nowe). |
share-revoke | alerting:delete | destrukcyjny (confirm: true) | Revoke (właściciel) lub leave (odbiorca) aktywnego współdzielenia. |
Narzędzie share-create jest idempotentne — ponowne udostępnienie już współdzielonego zasobu to no-op (status: already_shared). Narzędzia share-accept i share-decline działają wyłącznie na oczekującym zaproszeniu adresowanym do wywołującego; nie wymagają potwierdzenia, bo nic nieodwracalnego nie ginie (odrzucone zaproszenie właściciel może odtworzyć). Tylko share-revoke jest oznaczone jako destrukcyjne i wymaga confirm: true.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "shares-list",
"arguments": { "box": "incoming_pending", "per_page": 15 }
}
}{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "share-create",
"arguments": {
"resource_type": "website",
"resource_id": "42",
"recipient_email": "collab@example.com"
}
}
}{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "share-revoke",
"arguments": { "id": 123, "confirm": true }
}
}