Nodea — logo

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żkaScopeOpis
GET/sharesalerting:readLista współdzieleń w modelu trzech skrzynek.
POST/sharesalerting:writeUdostępnij własny zasób innemu kontu.
POST/shares/{share}/acceptalerting:writeZaakceptuj oczekujące zaproszenie adresowane do Ciebie.
POST/shares/{share}/declinealerting:writeOdrzuć oczekujące zaproszenie adresowane do Ciebie.
DELETE/shares/{share}alerting:deleteUsuń 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 wiersze FOREIGN z pustym accepted_at).
  • incoming_accepted — współdzielenia, które zaakceptowałem od innych.
  • outbound — zaproszenia, które sam wysłałem (wiersze FOREIGN na 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_typewebsite, heartbeat lub server.
  • resource — zwięzłe podsumowanie udostępnionego zasobu (id, name, dla stron dodatkowo url, dla serwerów ip). Jest null, jeśli zasób usunięto po utworzeniu współdzielenia.
  • statuspending lub accepted.
  • 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 (lub null).

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

KodZnaczenie
401Brak lub nieprawidłowy token dostępowy.
403Token nie ma wymaganego scope'a (alerting:read / write / delete).
404Nieznany lub obcy share id — dostęp sprawdzany wierszowo.
422Błą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.

NazwaScopeTrybOpis
shares-listalerting:readtylko-odczytLista współdzieleń użytkownika z markerem box na każdym wierszu.
share-createalerting:writezapis (idempotentny)Udostępnij własny zasób innemu kontu po adresie e-mail.
share-acceptalerting:writezapisZaakceptuj oczekujące zaproszenie adresowane do Ciebie.
share-declinealerting:writezapisOdrzuć oczekujące zaproszenie (właściciel może wysłać nowe).
share-revokealerting:deletedestrukcyjny (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 }
  }
}