GenHTTP Lambda

Jak to działa

Piszesz snippet w C#. To, co zwraca, w kilka sekund trafia pod publiczny adres HTTPS. Poniżej wszystko po kolei – w takiej kolejności, w jakiej na to trafisz.

Czym jest lambda

Lambda to snippet, który zwraca handler GenHTTP. Platforma go kompiluje, ładuje i montuje to, co zwrócił, pod twoim własnym adresem. Nie ma projektu, pliku builda ani instrukcji using. Wszystkie moduły GenHTTP są już zaimportowane.

return Content.From(Resource.FromString("hello"));

To kompletna lambda. Wdrożona pod /lambda/your-key/ odpowiada na każde żądanie słowem hello.

Snippet to instrukcje, a nie klasa. Na końcu zwraca coś, co potrafi obsługiwać żądania: handler albo builder, który go tworzy.

Twoja pierwsza lambda

  1. 1
    Kliknij Utwórz lambdę. Dostaniesz publiczny adres i klucz edytora. Klucz to jedyna droga powrotu, więc go zachowaj. Nikt go za ciebie nie odzyska.
  2. 2
    Trafiasz do centrum sterowania, a pierwsza wersja to już gotowa mała usługa REST. To tylko punkt wyjścia.
  3. 3
    Daj klucz edytora agentowi i powiedz, co ma zbudować – zapisuje nowe wersje przez MCP. Albo otwórz Kod i napisz wszystko samodzielnie: Sprawdź kompiluje bez zapisywania i pokazuje, co mówi kompilator – z nazwą pliku i numerem linii.
  4. 4
    Kliknij Wdróż. Teraz lambda jest online. Wcześniej nic nie jest dostępne, a każde kolejne wdrożenie wydłuża czas, przez który pozostaje online.

Centrum sterowania

Link do edytora otwiera centrum sterowania, a nie pole tekstowe: większość kodu piszą tu agenci, więc najpierw widzisz, jak radzi sobie twoja lambda. Na pasku bocznym jest sama lambda – czy jest online, jej adres i przycisk, gdy nowsza wersja czeka na wdrożenie – oraz jej sekcje. Rzadsze akcje, jak zmiana adresu czy usunięcie, są tam w menu ⋯.

Przegląd
Czy jest online, ile dziś było żądań i ile z nich się nie udało, ostatnia zmiana i ile zostało miejsca.
Zmień
Napisz, co ma być inaczej, a agent na tym serwerze zrobi to na twoich oczach. Pracuje w szkicu, tam sprawdza zmianę, a gdy działa, scala szkic w kolejną wersję. Wyłącz Wdróż po zakończeniu, jeśli chcesz najpierw samodzielnie wypróbować szkic.
Szkice
Zmiany przygotowywane obok lambdy: każdą wypróbowuje się pod osobnym adresem i scala w kolejną wersję, gdy jest gotowa. Otwarty szkic ma własny kod, dane i logi.
Pliki
Pliki danej wersji: jej kod i zasoby, czyli sam program. Kłódka albo globus pokazuje, czy są publicznie dostępne.
Dane
To, co lambda przechowuje w trakcie działania, wspólne dla wszystkich wersji: obszar roboczy. Zajrzyj do środka, przesyłaj i usuwaj pliki albo go wyłącz.
Wersje
Co zmieniła każda wersja, o co proszono i czym różni się od poprzedniej. Stąd wdrażasz wersję albo wracasz do starszej – albo tworzysz szkic na bazie dowolnej z nich.
Wdrożenia
Co i kiedy było online – i co to wyłączyło.
Statystyki
Żądania, błędy, czasy odpowiedzi i najczęściej odwiedzane ścieżki z ostatniej godziny albo ostatnich 24 godzin.
Logi
Żądania, to, co lambda wypisała, i stack trace każdego błędu – na bieżąco.
Kod
Tu piszesz kod ręcznie. Sprawdź kompiluje, Zapisz tworzy wersję, Wdróż wrzuca kod online. W szkicu Zapisz zostawia kod w szkicu, a Wdróż podgląd wrzuca go online pod adresem szkicu. Ctrl-S zapisuje; F12 przechodzi do deklaracji.

Każda sekcja działa tak samo: tytuł, ⓘ z wyjaśnieniem, akcje po prawej i – jeśli sekcja ma kilka widoków – rząd zakładek pod spodem. W sekcji Kod zakładki to pliki.

Ruch i log są trzymane w pamięci – do podglądu, nie do archiwizacji: po restarcie serwera zaczynają się od zera. Wersje i historia wdrożeń są zapisywane na stałe.

Opisz, dlaczego

Wersja to kod i opcjonalnie dwie notatki o nim: specyfikacja, czyli czego chce użytkownik i dlaczego – najlepiej jego słowami, oraz zmiana, czyli jedna linijka o tym, co robi ta wersja. Obie widać obok diffu w historii wersji, więc dlaczego zostaje obok co – dla ciebie i dla następnego agenta, który przeczyta historię, zanim cokolwiek zmieni.

POST /api/v1/lambdas/{editorKey}/versions
{
  "files": [ { "name": "lambda.cs", "code": "..." } ],
  "specification": "Księga gości, którą ludzie mogą podpisać; wpisy muszą przetrwać restart",
  "change": "Trzyma wpisy w obszarze roboczym, żeby przetrwały restart"
}

Agenci przekazują te same dwa pola do write_code. W sekcji Kod o zmianę pyta okno zapisywania. Oba pola są opcjonalne. Za długi tekst nie jest odrzucany, tylko przycinany: specyfikacja do 4000 znaków, zmiana do 500. Szkic ma własne dwa pola, a wersja, w którą zostanie scalony, je przejmuje.

Bezpieczne zmiany

Zapisana wersja nigdy się nie zmienia – i właśnie dlatego każdą warto zachować: każdą można porównać i przywrócić online dokładnie taką, jaka była. Żeby zmienić lambdę, z której ludzie korzystają, utwórz zamiast tego szkic.

  1. 1
    Utwórz go w sekcji Szkice albo na bazie dowolnej wersji. To kopia kodu i zasobów tej wersji oraz danych lambdy.
  2. 2
    Zmieniaj go tyle razy, ile trzeba – w sekcji Kod albo prosząc agenta. Wdróż podgląd wrzuca go online pod osobnym adresem, /features/…/, na jego własnej kopii danych. Odwiedzający lambdę nic z tego nie widzą, a nic, co zapisze szkic, nie trafia do danych lambdy.
  3. 3
    Scal go, gdy wszystko będzie gotowe: stanie się kolejną wersją razem ze swoimi notatkami i od razu trafi online, jeśli zechcesz. Szkic znika – razem z podglądem i kopią danych.
POST /api/v1/lambdas/{editorKey}/features
{ "name": "Ranking" }

PUT  /api/v1/lambdas/{editorKey}/features/{feature}/files?deploy=true
POST /api/v1/lambdas/{editorKey}/features/{feature}/merge
{ "deploy": true }

Nad kilkoma szkicami można pracować jednocześnie. Scalić można tylko szkic oparty na najnowszej wersji, żeby scalenie nigdy nie cofnęło wersji zapisanej po utworzeniu szkicu. Jeśli wcześniej scalono inny, przenieś jego zmiany – albo poproś o to agenta – a potem oprzyj szkic na najnowszej wersji. Nic nie scala się samo; tak ma być.

Więcej niż jeden plik

Typów nie trzeba dopisywać pod kodem, który ich używa. W sekcji Kod kliknij + obok plików, a nowy plik zostanie skompilowany obok snippetu, w tej samej przestrzeni nazw – nic nie trzeba importować. Nazwa bez rozszerzenia oznacza plik C#.

lambda.cs
var shelf = new Shelf();

return Inline.Create()
             .Get(() => shelf.All())
             .Post((Book book) => shelf.Add(book));
Shelf.cs
public sealed class Shelf
{
    private readonly List<Book> _books = [];

    public IEnumerable<Book> All() => _books;

    public Book Add(Book book)
    {
        _books.Add(book);
        return book;
    }
}

public record Book(string Title, string Author);

Serwowanie strony

Stronę można serwować na dwa sposoby, a do tego jest jeszcze trzeci – na to, co ludzie przesyłają obok niej.

Jedna strona, wpisana w kod

Wystarczy do czegoś małego. Strona jest częścią snippetu.

var page = Resource.FromString("""
                              <!doctype html>
                              <title>Mine</title>
                              <h1>It works</h1>
                              """)
                   .Type(new ContentType("text/html; charset=utf-8"));

return Content.From(page);

Folder z prawdziwymi plikami

Najlepszy wybór, gdy masz arkusz stylów i skrypt. Pliki dodajesz tak samo jak plik C#, a serwowane są dokładnie tak, jak je napiszesz. Nic ich nie kompiluje.

return Layout.Create()
             .Add("api", api)
             .Add(Assets.App("site"));

Przesłane pliki, z danych

Na to, co przesyłają ludzie albo tworzy lambda – zdjęcia, dokumenty – serwowane obok aplikacji. Nie na strony samej aplikacji: ich miejsce jest w folderze z plikami, gdzie trafiają do wersji razem z kodem, który ich potrzebuje.

return Layout.Create()
             .Add("api", api)
             .Add("uploads", Workspace.Files("uploads"))
             .Add(Assets.App("site"));

Frontend krok po kroku

Drugi sposób, krok po kroku. Każde demo serwuje swoją stronę właśnie tak, z folderu web – otwórz demo-crud, żeby zobaczyć przykład. Dema są tylko do odczytu; ich klucz edytora to ich nazwa.

  1. 1
    W sekcji Kod kliknij + obok plików i wpisz site/index.html. Ukośnik w nazwie umieszcza plik w folderze, a rozszerzenie mówi, jakim plikiem jest.
  2. 2
    Tak samo dodaj site/app.css i site/app.js. Strona odwołuje się do nich po nazwie, np. href="app.css", bo folder to katalog główny serwowanych plików, a nie część adresu.
  3. 3
    Pliki, które nie są tekstem, np. obrazek czy font, dodasz tak: otwórz dowolny plik w site i kliknij przycisk przesyłania obok plików – plik trafi do tego samego folderu. PNG nie da się wpisać w edytor tekstu, więc to jedyna droga.
  4. 4
    W lambda.cs serwuj ten folder:
    return Layout.Create().Add(Assets.App("site"));
  5. 5
    Kliknij Wdróż. site/index.html odpowiada pod /, site/app.css pod /app.css, a na każdy adres, który nie pasuje do żadnego pliku, odpowiada strona. Dzięki temu frontend z własnym routingiem działa, nawet gdy ktoś odświeży głęboki link.
  6. 6
    Dodaj obok API, a strona będzie miała z czym rozmawiać:
    var api = Inline.Create().Get("notes", () => notes);
    
    return Layout.Create()
                 .Add("api", api)
                 .Add(Assets.App("site"));

Dwa miejsca na pliki

Lambda trzyma pliki w dwóch miejscach, a edytor pokazuje je osobno: Pliki to pliki wersji – program – a Dane to obszar roboczy – to, co program przechowuje. Cała różnica polega na tym, do kogo należą. Pliki wersji należą do tej wersji; dane należą do lambdy i wszystkie wersje je współdzielą.

W wersjiW danych
co zawierakod i zasoby: program, łącznie z frontendemwszystko, co zapisze lambda albo ktoś prześle
kiedy się zmienianigdy – zmiana to nowa wersjaw chwili, gdy coś zostanie zapisane
wdrożeniewrzuca online dokładnie te plikinigdy ich nie rusza
powrót do starszej wersjiprzywraca stare plikibez wpływu: wszystkie wersje je współdzielą
szkiczaczyna jako ich kopiadziała na ich kopii
kiedy znikarazem ze starymi wersjami, po przekroczeniu limiturazem z lambdą albo gdy je wyłączysz
dostęp z kodu przezAssetsWorkspace

Nie mogą być jednym miejscem. Gdyby były, każde wdrożenie albo kasowałoby wszystko, co lambda zapisała od poprzedniego, albo z tego, co wdrażasz, nie dałoby się nigdy niczego usunąć. Gra z rankingiem potrzebuje tego drugiego, a strona, którą serwuje – pierwszego. Dlatego strona trafia do wersji, a ranking do danych.

Przechowywanie danych

Workspace to prywatny katalog, w którym lambda może czytać i zapisywać. To miejsce na wszystko, co ma przetrwać dłużej niż jedno żądanie albo jedno wdrożenie.

var notes = new List<string>();

if (Workspace.Exists("notes.json"))
{
    notes.AddRange(JsonSerializer.Deserialize<List<string>>(Workspace.ReadText("notes.json")) ?? []);
}

return Inline.Create()
             .Get("notes", () => notes)
             .Post("notes", (string text) =>
             {
                 notes.Add(text);
                 Workspace.WriteText("notes.json", JsonSerializer.Serialize(notes));
                 return notes.Count;
             });

Są też ReadBytes, WriteBytes, Delete, List, CreateFolder oraz Tree/Files/App do serwowania. Nic więcej w systemie plików nie jest dostępne.

Websockety

Obsługiwane – i to nie na doczepkę. Demo demo-game łączy graczy w pary i prowadzi każdą grę na serwerze. Najprostsza wersja to trzy callbacki:

var room = new ConcurrentDictionary<IReactiveConnection, string>();

var socket = Websocket.Functional()
                      .OnOpen(c => { room[c] = "someone"; return ValueTask.CompletedTask; })
                      .OnMessage(async (c, text) =>
                      {
                          foreach (var other in room.Keys)
                          {
                              await other.WritePayloadAsync(text);
                          }
                      })
                      .OnClose((c, _) => { room.TryRemove(c, out _); return ValueTask.CompletedTask; });

return Layout.Create().Add("chat", socket);

Jedna rzecz zaskakuje każdego: przeglądarka nie może ustawić nagłówków przy nawiązywaniu połączenia websocket. Przekaż to, czego potrzebuje handler, w query stringu, skąd odczyta to przez connection.Request.Header.Query, albo wyślij sekrety w pierwszej wiadomości.

Czego nie da się zrobić

Twój kod działa na wspólnym serwerze, więc część C# jest odrzucana jeszcze przed kompilacją: uruchamianie procesów, otwieranie własnych socketów, ładowanie assembly, sięganie do systemu plików poza obszarem roboczym i refleksja użyta, żeby to wszystko obejść.

Cała reszta jest dostępna, łącznie z pełnym API modułów GenHTTP. Jeśli coś zostanie odrzucone, dowiesz się, w której linii i dlaczego – a nie tylko, że się nie udało.

Zabierz kod ze sobą

Pobierz jako projekt .NET w menu edytora daje ci całość: solution, które możesz otworzyć, uruchomić przez dotnet run i zachować na zawsze. Ma jedną referencję do pakietu i ani śladu tej platformy.

Twój snippet staje się treścią Program.cs, opakowaną w hosta, który serwuje to, co snippet zwraca. Pozostałe pliki trafiają do projektu bez zmian. Workspace i Assets stają się dwoma folderami obok kodu, z tymi samymi metodami, więc w kodzie nie trzeba nic zmieniać.

Warto to wiedzieć, zanim cokolwiek tu zbudujesz: to, co piszesz, należy do ciebie i możesz to zabrać w całości. To, że kod działa na tej maszynie, w niczym go do niej nie przywiązuje.

Niech zrobi to agent

Pod /mcp działa endpoint MCP. Podłącz do niego agenta, a zrobi wszystko to, co edytor: przeczyta dokumentację, przeczyta całe demo, zapisze pliki, skompiluje je i wdroży. Pod spodem to samo API.

Przy okazji mówi, dlaczego coś robi – write_code przyjmuje specyfikację i zmianę – i może sprawdzić, co wdrożył: read_logs zwraca ostatnie żądania lambdy, to, co wypisała, i stack trace każdego wyjątku. Tak agent dowiaduje się, że jego kod działa, zamiast to zakładać. Ty widzisz to samo w centrum sterowania.

Więcej o tym →