CLI cmssy
init generuje okablowanie w istniejącej aplikacji, add block tworzy i rejestruje blok, link łączy aplikację z workspace'em i dowodzi, że działa, a types generuje TypeScript dla modeli workspace'u.
Każda z poniższych komend obsługuje moment, który kiedyś był robotą ręczną: okablowanie nowej aplikacji, dodanie bloku i podłączenie do workspace'u.
cmssy init
cmssy nigdy nie scaffolduje Twojej aplikacji. Framework jest adapterem, nigdy fundamentem - aplikację tworzysz własnym CLI Next.js, a init dokłada do niej okablowanie cmssy.
npx create-next-app@latest my-site
cd my-site
npx @cmssy/cli initCLI celuje w Next.js z App Routerem i wymaga Node 18.18+. Astro, Remix i React Router są wspierane przez samo SDK - te podpinasz ręcznie, a nie przez init.
Jest idempotentne: plik, który już istnieje, jest pomijany i raportowany jako pominięty, nigdy nadpisywany. Uruchom dwa razy, a drugi przebieg niczego nie zmieni.
Co zapisuje
cmssy.config.ts
proxy.ts
next.config.mjs
env.example
cmssy/blocks.ts rejestr bloków
cmssy/editor.tsx most edytora
blocks/hero/block.ts
blocks/hero/Hero.tsx
blocks/hero/Hero.module.css
app/[[...path]]/page.tsx catch-all route
app/api/draft/route.ts podgląd roboczyZwróć uwagę, czego tam nie ma: żadnego app/sitemap.ts, żadnego app/robots.ts, żadnego route'u /cmssy-edit, żadnego root layoutu ani edytowalnego layoutu.
To jest celowe, a nie brakujące. Te pliki kodują decyzje o Twojej aplikacji - jakie URL-e wystawiasz, jak wygląda Twoje chrome, jak kształtujesz sitemapę - a szablon, który by je zgadywał, byłby zły dla większości projektów. init daje Ci renderującą stronę i route roboczy; resztę dokładasz sam, według route'ów i stron, layoutów i SEO.
Flagi: --dir <ścieżka> celuje w aplikację poza katalogiem roboczym, --force nadpisuje istniejące okablowanie.
cmssy add block
Każdy blok po wygenerowanym hero oznaczał kiedyś ręczne kopiowanie plików i pamiętanie o edycji rejestru.
cmssy add block pricing-table
cmssy add block faq-list --dir ../my-siteWszystkie nazwy wyprowadza z argumentu w kebab-case: pricing-table daje typ pricing-table, etykietę Pricing Table, komponent PricingTable i eksport pricingTableBlock.
Zapisuje pliki bloku i rejestruje go w cmssy/blocks.ts - dodaje import i dopisuje do tablicy blocks, zachowując Twoje formatowanie i istniejące wpisy.
Odmawia tknięcia czegokolwiek niejednoznacznego: nieprawidłowej nazwy, już zarejestrowanego bloku, istniejących plików albo rejestru bez tablicy export const blocks = [...]. Każdy z tych przypadków to głośny błąd z wypisanym krokiem ręcznym - nigdy cichy częściowy zapis.
Wygenerowany blok startuje z wymaganym heading i opcjonalnym text. Zmień propsy i markup, zrestartuj dev server, a edytor podchwyci nowy typ z handshake'u manifestu.
cmssy link
Podłączenie aplikacji do workspace'u oznaczało kiedyś ręczne przeklejanie pięciu wartości między panelem a .env.local - a edytor pozostawał martwy, dopóki każda nie była poprawna.
npx @cmssy/cli link
cmssy link --token cs_... --workspace acme/shop --preview-url https://shop.example.comUwierzytelnia się tokenem API (z --token albo CMSSY_API_TOKEN; .env.local i .env są czytane najpierw, nigdy nie nadpisując zmiennych z powłoki), wybiera workspace, odczytuje draft secret, zapisuje CMSSY_ORG_SLUG, CMSSY_WORKSPACE_SLUG i CMSSY_DRAFT_SECRET do .env.local - scalając, więc istniejące linie i komentarze przeżywają - po czym odpala preflight i wypisuje deep link do edytora.
Odczyt draft secretu wymaga uprawnienia PAGES_EDIT. Jego brak jest raportowany dokładnie jako to.
Preview URL jest współdzielony - localhost jest odrzucany
--preview-url ustawia origin, pod którym edytor osadza Twoją aplikację dla wszystkich w workspace. Wartość localhost jest odrzucana celowo: wskazanie współdzielonego podglądu na Twoją maszynę zepsułoby edytor każdemu współpracownikowi.
Do pracy lokalnej przełącz tryb dev w edytorze cmssy i wpisz tam swój lokalny host. Ten cel jest per użytkownik i nie dotyka niczego współdzielonego. Bez flagi wartość pozostaje niezmieniona.
Sprawdzenia
- Workspace osiągalny -
public.siteConfigodpowiada dla podłączonej organizacji i workspace'u. Rozróżnia złe slugi, problemy sieciowe i workspace ponad limitem. - Draft secret - backend potwierdza, że zapisany sekret się zgadza. Na platformie bez tego pola raportuje
?i idzie dalej. - Deep link do edytora - zawsze wypisywany.
- Link podglądu roboczego - wypisywany, gdy workspace zgłasza preview URL. Wyjście z trybu roboczego:
/api/draft?disable=1.
Statusy są trzy, nie dwa: ✓ zweryfikowane, ✗ zepsute z poprawką w następnej linii i kodem wyjścia 1, oraz ? nie dało się zweryfikować - co nigdy nie blokuje. Ten trzeci stan istnieje, bo "nieznane" i "zepsute" to różne rzeczy, a narzędzie, które je sklei, albo krzyczy bez powodu, albo ukrywa prawdziwą awarię.
Preflight jest też API
Każde sprawdzenie to czysta funkcja w @cmssy/core, wystawiona pod podsceżką, żeby narzędzia deweloperskie nigdy nie trafiły do Twojego bundla produkcyjnego:
import {
checkWorkspaceReachable,
checkDraftSecret,
checkPreviewUrl,
checkFrameAncestors,
buildEditorUrl,
} from "@cmssy/core/preflight";Każda zwraca { status: "ok" | "fail" | "unknown", message, fix? }. Dwie pierwsze rozmawiają z API dostawczym; reszta to czysta logika na stringach. Żadna nie importuje frameworka ani wbudowanego modułu Node'a, więc działają wszędzie - w endpoincie health, w kroku CI, w dashboardzie.
Gdy okablowanie jest zepsute
W developmencie te same sprawdzenia pilnują route'u edycyjnego. Żądanie edytora, które nie przejdzie weryfikacji, nie daje 404 - adapter renderuje stronę diagnostyczną wewnątrz ramki edytora, linia na sprawdzenie: brakujące zmienne środowiskowe i skąd je wziąć, nieosiągalny workspace, niezgodność draft secretu, porównanie preview URL i originy, które musi dopuszczać frame-ancestors.
Pokazuje slug workspace'u i które sprawdzenie padło, nigdy wartości sekretu.
cmssy types
Generuje TypeScript dla modeli workspace'u, więc data rekordu przestaje być unknown.
npx @cmssy/cli types # cmssy/models.ts + cmssy/operations.graphql
npx @cmssy/cli types --out types/cms.ts
npx @cmssy/cli types --check # CI: pada, gdy któryś plik jest nieaktualnyCzyta definicje modeli przez publiczne API dostawcze, z tymi samymi CMSSY_ORG_SLUG / CMSSY_WORKSPACE_SLUG, których używa Twoja aplikacja (z .env.local / .env). Bez tokenu API, więc działa w CI.
Flagi: --out <ścieżka>, --operations-out <ścieżka>, --no-operations, --check, --org <slug>, --workspace <slug>.
Dla każdego modelu zapisuje <Model>Data i <Model>Record (czyli CmssyRecordOf<<Model>Data>):
- pola wymagane są nieopcjonalne, reszta opcjonalna
- pola lokalizowane mają typ
CmssyLocalized - select, radio i multiselect stają się unią swoich wartości opcji, więc literówka w filtrze to błąd kompilacji
- relacja to id rekordu (lub rekordów), które przechowuje, a model docelowy jest nazwany w komentarzu dokumentacyjnym
- pola object i repeater są rozwijane w miejscu; pola ukryte są pomijane
- komentarze dokumentacyjne niosą etykietę każdego pola w domyślnym języku workspace'u
Zapisuje też cmssy/operations.graphql - zapytania dostawcze, które wysyła sam @cmssy/core - dla Twojego codegenu GraphQL: dodaj "cmssy/**/*.graphql" do documents. Plik jest nadpisywany przy każdym uruchomieniu. Jeśli Twoja aplikacja już deklaruje operację o tej samej nazwie, komenda się zatrzymuje i wskazuje plik: usuń swoją kopię albo przekaż --no-operations, żeby ją zachować.
Commituj oba pliki i uruchom ponownie po zmianie modelu w CMS-ie - usunięte pole staje się błędem kompilacji. Wymaga @cmssy/cli 19.6.0 lub nowszego; starsze wersje padają na obecnym API.
Następne kroki
- Instalacja - co generuje
init, wyjaśnione. - Tworzenie bloków - co zrobić ze zescaffoldowanym blokiem.
- Podgląd roboczy - sekrety, które zapisuje
link.