SubSovereign
All guides

SubSovereign Web Component — przewodnik integracji (Vue, Svelte, Angular, czysty HTML)

Ten przewodnik dotyczy sdk-web/ — frameworkowo-niezależnego SDK przeglądarkowego. Zawiera klienta danych oparty na fetch oraz dwa Web Componenty, <subsovereign-paywall> i <subsovereign-withdrawal>, które działają na każdej stronie — Vue, Svelte, Angular lub zwykłej stronie HTML — bez kroku kompilacji i bez zależności. (Używasz Reacta? Skorzystaj z przewodnika dla Reacta.)

Przed rozpoczęciem

Działający serwer SubSovereign, zarejestrowana aplikacja w panelu (zawierająca appId i klucz API w roli SDK), oraz opublikowana bramka płatności.

Krok 1 — Załadowanie i konfiguracja

<script type="module">
  import { SubSovereign } from './sdk-web/src/index.js'; // importing registers the elements

  SubSovereign.configure({
    apiKey:  'YOUR_SDK_KEY',
    appId:   'your-app-id',
    baseUrl: 'https://subs.yourdomain.com/api/v1', // YOUR self-hosted server
    userId:  currentUser.id,                        // your own stable user id
    locale:  'en',
  });
</script>

Krok 2 — Sprawdzanie dostępu użytkownika

const { hasAccess } = await SubSovereign.checkEntitlements();
if (hasAccess) showPremiumContent();
else showPaywall();

W przypadku prostego zabezpieczenia dostępna jest metoda hasAccess(), opcjonalnie dla konkretnego poziomu dostępu. Działa zamknięcie awaryjne: w przypadku błędu sieci zwraca false, więc chwilowa awaria nigdy nie odblokuje płatnej zawartości przez przypadek.

if (await SubSovereign.hasAccess('pro')) showPremiumContent();

Metoda checkEntitlements() zgłasza wyjątek w przypadku niepowodzenia, aby użytkownik mógł pozostać przy ostatnio znanym dostępie; hasAccess() nigdy nie zgłasza wyjątku. Wybierz tę, której zachowanie w przypadku awarii Ci odpowiada.

Krok 3 — Wyświetlanie bramy płatności i sprzedaż

<subsovereign-paywall id="pw"></subsovereign-paywall>

<script type="module">
  const pw = document.getElementById('pw');
  pw.config = await SubSovereign.getPaywallConfig(); // platform defaults to 'web'
  pw.addEventListener('select-product', (e) => {
    startCheckout(e.detail.productId);               // wire to your checkout
  });
</script>

Rozmiar bramy jest Twoim zadaniem. Domyślna szerokość wynosi 420px; możesz ją powiększyć za pomocą właściwości CSS (właściwości niestandardowe przenikają przez shadow DOM) i/lub skalować jednolicie:

subsovereign-paywall { --ss-paywall-max-width: 900px; transform: scale(1.4); }

Przyznawanie zakupu: ten SDK nie zawiera klientskiego wywołania validate…. Dopełnij płatności za pomocą swojego dostawcy, przyznaj dostęp po stronie serwera — Twój backend wywołuje Twój serwer SubSovereign lub podpisany mostek rozliczeń własnych (POST /entitlements/external) — a następnie ponownie sprawdź:

const again = await SubSovereign.checkEntitlements();
if (again.hasAccess) unlock();

Flagi funkcjonalne

Wdrażaj funkcje z poziomu serwera bez konieczności wdrażania. Działa zamknięcie awaryjne: w przypadku błędu sieci otrzymasz {}, więc każda flaga będzie traktowana jako wyłączona.

const flags = await SubSovereign.getFeatureFlags(); // { newPlayer: true, ... }
if (flags.newPlayer) showNewPlayer();

Atrybucja odpowiedzi AI (GEO)

Jeśli korzystasz z funkcji Acquisition/GEO, przechwyć źródło odwiedzających — odnośnik AI istnieje tylko na stronie docelowej, a identyfikator użytkownika pojawia się dopiero po rejestracji, dlatego jest to proces dwuetapowy: zapisanie i wysłanie:

import { ssCaptureLanding } from '@subsovereign/web';

// On every page of your marketing site, ONCE THE VISITOR HAS ACCEPTED YOUR CONSENT BANNER:
onConsentAccepted(() => ssCaptureLanding());

// …later, the moment the user signs up / signs in, after SubSovereign.configure():
await SubSovereign.recordAttributionTouch();

SDK nie zapisuje niczego na urządzeniu odwiedzającego do momentu wywołania ssCaptureLanding(). Importowanie pakietu niczego nie zapisuje. Zapisywane dane (odnośnik + tagi UTM) są danymi osobowymi zgodnie z RODO i przechowywaniem zgodnie z ePrivacy, dlatego kiedy je przechwycić, to decyzja o zgodzie, a nie nasza — wywołaj je z obsługi akceptacji Twojego banera. Bez przechwycenia recordAttributionTouch() raportuje jedynie to, co widzi strona rejestracji — tagi UTM z adresu URL i ewentualny odnośnik, jeśli nie pochodzi z Twojej witryny — dlatego AI lub wyszukiwarka, która odesłała użytkownika wcześniej, nie zostanie przypisana. To koszt braku przechwycenia i to wybór odwiedzającego.

recordAttributionTouch() wysyła pierwsze zapisane lądowanie (jest ważniejsze niż bieżąca strona), czyści zapis tylko po udanym wysłaniu, aby późniejsze logowanie mogło ponowić próbę, i nigdy nie zgłasza wyjątku. Jeśli strony docelowe nie mogą wywołać configure() (statyczna strona marketingowa bez użytkownika), ssFlushAttribution(userId, { apiUrl, apiKey }) wykonuje to samo wysłanie z jawnymi danymi uwierzytelniającymi — lub ustaw window.SS_API_URL i window.SS_API_KEY.

Pochodzenie Twojej witryny musi być na liście ALLOWED_ORIGINS serwera, w przeciwnym razie przeglądarka milcząco nic nie zgłosi.

Prywatność (RODO i CCPA)

await SubSovereign.recordConsent({ purpose: 'analytics', granted: true });

await SubSovereign.requestErasure();               // "forget me" — GDPR Art. 17
const myData = await SubSovereign.exportMyData();  // data export — GDPR Art. 20
await SubSovereign.setDoNotSell(true);             // CCPA "Do Not Sell" / GPC signal

Trzy wywołania dotyczące prywatności zgłaszają wyjątek w przypadku niepowodzenia (ApiError, z .status). Użytkownik korzystający z przysługującego mu prawa musi zostać poinformowany, gdy operacja nie powiodła się — złap błąd i poinformuj o tym; nigdy nie pokazuj milczącego sukcesu. Rekordy rozliczeniowe są przechowywane przez serwer zgodnie z art. 17 ust. 3 lit. b RODO i anonimizowane.

Przycisk wycofania z UE (Paszport Zgodności)

<subsovereign-withdrawal subscription-id="SUB_ID" appearance="auto"></subsovereign-withdrawal>

Wyraźnie oznaczony przycisk → pojedyncze potwierdzenie → idempotentne wysłanie → potwierdzenie, zgodnie z Dyrektywą (UE) 2023/2673. W przypadku interfejsów niestandardowych: SubSovereign.withdraw(subscriptionId, opts) i SubSovereign.getWithdrawalConfig().

Wygląd — light, dark lub auto (domyślnie), i tylko te wartości. Dialog samodzielnie maluje swoją kartę i tekst, dzięki czemu jest czytelny na każdej stronie hosta; auto stosuje się do ustawień przeglądarki odwiedzającego (prefers-color-scheme), a atrybut można zmienić w dowolnym momencie — karta jest ponownie malowana. Celowo nie ma możliwości przekazania koloru: jest to obowiązkowe powiadomienie, a sformułowania i kolory są ustalone, aby były czytelne dla każdego klienta każdego najemcy. Słowa pochodzą z Twojego serwera w języku klienta (locale w configure()); przy starszym serwerze następuje zapasowe tłumaczenie na angielski zamiast pozostawienia pustego pola.

Element emituje zdarzenia withdrawal-shown, withdrawal-submitted (szczegóły: potwierdzenie) oraz withdrawal-error (szczegóły: { reason, status? }) dla Twojej analityki. Jeśli zapomnisz o subscription-id, klient zobaczy przetłumaczony komunikat o błędzie, a Ty otrzymasz błąd w konsoli i zdarzenie withdrawal-error. Jeśli element nie może załadować ustawień (zły klucz, zły appId, serwer odmawia dostępu do pochodzenia tej strony), klient nadal otrzyma przycisk — po angielsku — a Ty otrzymasz console.warn z prawdopodobną przyczyną oraz zdarzenie withdrawal-error z reason: 'config-unavailable' i, jeśli istnieje, kodem HTTP status (odmowa pochodzenia lub błędny adres URL nie posiadają statusu). Nasłuchuj tego zdarzenia we wszystkich środowiskach: to dzięki niemu dowiesz się, że klienci niemieckojęzyczni widzą angielski. Zauważ, że zdarzenie to wyzwalane jest podczas ładowania, przed jakąkolwiek interakcją użytkownika — nie traktuj go jako nieudanego anulowania. Błąd konfiguracji nigdy nie jest ukryty dla developera i nigdy nie jest widoczny dla klienta.

Szybki przegląd

Chcesz… Użyj
Skonfigurować SDK SubSovereign.configure(config)
Zobaczyć, co użytkownik odblokował await checkEntitlements(){ hasAccess, … } (zgłasza wyjątek w przypadku niepowodzenia)
Proste zabezpieczenie (zamknięcie awaryjne) await hasAccess('pro')boolean
Załadować + wyświetlić bramę płatności pw.config = await getPaywallConfig() + zdarzenie select-product
Dopasować rozmiar bramy --ss-paywall-max-width · transform: scale(…)
Przyznać dostęp po zakupie po stronie serwera (Twój backend lub mostek rozliczeń własnych), a następnie ponownie sprawdź
Flagi funkcjonalne (zamknięcie awaryjne) await getFeatureFlags(){ [flag]: boolean }
Atrybucja GEO ssCaptureLanding() po zgodzie · recordAttributionTouch() po identyfikacji
Zarejestrować zgodę await recordConsent({ purpose, granted })
RODO / CCPA (zgłaszanie wyjątku w przypadku niepowodzenia) requestErasure() · exportMyData() · setDoNotSell(bool)
Wycofanie z UE <subsovereign-withdrawal subscription-id="…" appearance="light|dark|auto"> · withdraw()

Następne kroki