Dla aplikacji zbudowanych na Supabase

Bramka AI dla
Supabase Edge Functions.

Zweryfikuj użytkownika Supabase, przekaż jego identyfikator w jednym nagłówku, a każde wywołanie AI zostanie zmierzone, ograniczone i przypisane do rozliczenia tej osoby. Dowolny model, jedno API zgodne z OpenAI, bez instalowania pakietu.

Bez pakietu, jeden wspólny plikZweryfikowany użytkownik przy każdym wywołaniuDziała też z Lovable Cloud
Jak płynie wywołanie

Twoja funkcja ustala, kto pyta. Resztą zajmuje się odnoga.

  1. Twoja aplikacja

    Wywołuje Edge Function z sesją zalogowanego użytkownika Supabase.

  2. Twoja Edge Function

    Weryfikuje JWT, odrzuca niezweryfikowanych, dodaje x-odnoga-end-user.

  3. odnoga

    Sprawdza środki użytkownika, kieruje do modelu, zapisuje koszt i czas odpowiedzi dla tej osoby.

Trzy kroki

Od Edge Function do pierwszego zmierzonego wywołania

  1. 1

    Załóż bezpłatne konto w odnodze i utwórz klucz API.

    W obszarze roboczym otwórz „Klucze API” i wybierz „Nowy klucz”.
  2. 2

    Zapisz go jako sekret Supabase.

    supabase secrets set ODNOGA_API_KEY=sk_live_…
  3. 3

    Dodaj helper i wywołuj go z dowolnej funkcji.

    Jeden wspólny plik. Każda funkcja, która go importuje, jest weryfikowana, mierzona i śledzona dla każdego użytkownika.
supabase/functions/_shared/odnoga.ts
// supabase/functions/_shared/odnoga.ts
import { createClient } from "jsr:@supabase/supabase-js@2";

const BASE = "https://api.odnoga.com/v1";

// Resolve the caller, or refuse. Your odnoga key is a paid credential: if
// this throws before it is used, an unauthenticated request cannot spend it.
export async function requireUser(req: Request): Promise<string> {
  const jwt = (req.headers.get("authorization") ?? "").split(" ")[1];
  if (!jwt) throw new Response("Unauthorized", { status: 401 });
  const supabase = createClient(
    Deno.env.get("SUPABASE_URL")!,
    Deno.env.get("SUPABASE_ANON_KEY")!,
  );
  // VERIFY the token. A decoded-but-unverified subject can be forged, and
  // the spend would land on someone else's account.
  const { data, error } = await supabase.auth.getUser(jwt);
  if (error || !data.user) throw new Response("Unauthorized", { status: 401 });
  return data.user.id;
}

// One caller per request, bound to the verified Supabase user.
export function odnoga(endUser: string, fn = "edge") {
  return (path: string, body: unknown) =>
    fetch(BASE + path, {
      method: "POST",
      headers: {
        "content-type": "application/json",
        Authorization: `Bearer ${Deno.env.get("ODNOGA_API_KEY")}`,
        "x-odnoga-end-user": endUser,   // whose usage this is
        "x-odnoga-function": fn,        // which of your functions spent it
      },
      body: JSON.stringify(body),
    });
}
Natywnie w środowisku Supabase

Co zyskujesz po dodaniu helpera

Użytkownik Supabase to użytkownik końcowy

Weryfikujesz JWT przez supabase.auth.getUser() i wysyłasz identyfikator w jednym nagłówku, x-odnoga-end-user. Od tej chwili każde wywołanie, koszt i limit należą do tej osoby. Identyfikator przypominający e-mail lub numer telefonu jest przed zapisem zamieniany na skrót.

Jeden sekret, tylko po stronie serwera

supabase secrets set ODNOGA_API_KEY=… Klucz jest w środowisku Edge Function — nigdy w przeglądarce ani w repozytorium.

Środki dla każdego użytkownika

Każdy użytkownik Supabase może mieć własny portfel. Gdy środki się skończą, odnoga odpowiada 402 end_user_exhausted, zanim zostanie wywołany jakikolwiek model — nikt nie wyda pieniędzy innej osoby ani Twoich.

Jak to działa

Rozliczaj użytkowników przez własny Stripe

Plany, płatność i portal rozliczeń dla Twoich użytkowników, powiązane z tym samym identyfikatorem. Przychód trafia na Twoje konto Stripe, nie nasze.

Jak to działa

Zobacz, która funkcja wydaje

Nazwij wywołującego nagłówkiem x-odnoga-function (i x-odnoga-app), a każda Edge Function dostanie własny koszt, liczbę wywołań i błędy oraz ostrzeżenie, gdy jej ruch ustanie lub gwałtownie wzrośnie.

Jak to działa

Wywołania z przeglądarki tokenami eut_

Twoja funkcja generuje krótkotrwały token dla jednego użytkownika przez POST /v1/sessions (klucz o zakresie przeglądarki i dozwolony origin; domyślnie godzina, najwyżej 24). Przeglądarka łączy się z odnogą bezpośrednio i nie widzi kosztów ani dostawcy.

Jak to działa

RAG z pgvector, dane zostają u Ciebie

Embeddingi i czat przez odnogę, wyszukiwanie wektorowe we własnej bazie, pod Twoim RLS. odnoga nie przechowuje embeddingów i nie łączy się z Twoim projektem.

Streaming, embeddingi, obrazy

Zgodne z OpenAI /chat/completions (ze streamingiem lub bez), /embeddings i /images/generations dla modeli z katalogu, za tym samym helperem.

Każde wywołanie to osobny zapis

Użytkownik, funkcja, model, wersja promptu, tokeny, koszt i czas odpowiedzi dla każdego wywołania — do przeszukania w panelu i do eksportu dla jednej osoby na potrzeby RODO.

Jak to działa
Przepisy

Trzy funkcje, które pewnie napiszesz

Wszystkie importują helper powyżej. Nazwy modeli pochodzą z aktualnego katalogu.

supabase/functions/chat/index.ts
import { odnoga, requireUser } from "../_shared/odnoga.ts";

Deno.serve(async (req) => {
  let userId: string;
  try {
    userId = await requireUser(req);
  } catch (refusal) {
    return refusal as Response;   // 401, before the paid key is touched
  }

  const { message } = await req.json();
  const ai = odnoga(userId, "chat");
  const r = await ai("/chat/completions", {
    model: "gpt-5.1",
    messages: [{ role: "user", content: message }],
  });
  // Pass the status through: a 402 (credits used) or 429 must not
  // reach your client as a 200.
  return new Response(r.body, {
    status: r.status,
    headers: { "content-type": "application/json" },
  });
});
Szczerze

Bezpośrednio do dostawcy czy przez odnogę?

Łącz się bezpośrednio, jeśli…

  • — jeden model jednego dostawcy wystarczy Ci na zawsze
  • — nie musisz wiedzieć, ile kosztuje każdy użytkownik
  • — nikt nie płaci Ci za AI w aplikacji

Dodaj odnogę, gdy…

  • — chcesz znać koszt AI każdego użytkownika, a nie jedną sumę miesięczną
  • — wydatki użytkownika mają zatrzymać się na limicie, zanim przyjdzie rachunek
  • — chcesz zmieniać modele bez ponownego wdrażania funkcji
  • — rozliczasz użytkowników za użycie przez Stripe
Pytania

Czy to oficjalny produkt Supabase?

Nie. odnoga to niezależna bramka AI, niezwiązana z Supabase. Integracja to zwykłe wywołanie HTTPS z Twojej Edge Function, więc nic w Twoim projekcie od nas nie zależy.

Czy muszę instalować pakiet?

Nie. Jeden plik w supabase/functions/_shared i jeden sekret. Endpoint jest zgodny z OpenAI, więc działa też każde SDK OpenAI po ustawieniu adresu bazowego na odnogę i dodaniu nagłówka.

Czy odnoga weryfikuje JWT moich użytkowników?

Nie — robi to Twoja Edge Function przez supabase.auth.getUser(). odnoga przypisuje użycie do identyfikatora, który wysyłasz, i właśnie dlatego helper odrzuca niezweryfikowane wywołanie, zanim użyje klucza.

A co z row-level security?

Bez zmian. odnoga nie łączy się z Twoją bazą. Klient Supabase i RLS nadal decydują, co widzi każdy użytkownik; odnoga zapisuje tylko wysłany identyfikator, by przypisać koszt.

Czy mogę ograniczyć wydatki jednego użytkownika?

Tak, przez portfele użytkowników: gdy środki się skończą, kolejne wywołanie zostanie odrzucone kodem 402. Budżety i alerty kwotowe działają dodatkowo dla całego obszaru roboczego.

Czy przeglądarka może łączyć się z odnogą bezpośrednio?

Tak. Utwórz klucz o zakresie przeglądarki z dozwolonym originem strony, wygeneruj w Edge Function token eut_ dla zalogowanego użytkownika przez POST /v1/sessions i użyj go jako bearer. Klucz serwerowy nie opuszcza serwera.

Moja aplikacja powstała w Lovable. Czy to mnie dotyczy?

Tak — aplikacje Lovable działają na Supabase, także w Lovable Cloud. Na stronie o Lovable jest jedno polecenie, po którym Lovable sam napisze ten helper.

Budujesz w Lovable? Jedno polecenie skonfiguruje to za Ciebie

Uruchom AI w Edge Functions już dziś.

Załóż konto, ustaw jeden sekret, dodaj jeden plik.