@monetize.software/sdk 3.0.0-alpha.2 → 3.0.0-alpha.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -13
- package/dist/chunks/PaywallUI-BJKIG_oT.js +3555 -0
- package/dist/chunks/PaywallUI-BJKIG_oT.js.map +1 -0
- package/dist/chunks/PaywallUI-C2aGYQ7I.js +26 -0
- package/dist/chunks/PaywallUI-C2aGYQ7I.js.map +1 -0
- package/dist/chunks/ar-OnxZkqWR.js +2 -0
- package/dist/chunks/ar-OnxZkqWR.js.map +1 -0
- package/dist/chunks/ar-rSKgwKvp.js +129 -0
- package/dist/chunks/ar-rSKgwKvp.js.map +1 -0
- package/dist/chunks/cs-Cb2KZ70r.js +2 -0
- package/dist/chunks/cs-Cb2KZ70r.js.map +1 -0
- package/dist/chunks/cs-DIWkcge_.js +125 -0
- package/dist/chunks/cs-DIWkcge_.js.map +1 -0
- package/dist/chunks/da-DdMW98j3.js +125 -0
- package/dist/chunks/da-DdMW98j3.js.map +1 -0
- package/dist/chunks/da-DyQC12xy.js +2 -0
- package/dist/chunks/da-DyQC12xy.js.map +1 -0
- package/dist/chunks/de-CWM13wnK.js +2 -0
- package/dist/chunks/de-CWM13wnK.js.map +1 -0
- package/dist/chunks/de-D1bSmD_-.js +144 -0
- package/dist/chunks/de-D1bSmD_-.js.map +1 -0
- package/dist/chunks/el-BtKuORsc.js +2 -0
- package/dist/chunks/el-BtKuORsc.js.map +1 -0
- package/dist/chunks/el-C4LtWpfP.js +129 -0
- package/dist/chunks/el-C4LtWpfP.js.map +1 -0
- package/dist/chunks/es-Bhx7w85J.js +144 -0
- package/dist/chunks/es-Bhx7w85J.js.map +1 -0
- package/dist/chunks/es-qLcKnBft.js +2 -0
- package/dist/chunks/es-qLcKnBft.js.map +1 -0
- package/dist/chunks/fi-C34Oc6rg.js +125 -0
- package/dist/chunks/fi-C34Oc6rg.js.map +1 -0
- package/dist/chunks/fi-kGtbK51C.js +2 -0
- package/dist/chunks/fi-kGtbK51C.js.map +1 -0
- package/dist/chunks/fr-BrWtqej3.js +144 -0
- package/dist/chunks/fr-BrWtqej3.js.map +1 -0
- package/dist/chunks/fr-CScwFVNj.js +2 -0
- package/dist/chunks/fr-CScwFVNj.js.map +1 -0
- package/dist/chunks/he-Byr2r07x.js +129 -0
- package/dist/chunks/he-Byr2r07x.js.map +1 -0
- package/dist/chunks/he-ChFVbP_S.js +2 -0
- package/dist/chunks/he-ChFVbP_S.js.map +1 -0
- package/dist/chunks/hi-BIswPYL2.js +2 -0
- package/dist/chunks/hi-BIswPYL2.js.map +1 -0
- package/dist/chunks/hi-CABVgpKU.js +129 -0
- package/dist/chunks/hi-CABVgpKU.js.map +1 -0
- package/dist/chunks/hu-CSQ9avfJ.js +125 -0
- package/dist/chunks/hu-CSQ9avfJ.js.map +1 -0
- package/dist/chunks/hu-CT_jwL0k.js +2 -0
- package/dist/chunks/hu-CT_jwL0k.js.map +1 -0
- package/dist/chunks/id-2lYf7ogC.js +2 -0
- package/dist/chunks/id-2lYf7ogC.js.map +1 -0
- package/dist/chunks/id-BJ5w6RSU.js +125 -0
- package/dist/chunks/id-BJ5w6RSU.js.map +1 -0
- package/dist/chunks/index-CLB1AgLg.js +2074 -0
- package/dist/chunks/index-CLB1AgLg.js.map +1 -0
- package/dist/chunks/index-CzDSBl4d.js +2 -0
- package/dist/chunks/index-CzDSBl4d.js.map +1 -0
- package/dist/chunks/it-CEMhCvXU.js +2 -0
- package/dist/chunks/it-CEMhCvXU.js.map +1 -0
- package/dist/chunks/it-Df8ChmTK.js +144 -0
- package/dist/chunks/it-Df8ChmTK.js.map +1 -0
- package/dist/chunks/ja-CkpO3n78.js +2 -0
- package/dist/chunks/ja-CkpO3n78.js.map +1 -0
- package/dist/chunks/ja-a53E5b2s.js +148 -0
- package/dist/chunks/ja-a53E5b2s.js.map +1 -0
- package/dist/chunks/ko-AZ8GrmXu.js +148 -0
- package/dist/chunks/ko-AZ8GrmXu.js.map +1 -0
- package/dist/chunks/ko-BKdzk0jX.js +2 -0
- package/dist/chunks/ko-BKdzk0jX.js.map +1 -0
- package/dist/chunks/nl-Bek7IiHL.js +2 -0
- package/dist/chunks/nl-Bek7IiHL.js.map +1 -0
- package/dist/chunks/nl-sF6ms5FU.js +144 -0
- package/dist/chunks/nl-sF6ms5FU.js.map +1 -0
- package/dist/chunks/no-BztcQKh8.js +2 -0
- package/dist/chunks/no-BztcQKh8.js.map +1 -0
- package/dist/chunks/no-DGf5PuW5.js +125 -0
- package/dist/chunks/no-DGf5PuW5.js.map +1 -0
- package/dist/chunks/pl-CMF2KerQ.js +2 -0
- package/dist/chunks/pl-CMF2KerQ.js.map +1 -0
- package/dist/chunks/pl-Dd-Ze6wn.js +125 -0
- package/dist/chunks/pl-Dd-Ze6wn.js.map +1 -0
- package/dist/chunks/pt-BL9X8Du2.js +144 -0
- package/dist/chunks/pt-BL9X8Du2.js.map +1 -0
- package/dist/chunks/pt-DF9cd_iW.js +2 -0
- package/dist/chunks/pt-DF9cd_iW.js.map +1 -0
- package/dist/chunks/ro-CGYmtR8q.js +125 -0
- package/dist/chunks/ro-CGYmtR8q.js.map +1 -0
- package/dist/chunks/ro-DpPc1UhJ.js +2 -0
- package/dist/chunks/ro-DpPc1UhJ.js.map +1 -0
- package/dist/chunks/ru-gt3-clOi.js +2 -0
- package/dist/chunks/ru-gt3-clOi.js.map +1 -0
- package/dist/chunks/ru-oPoQtUxk.js +147 -0
- package/dist/chunks/ru-oPoQtUxk.js.map +1 -0
- package/dist/chunks/sv-Cg7O9Uh3.js +2 -0
- package/dist/chunks/sv-Cg7O9Uh3.js.map +1 -0
- package/dist/chunks/sv-kXHP1Ct3.js +125 -0
- package/dist/chunks/sv-kXHP1Ct3.js.map +1 -0
- package/dist/chunks/th-DMcmb36d.js +129 -0
- package/dist/chunks/th-DMcmb36d.js.map +1 -0
- package/dist/chunks/th-pvtT9u-U.js +2 -0
- package/dist/chunks/th-pvtT9u-U.js.map +1 -0
- package/dist/chunks/tr-gAn3KCul.js +2 -0
- package/dist/chunks/tr-gAn3KCul.js.map +1 -0
- package/dist/chunks/tr-zjLbddlL.js +125 -0
- package/dist/chunks/tr-zjLbddlL.js.map +1 -0
- package/dist/chunks/uk-BYSiM14V.js +147 -0
- package/dist/chunks/uk-BYSiM14V.js.map +1 -0
- package/dist/chunks/uk-HIaOETe4.js +2 -0
- package/dist/chunks/uk-HIaOETe4.js.map +1 -0
- package/dist/chunks/vi-B7DVCjxx.js +2 -0
- package/dist/chunks/vi-B7DVCjxx.js.map +1 -0
- package/dist/chunks/vi-FbVRwy9D.js +125 -0
- package/dist/chunks/vi-FbVRwy9D.js.map +1 -0
- package/dist/chunks/zh-007yK7rl.js +2 -0
- package/dist/chunks/zh-007yK7rl.js.map +1 -0
- package/dist/chunks/zh-Cv0Yw4qR.js +148 -0
- package/dist/chunks/zh-Cv0Yw4qR.js.map +1 -0
- package/dist/core.cjs +1 -1
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.ts +260 -26
- package/dist/core.js +17 -1899
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +411 -45
- package/dist/index.js +17 -13
- package/dist/ui.cjs +1 -1
- package/dist/ui.d.ts +376 -44
- package/dist/ui.js +1 -1
- package/package.json +32 -31
- package/dist/chunks/PaywallUI-CRTEPjJm.js +0 -2229
- package/dist/chunks/PaywallUI-CRTEPjJm.js.map +0 -1
- package/dist/chunks/PaywallUI-CbbcfXXZ.js +0 -26
- package/dist/chunks/PaywallUI-CbbcfXXZ.js.map +0 -1
package/dist/ui.d.ts
CHANGED
|
@@ -46,7 +46,9 @@ declare class ApiGatewayClient {
|
|
|
46
46
|
|
|
47
47
|
declare interface ApiGatewayClientOptions {
|
|
48
48
|
paywallId: string;
|
|
49
|
-
|
|
49
|
+
/** Origin серверного API SDK — обязательное поле, тот же `custom_domain`, что
|
|
50
|
+
* у BillingClient/AuthClient. См. {@link BillingClientOptions.apiOrigin}. */
|
|
51
|
+
apiOrigin: string;
|
|
50
52
|
/** AuthClient — Bearer добавляется автоматически. На 401 от gateway клиент
|
|
51
53
|
* не делает refresh: AuthClient уже сделал lazy-refresh в getAccessToken. */
|
|
52
54
|
auth?: AuthClient;
|
|
@@ -66,7 +68,28 @@ declare interface ApiGatewayClientOptions {
|
|
|
66
68
|
onQuotaExceeded?: (err: QuotaExceededError) => void;
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
|
|
71
|
+
/** Дискриминатор для `onAuthChange`. Позволяет listener'у отличать первый
|
|
72
|
+
* callback (восстановление сессии из storage / синтетический snapshot для
|
|
73
|
+
* свежей подписки) от реальных переходов. Конвенция Supabase, минус события,
|
|
74
|
+
* которых у нас нет (MFA, EMAIL_VERIFIED).
|
|
75
|
+
*
|
|
76
|
+
* - INITIAL_SESSION — единственный гарантированный первый callback на каждую
|
|
77
|
+
* подписку. Дёргается через microtask после resolve hydrated-promise, даже
|
|
78
|
+
* если session=null. Listener'ы по этому event'у НЕ должны делать побочные
|
|
79
|
+
* эффекты типа force-refetch — это просто доставка стартового state'а.
|
|
80
|
+
* - SIGNED_IN — свежий вход: email/OAuth/anon, или появление session в этом
|
|
81
|
+
* инстансе из другого контекста (storage.watch), когда раньше был null.
|
|
82
|
+
* - SIGNED_OUT — signOut, revokeAllSessions, 401 на refresh, удаление session
|
|
83
|
+
* из другого контекста.
|
|
84
|
+
* - TOKEN_REFRESHED — тот же user, обновлённые токены: refresh(), либо
|
|
85
|
+
* storage.watch когда содержимое сменилось но user.id остался.
|
|
86
|
+
* - USER_UPDATED — изменился user.email / user.user_metadata (updatePassword,
|
|
87
|
+
* upgradeAnonymousToEmail) при том же user.id.
|
|
88
|
+
* - PASSWORD_RECOVERY — verifyOtp(type='recovery'). Listener знает, что надо
|
|
89
|
+
* показать «set new password» UI вместо обычного post-login flow'а. */
|
|
90
|
+
declare type AuthChangeEvent = 'INITIAL_SESSION' | 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED' | 'USER_UPDATED' | 'PASSWORD_RECOVERY';
|
|
91
|
+
|
|
92
|
+
declare type AuthChangeListener = (event: AuthChangeEvent, session: AuthSession | null) => void;
|
|
70
93
|
|
|
71
94
|
declare class AuthClient {
|
|
72
95
|
readonly paywallId: string;
|
|
@@ -225,10 +248,8 @@ declare class AuthClient {
|
|
|
225
248
|
* когда сервер начнёт возвращать challenge_required в риск-сценариях,
|
|
226
249
|
* SDK сможет передать proof-of-something обратно без breaking change.
|
|
227
250
|
*
|
|
228
|
-
* `
|
|
229
|
-
* нового anon-юзера). Используется в switch-account flow.
|
|
230
|
-
* остаётся `forceCaptcha`, хотя капчи там больше нет — менять имя ломает
|
|
231
|
-
* host-сигнатуру; смысл «принудительно новая anon-сессия» сохранён.
|
|
251
|
+
* `forceNewAnon: true` пропускает шаги 1-2 и сразу делает /signin (создаёт
|
|
252
|
+
* нового anon-юзера). Используется в switch-account flow.
|
|
232
253
|
*
|
|
233
254
|
* Параллельные вызовы дедуплицируются через `inflightAnonSignin` — два
|
|
234
255
|
* click'а на «Войти как гость» не создадут двух anon-юзеров (два /signup =
|
|
@@ -237,7 +258,7 @@ declare class AuthClient {
|
|
|
237
258
|
signInAnonymously(input?: {
|
|
238
259
|
captchaToken?: string;
|
|
239
260
|
userMeta?: Record<string, string>;
|
|
240
|
-
|
|
261
|
+
forceNewAnon?: boolean;
|
|
241
262
|
}): Promise<AuthSession>;
|
|
242
263
|
/**
|
|
243
264
|
* Внутренний resume — пробует /auth/refresh с сохранённым anon refresh_token.
|
|
@@ -385,8 +406,19 @@ declare class AuthClient {
|
|
|
385
406
|
}): Promise<void>;
|
|
386
407
|
/**
|
|
387
408
|
* Подписка на изменения session: signin/signup/refresh/signOut/expired-401.
|
|
388
|
-
*
|
|
389
|
-
*
|
|
409
|
+
*
|
|
410
|
+
* Гарантированный контракт: ПЕРВЫЙ callback каждому subscriber'у — всегда
|
|
411
|
+
* `event = 'INITIAL_SESSION'`, дёргается асинхронно после resolve hydrate'а
|
|
412
|
+
* (даже если session=null — listener получает explicit «нет сессии», а не
|
|
413
|
+
* молчание). Все последующие callback'и — реальные переходы с конкретным
|
|
414
|
+
* event'ом (SIGNED_IN / SIGNED_OUT / TOKEN_REFRESHED / USER_UPDATED /
|
|
415
|
+
* PASSWORD_RECOVERY).
|
|
416
|
+
*
|
|
417
|
+
* Это позволяет listener'у безопасно делать «only on real signin» побочные
|
|
418
|
+
* эффекты (force refetch balances и т.п.) через `event === 'SIGNED_IN'`,
|
|
419
|
+
* не путая их с восстановлением из storage.
|
|
420
|
+
*
|
|
421
|
+
* Возвращает unsubscribe.
|
|
390
422
|
*/
|
|
391
423
|
onAuthChange(cb: AuthChangeListener): () => void;
|
|
392
424
|
private isFresh;
|
|
@@ -412,6 +444,18 @@ declare class AuthClient {
|
|
|
412
444
|
private readAnonRefreshToken;
|
|
413
445
|
private writeAnonRefreshToken;
|
|
414
446
|
private clearAnonRefreshToken;
|
|
447
|
+
/**
|
|
448
|
+
* Last-used auth method + email — для UI бейджа "Last used" и pre-fill'а
|
|
449
|
+
* email-инпута. Storage paywall-scoped, поэтому переключение между
|
|
450
|
+
* пейволами на одном host'е не пересекает данные. Чтение всегда возвращает
|
|
451
|
+
* объект — отсутствующие поля = null. */
|
|
452
|
+
getLastLogin(): Promise<LastLogin | null>;
|
|
453
|
+
/** Запись method и email атомарно (для email/password flows — оба известны
|
|
454
|
+
* на момент signin/signup'а). OAuth-flows используют раздельные
|
|
455
|
+
* recordLastLoginMethod (до popup) и recordLastLoginEmail (после exchange). */
|
|
456
|
+
private recordLastLogin;
|
|
457
|
+
private recordLastLoginMethod;
|
|
458
|
+
private recordLastLoginEmail;
|
|
415
459
|
/**
|
|
416
460
|
* Читает stable visitor_id из storage если он там уже есть. НЕ генерит:
|
|
417
461
|
* AuthClient может быть инстанцирован раньше BillingClient, а синтетический
|
|
@@ -424,7 +468,9 @@ declare class AuthClient {
|
|
|
424
468
|
|
|
425
469
|
declare interface AuthClientOptions {
|
|
426
470
|
paywallId: string;
|
|
427
|
-
|
|
471
|
+
/** Origin серверного API SDK — обязательное поле, тот же `custom_domain`, что
|
|
472
|
+
* у BillingClient. См. {@link BillingClientOptions.apiOrigin}. */
|
|
473
|
+
apiOrigin: string;
|
|
428
474
|
storage?: StorageAdapter;
|
|
429
475
|
fetch?: typeof fetch;
|
|
430
476
|
openPopup?: (url: string, name: string) => Window | null;
|
|
@@ -577,6 +623,13 @@ declare class BillingClient {
|
|
|
577
623
|
}): Promise<PaywallPrice[]>;
|
|
578
624
|
/** Sync-снимок цен из последнего bootstrap'а. null = ещё не загружали. */
|
|
579
625
|
getCachedPrices(): PaywallPrice[] | null;
|
|
626
|
+
/** Sync-снимок офферов из последнего bootstrap'а. null = bootstrap ещё не
|
|
627
|
+
* загружали, пустой массив = бэк отдал пейвол без офферов. Бэк уже
|
|
628
|
+
* применил серверный таргетинг (target_countries / target_emails /
|
|
629
|
+
* targeting_mode из offer_settings) — наружу выезжает только то, что
|
|
630
|
+
* применимо к текущему юзеру. Клиентская сторона остаётся ответственной
|
|
631
|
+
* за price_id-matching и countdown (см. core/offer.ts → resolveOffer). */
|
|
632
|
+
getCachedOffers(): PaywallOffer[] | null;
|
|
580
633
|
/**
|
|
581
634
|
* Снимок того, какой язык SDK сейчас считает «языком юзера». Полезно для
|
|
582
635
|
* синхронизации i18n хоста с тем, что фактически показывает пейвол — чтобы
|
|
@@ -703,6 +756,17 @@ declare class BillingClient {
|
|
|
703
756
|
errorUrl?: string;
|
|
704
757
|
shopUrl?: string;
|
|
705
758
|
trialDays?: number;
|
|
759
|
+
/** Активный offer для этой цены — резолвится host'ом через
|
|
760
|
+
* `paywall.getOfferForPrice(priceId)?.offer.id` или
|
|
761
|
+
* `findApplicableOffer(client.getCachedOffers(), priceId)?.id`. Без
|
|
762
|
+
* явной передачи бэк сделает auto-resolve по email — но только для
|
|
763
|
+
* end_date-офферов. duration_minutes-офферы тикают в clientStorage и
|
|
764
|
+
* сервер их не видит: для них offerId ОБЯЗАН прийти от клиента, иначе
|
|
765
|
+
* скидка не применится на чекауте, хотя UI её показывал.
|
|
766
|
+
*
|
|
767
|
+
* Передавать offer-id всегда безопасно — бэк сам проверит applicable
|
|
768
|
+
* ли offer к этому юзеру (страна/email/режим) и игнорирует если нет. */
|
|
769
|
+
offerId?: string;
|
|
706
770
|
/**
|
|
707
771
|
* Stage 1 защиты от дубликатов покупок. Идемпотентный ключ запроса
|
|
708
772
|
* (UUID). Повторный вызов с тем же ключом вернёт тот же checkout-URL
|
|
@@ -729,7 +793,9 @@ declare class BillingClient {
|
|
|
729
793
|
* инвойсы). Опен-флоу управляется host'ом:
|
|
730
794
|
*
|
|
731
795
|
* ```ts
|
|
732
|
-
* const { url } = await billing.getCustomerPortalUrl(
|
|
796
|
+
* const { url } = await billing.getCustomerPortalUrl({
|
|
797
|
+
* returnUrl: 'https://your-app.com/account'
|
|
798
|
+
* });
|
|
733
799
|
* window.open(url, '_blank');
|
|
734
800
|
* ```
|
|
735
801
|
*
|
|
@@ -741,6 +807,14 @@ declare class BillingClient {
|
|
|
741
807
|
*/
|
|
742
808
|
getCustomerPortalUrl(opts?: {
|
|
743
809
|
signal?: AbortSignal;
|
|
810
|
+
/** URL для return-button у провайдера (Stripe «Return to ...», Paddle
|
|
811
|
+
* и Chargebee redirect_url'ы). Передавай туда страницу-аккаунт твоего
|
|
812
|
+
* app'а — `https://your-app.com/account`. Без явного returnUrl бэк
|
|
813
|
+
* применяет fallback в порядке: `paywall_settings.shop_url` →
|
|
814
|
+
* custom_domain пейвола → NEXT_PUBLIC_ONLINE_ORIGIN (последнее — это
|
|
815
|
+
* страница в самом online-сервисе, годится только для legacy
|
|
816
|
+
* v2-iframe-флоу). */
|
|
817
|
+
returnUrl?: string;
|
|
744
818
|
}): Promise<{
|
|
745
819
|
url: string;
|
|
746
820
|
}>;
|
|
@@ -751,21 +825,31 @@ declare class BillingClient {
|
|
|
751
825
|
* `/api/v1/paywall/[id]/user` без unstable_cache, потому что list для UI
|
|
752
826
|
* должен быть свежим после cancel-а.
|
|
753
827
|
*
|
|
754
|
-
* Auth
|
|
755
|
-
*
|
|
828
|
+
* Auth (два пути):
|
|
829
|
+
* - Bearer (через AuthClient) — user.id резолвится из сессии, identity
|
|
830
|
+
* в query игнорируется.
|
|
831
|
+
* - `apiKey` + `identity.email`/`identity.userId` — server-SDK путь для
|
|
832
|
+
* интеграций со своей авторизацией. Бэк проверяет, что identity линкована
|
|
833
|
+
* к этому пейволу (защита от cross-paywall lookup).
|
|
834
|
+
* Без auth и без apiKey+identity — `identity_required`.
|
|
756
835
|
*/
|
|
757
836
|
listPurchases(opts?: {
|
|
758
837
|
signal?: AbortSignal;
|
|
759
838
|
}): Promise<PaywallPurchaseDetailed[]>;
|
|
760
839
|
/**
|
|
761
|
-
* Отменить подписку. Бэк
|
|
762
|
-
*
|
|
763
|
-
*
|
|
840
|
+
* Отменить подписку. Бэк проверит, что subscription принадлежит юзеру
|
|
841
|
+
* (Bearer-путь — из сессии; apiKey-путь — из identity), и сделает cancel у
|
|
842
|
+
* acquiring'а (Stripe/Paddle/Chargebee/Overpay). По умолчанию cancel в
|
|
843
|
+
* конце текущего периода — юзер сохраняет access до renewal date'ы.
|
|
764
844
|
*
|
|
765
|
-
* `reason` обязательна (валидация на бэке).
|
|
766
|
-
* причин в host-UI, как в legacy customer portal'е.
|
|
845
|
+
* `reason` обязательна (валидация на бэке).
|
|
767
846
|
*
|
|
768
|
-
* Auth
|
|
847
|
+
* Auth (два пути):
|
|
848
|
+
* - Bearer (через AuthClient) — стандартный путь для UI customer-portal'a.
|
|
849
|
+
* - `apiKey` + `identity.email`/`identity.userId` — для self-service UI на
|
|
850
|
+
* бэке клиента со своей авторизацией. Бэк дополнительно фильтрует
|
|
851
|
+
* subscription по paywall_id, чтобы owner пейвола A не отменил подписку
|
|
852
|
+
* пейвола B.
|
|
769
853
|
*/
|
|
770
854
|
cancelSubscription(params: {
|
|
771
855
|
subscriptionId: string;
|
|
@@ -802,7 +886,15 @@ declare class BillingClient {
|
|
|
802
886
|
|
|
803
887
|
declare interface BillingClientOptions {
|
|
804
888
|
paywallId: string;
|
|
805
|
-
|
|
889
|
+
/**
|
|
890
|
+
* Origin серверного API SDK — обязательное поле. Должно совпадать с
|
|
891
|
+
* `custom_domain`, заданным для пейвола в платформе (модерация привязывает
|
|
892
|
+
* домен к paywall_id). SDK сверяет это значение с `bootstrap.settings.custom_domain`
|
|
893
|
+
* на первом ответе и кидает `invalid_config` при расхождении — защита от
|
|
894
|
+
* опечаток интегратора. Промежуточный `appbox.space` в новом SDK НЕ
|
|
895
|
+
* используется (это только для legacy v2).
|
|
896
|
+
*/
|
|
897
|
+
apiOrigin: string;
|
|
806
898
|
identity?: Identity;
|
|
807
899
|
storage?: StorageAdapter;
|
|
808
900
|
capabilities?: string[];
|
|
@@ -848,6 +940,10 @@ export declare interface BlockContext {
|
|
|
848
940
|
/** Текущая auth-session (snapshot из AuthClient). null = разлогинен. PaywallRoot
|
|
849
941
|
* подписан на onAuthChange и пробрасывает свежий snapshot сюда. */
|
|
850
942
|
authSession: AuthSession | null;
|
|
943
|
+
/** Стартовый mode для AuthPanel — переопределяет дефолт 'signin'.
|
|
944
|
+
* Выставляется AuthGate'ом когда host вызвал openSignup()/openSignin().
|
|
945
|
+
* Остальные блоки игнорируют. */
|
|
946
|
+
initialAuthMode?: 'signin' | 'signup';
|
|
851
947
|
}
|
|
852
948
|
|
|
853
949
|
export declare interface BlockProps<B extends LayoutBlock = LayoutBlock> {
|
|
@@ -877,6 +973,18 @@ declare interface Identity {
|
|
|
877
973
|
anonymousId?: string;
|
|
878
974
|
}
|
|
879
975
|
|
|
976
|
+
declare interface LastLogin {
|
|
977
|
+
method: LastLoginMethod;
|
|
978
|
+
email: string | null;
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
/** Метод, которым юзер залогинился в последний раз на этом пейволе.
|
|
982
|
+
* Хранится per-paywall в storage и используется UI чтобы:
|
|
983
|
+
* - предзаполнить email-инпут last-known email'ом;
|
|
984
|
+
* - подсветить ту же OAuth-кнопку / email-форму бейджем "Last used".
|
|
985
|
+
* `email` — email/password forms (signin или signup → confirm). */
|
|
986
|
+
declare type LastLoginMethod = OAuthProvider | 'email';
|
|
987
|
+
|
|
880
988
|
declare interface Layout {
|
|
881
989
|
type: 'modal';
|
|
882
990
|
blocks: LayoutBlock[];
|
|
@@ -892,9 +1000,13 @@ declare type LayoutBlock = {
|
|
|
892
1000
|
} | {
|
|
893
1001
|
type: 'price_grid';
|
|
894
1002
|
priceIds?: string[];
|
|
895
|
-
/** Раскладка карточек
|
|
896
|
-
* `
|
|
897
|
-
|
|
1003
|
+
/** Раскладка карточек цен:
|
|
1004
|
+
* - `vertical` (default) — стек карточек сверху вниз;
|
|
1005
|
+
* - `compact` — компактный список (одна строка на цену, без карточки,
|
|
1006
|
+
* с разделителем); v2-аналог `view: 'telegram'`;
|
|
1007
|
+
* - `horizontal` — несколько карточек рядом в ряд; v2-only с момента
|
|
1008
|
+
* SDK 3.0 (legacy не показывает выбор этой опции в админке). */
|
|
1009
|
+
view?: 'vertical' | 'compact' | 'horizontal';
|
|
898
1010
|
/** ID цены, которая помечается лейблом «популярный план». v2-аналог
|
|
899
1011
|
* пары `price_label_id` + `price_label`. */
|
|
900
1012
|
popular_price_id?: string;
|
|
@@ -903,7 +1015,10 @@ declare type LayoutBlock = {
|
|
|
903
1015
|
popular_label?: string;
|
|
904
1016
|
} | {
|
|
905
1017
|
type: 'cta_button';
|
|
906
|
-
|
|
1018
|
+
/** Текст на кнопке. Если не задан — рендерер сам подберёт по
|
|
1019
|
+
* selected price'у и `trial_days`: "Start N-Day Free Trial",
|
|
1020
|
+
* "Get Lifetime Access", "Get Monthly Plan" и т.п. */
|
|
1021
|
+
label?: string;
|
|
907
1022
|
action: 'checkout' | 'close';
|
|
908
1023
|
priceId?: string;
|
|
909
1024
|
} | {
|
|
@@ -922,8 +1037,23 @@ declare type LayoutBlock = {
|
|
|
922
1037
|
/** Скрывать панель, если юзер уже залогинен. По умолчанию true.
|
|
923
1038
|
* false — показываем "Signed in as ... [Sign out]" даже после логина. */
|
|
924
1039
|
hide_when_authenticated?: boolean;
|
|
925
|
-
/**
|
|
1040
|
+
/** Кастомный заголовок над формой. Если задан — отображается вместо
|
|
1041
|
+
* дефолтного (определяется по mode'у — "Welcome back!" / "Welcome!" /
|
|
1042
|
+
* "Forgot password?" / ...). Без `submit_label` также используется как
|
|
1043
|
+
* submit-лейбл для signin (например `heading="Restore Purchases"` →
|
|
1044
|
+
* submit тоже "Restore Purchases"). Длинные heading (типа "Войдите,
|
|
1045
|
+
* чтобы продолжить покупку") в кнопку влезают плохо — задай
|
|
1046
|
+
* `submit_label` отдельно. */
|
|
926
1047
|
heading?: string;
|
|
1048
|
+
/** Подпись под заголовком. Если опущен — подставляется default-текст
|
|
1049
|
+
* для текущего mode'а. Передай пустую строку чтобы скрыть подпись. */
|
|
1050
|
+
subheading?: string;
|
|
1051
|
+
/** Явный текст submit-кнопки. Имеет приоритет над heading-эхо. Нужен
|
|
1052
|
+
* для интентов с длинным descriptive heading'ом (preauth: "Войдите,
|
|
1053
|
+
* чтобы продолжить покупку" — кнопка только "Войти"). Для коротких
|
|
1054
|
+
* action-headings (restore: "Restore Purchases") опускай — эхо
|
|
1055
|
+
* даёт правильный UX. */
|
|
1056
|
+
submit_label?: string;
|
|
927
1057
|
} | {
|
|
928
1058
|
/** Список фич/преимуществ продукта. v2-аналог `features_list` + `features_view`.
|
|
929
1059
|
* До 5 элементов — рендерим как чек-лист с заголовком и описанием. */
|
|
@@ -947,6 +1077,35 @@ declare type LayoutBlock = {
|
|
|
947
1077
|
desc: string;
|
|
948
1078
|
count: number;
|
|
949
1079
|
}>;
|
|
1080
|
+
} | {
|
|
1081
|
+
/** Money-back guarantee badge под cta_button: иконка + жирный заголовок +
|
|
1082
|
+
* пояснение мелким шрифтом + bottom divider, который визуально стыкуется
|
|
1083
|
+
* с current_session ниже. v2-аналог inline-блока в `PaywallPricing`. */
|
|
1084
|
+
type: 'guarantee_badge';
|
|
1085
|
+
/** Заголовок жирным. По умолчанию "100% Money-Back Guarantee". */
|
|
1086
|
+
title?: string;
|
|
1087
|
+
/** Подзаголовок мелким серым. По умолчанию
|
|
1088
|
+
* "Not satisfied? We'll refund you — no questions asked.". */
|
|
1089
|
+
subtitle?: string;
|
|
1090
|
+
/** Иконка слева от заголовка. По умолчанию `dollar_shield` —
|
|
1091
|
+
* зелёный shield с долларом (legacy-вид). `none` — без иконки. */
|
|
1092
|
+
icon?: 'dollar_shield' | 'none';
|
|
1093
|
+
} | {
|
|
1094
|
+
/** Urgency-баннер с countdown'ом до конца offer'а. Берёт первый offer
|
|
1095
|
+
* из `bootstrap.offers` с валидным `expires_at` или `duration_minutes`.
|
|
1096
|
+
* Авто-скрывается по истечении, чтобы не показывать "0d 0h 0m 0s".
|
|
1097
|
+
* Размещение — обычно первый блок в layout (над heading). */
|
|
1098
|
+
type: 'offer_banner';
|
|
1099
|
+
/** ID конкретного offer'а из bootstrap.offers. Если не задано — берётся
|
|
1100
|
+
* первый offer с активным таймером. */
|
|
1101
|
+
offer_id?: string;
|
|
1102
|
+
/** Текст слева от countdown'а. Если опущен — берётся `offer.label`,
|
|
1103
|
+
* иначе fallback "Limited-time offer". К нему дописывается процент:
|
|
1104
|
+
* "{title} {discount_percent}%" если discount задан. */
|
|
1105
|
+
title?: string;
|
|
1106
|
+
/** В превью админки — игнорировать expired-state, всё равно показывать
|
|
1107
|
+
* banner с нулями. Прод-режим — false (banner исчезает). */
|
|
1108
|
+
force?: boolean;
|
|
950
1109
|
};
|
|
951
1110
|
|
|
952
1111
|
/** Локализационные оверрайды для одного языка. Накатываются поверх дефолтного
|
|
@@ -1106,9 +1265,19 @@ declare interface PaywallEventPayloads {
|
|
|
1106
1265
|
/** User-state изменился (bootstrap snapshot, getUser refresh, watcher tick).
|
|
1107
1266
|
* Дёргается также сразу с last-known user после первой подписки. */
|
|
1108
1267
|
userChange: PaywallUser;
|
|
1109
|
-
/** Auth-session
|
|
1110
|
-
*
|
|
1111
|
-
|
|
1268
|
+
/** Auth-session изменилась. Payload содержит `event` (см. AuthChangeEvent —
|
|
1269
|
+
* INITIAL_SESSION / SIGNED_IN / SIGNED_OUT / TOKEN_REFRESHED / USER_UPDATED /
|
|
1270
|
+
* PASSWORD_RECOVERY) и `session` (null = разлогинен).
|
|
1271
|
+
*
|
|
1272
|
+
* Гарантированный контракт: первый callback каждому subscriber'у — всегда
|
|
1273
|
+
* INITIAL_SESSION с восстановленной из storage сессией (или null если нет).
|
|
1274
|
+
* Дальше — реальные переходы. Listener'у с побочными эффектами вроде
|
|
1275
|
+
* force-refetch balances ловить SIGNED_IN, а не любой truthy session,
|
|
1276
|
+
* иначе reload страницы будет триггерить лишний запрос. */
|
|
1277
|
+
authChange: {
|
|
1278
|
+
event: AuthChangeEvent;
|
|
1279
|
+
session: AuthSession | null;
|
|
1280
|
+
};
|
|
1112
1281
|
/** Триал заблокировал показ модалки. payload содержит свежий статус (после
|
|
1113
1282
|
* recordBlock). Для `mode: 'time'` — startedAt/expiresAt/remainingMs;
|
|
1114
1283
|
* для `mode: 'opens'` — remainingActions/totalActions. Хост может
|
|
@@ -1128,7 +1297,17 @@ declare interface PaywallEventPayloads {
|
|
|
1128
1297
|
declare interface PaywallOffer {
|
|
1129
1298
|
id: string;
|
|
1130
1299
|
discount_percent: number | null;
|
|
1300
|
+
/** Абсолютная expiration date (ISO 8601). Если задана — countdown отсчитывает
|
|
1301
|
+
* до этого момента, по истечении offer считается истёкшим. */
|
|
1131
1302
|
expires_at: string | null;
|
|
1303
|
+
/** Относительный таймер: сколько минут offer живёт **от первого просмотра
|
|
1304
|
+
* пейвола** данным юзером. Старт хранится в clientStorage под ключом
|
|
1305
|
+
* `pw-offer-{id}-start` и остаётся там **после** expiry — это
|
|
1306
|
+
* forever-marker, чтобы юзер не мог «фармить» offer (re-open пейвола
|
|
1307
|
+
* не запускает countdown заново). Используется, когда бэк хочет
|
|
1308
|
+
* показывать "remaining time" без жёсткой server-time, а считать
|
|
1309
|
+
* относительно сессии юзера. expires_at имеет приоритет если задано. */
|
|
1310
|
+
duration_minutes?: number | null;
|
|
1132
1311
|
price_id: string | null;
|
|
1133
1312
|
label?: string | null;
|
|
1134
1313
|
}
|
|
@@ -1178,6 +1357,14 @@ declare interface PaywallSettings {
|
|
|
1178
1357
|
brand_color?: string | null;
|
|
1179
1358
|
custom_css?: string | null;
|
|
1180
1359
|
locale_default?: string | null;
|
|
1360
|
+
/** Origin, на котором живёт бэк пейвола (тот же, что мерчант передаёт в
|
|
1361
|
+
* `BillingClientOptions.apiOrigin` при инициализации SDK). Бэк присылает
|
|
1362
|
+
* его на каждом bootstrap'е, SDK сверяет с init.apiOrigin — расхождение
|
|
1363
|
+
* даёт `invalid_config` (защита от опечатки интегратора). Без схемы:
|
|
1364
|
+
* "pay.your-domain.com" или "https://pay.your-domain.com" — оба валидны.
|
|
1365
|
+
* Для новых пейволов поле всегда заполнено (модерация требует custom_domain);
|
|
1366
|
+
* для legacy v2 может быть null/undefined. */
|
|
1367
|
+
custom_domain?: string | null;
|
|
1181
1368
|
runtime_mode?: 'client' | 'hybrid' | 'server' | 'client-native' | 'hybrid-native';
|
|
1182
1369
|
/** true, если эквайринг пейвола в test-mode — SDK рисует TEST MODE бейдж. */
|
|
1183
1370
|
is_test_mode?: boolean;
|
|
@@ -1234,12 +1421,25 @@ declare type PaywallStateListener = (state: PaywallStateSnapshot) => void;
|
|
|
1234
1421
|
* один call onState; повторы (`useSyncExternalStore`-friendly).
|
|
1235
1422
|
*/
|
|
1236
1423
|
export declare interface PaywallStateSnapshot {
|
|
1237
|
-
/** Модалка отрендерена и видна. False — closed (или ещё не открывалась).
|
|
1424
|
+
/** Модалка отрендерена и видна. False — closed (или ещё не открывалась).
|
|
1425
|
+
* Может быть false при `processing=true` — direct-checkout (paywall.checkout)
|
|
1426
|
+
* делает bootstrap + createCheckout headless до того, как решит надо ли
|
|
1427
|
+
* монтировать модалку. */
|
|
1238
1428
|
open: boolean;
|
|
1239
1429
|
/** Что показывается в модалке. null когда `open=false`. */
|
|
1240
|
-
view: 'loading' | 'error' | 'layout' | 'auth' | '
|
|
1430
|
+
view: 'loading' | 'error' | 'layout' | 'auth' | 'support' | 'awaiting_payment' | 'popup_blocked' | 'purchased' | null;
|
|
1241
1431
|
/** Заполнено только когда `view === 'error'`. */
|
|
1242
1432
|
error: PaywallError | null;
|
|
1433
|
+
/** SDK делает фоновую работу для `paywall.checkout(priceId)` — bootstrap,
|
|
1434
|
+
* visibility/trial-gates, createCheckout — до того, как реально нужна
|
|
1435
|
+
* UI-модалка. Хост на этой фазе может задизейблить свою кнопку и
|
|
1436
|
+
* показать спиннер прямо на ней, чтобы у юзера не было ощущения «клик
|
|
1437
|
+
* ничего не сделал». Сбрасывается в false сразу после mountAndShow
|
|
1438
|
+
* (модалка взяла на себя UI), либо после headless reject (already-paid,
|
|
1439
|
+
* ошибка createCheckout без модалки). Для `paywall.open()`-flow всегда
|
|
1440
|
+
* false: там модалка появляется мгновенно со своим LoadingView и
|
|
1441
|
+
* отдельный «processing» не нужен. */
|
|
1442
|
+
processing: boolean;
|
|
1243
1443
|
}
|
|
1244
1444
|
|
|
1245
1445
|
export declare class PaywallUI {
|
|
@@ -1274,6 +1474,10 @@ export declare class PaywallUI {
|
|
|
1274
1474
|
private lastVisibility;
|
|
1275
1475
|
/** Поведение open() при холодном bootstrap'е. См. PaywallUIOptions.mountThenLoad. */
|
|
1276
1476
|
private mountThenLoad;
|
|
1477
|
+
/** Inline-режим (live-preview редактора). См. PaywallUIOptions.inline. */
|
|
1478
|
+
private inline;
|
|
1479
|
+
/** Force-locale для I18nProvider. См. PaywallUIOptions.locale. */
|
|
1480
|
+
private forceLocale;
|
|
1277
1481
|
/** Текущий snapshot UI state-machine. Обновляется PaywallRoot'ом через
|
|
1278
1482
|
* `onState` prop; при close сбрасывается обратно в CLOSED_STATE. */
|
|
1279
1483
|
private currentState;
|
|
@@ -1307,6 +1511,15 @@ export declare class PaywallUI {
|
|
|
1307
1511
|
* почти всегда нежелательна.
|
|
1308
1512
|
*/
|
|
1309
1513
|
setBootstrap(partial: Partial<PaywallBootstrap>): void;
|
|
1514
|
+
/**
|
|
1515
|
+
* Сменить force-locale на лету — для live-preview редактора админки, когда
|
|
1516
|
+
* юзер переключает «Preview as user from <country>». Грузит соответствующий
|
|
1517
|
+
* static-чанк и форсит re-render через handle.update. См. PaywallUIOptions.locale.
|
|
1518
|
+
*
|
|
1519
|
+
* Передай `null`/`undefined`, чтобы вернуть автоматическую резолв-логику
|
|
1520
|
+
* (navigator.language → locale_default).
|
|
1521
|
+
*/
|
|
1522
|
+
setLocale(locale: string | null | undefined): void;
|
|
1310
1523
|
on<E extends PaywallEvent>(event: E, handler: PaywallEventHandler<E>): () => void;
|
|
1311
1524
|
off<E extends PaywallEvent>(event: E, handler: PaywallEventHandler<E>): void;
|
|
1312
1525
|
private emit;
|
|
@@ -1351,23 +1564,93 @@ export declare class PaywallUI {
|
|
|
1351
1564
|
*/
|
|
1352
1565
|
openAuth(opts?: OpenOptions): void;
|
|
1353
1566
|
/**
|
|
1354
|
-
*
|
|
1355
|
-
* `
|
|
1356
|
-
*
|
|
1357
|
-
*
|
|
1358
|
-
*
|
|
1359
|
-
*
|
|
1360
|
-
|
|
1567
|
+
* Шорткат над `openAuth()` — открывает модалку сразу на signin-форме.
|
|
1568
|
+
* Эквивалент `openAuth()` (signin — дефолт). Существует для симметрии с
|
|
1569
|
+
* `openSignup()` и читаемости host-кода:
|
|
1570
|
+
* - `paywall.openSignin()` — «вход в существующий аккаунт»
|
|
1571
|
+
* - `paywall.openSignup()` — «новая регистрация»
|
|
1572
|
+
* Без managed-auth — no-op.
|
|
1573
|
+
*/
|
|
1574
|
+
openSignin(opts?: OpenOptions): void;
|
|
1575
|
+
/**
|
|
1576
|
+
* Открывает модалку с auth-gate сразу в режиме регистрации (signup-mode
|
|
1577
|
+
* AuthPanel'а — email/password/repeat). Если в paywall layout админ
|
|
1578
|
+
* отключил allow_signup, AuthPanel игнорит mode и стартует с signin —
|
|
1579
|
+
* соблюдается admin-конфиг.
|
|
1580
|
+
* Без managed-auth — no-op.
|
|
1581
|
+
*/
|
|
1582
|
+
openSignup(opts?: OpenOptions): void;
|
|
1583
|
+
/**
|
|
1584
|
+
* Direct-checkout: создать checkout-URL по конкретной цене и сразу открыть
|
|
1585
|
+
* платёжного провайдера, минуя layout с тарифами. Полезно когда
|
|
1586
|
+
* host-приложение рендерит pricing-карточки/таблицу собственным UI и
|
|
1587
|
+
* хочет, чтобы клик по «Buy / Get this plan» вёл прямо в Stripe/Paddle.
|
|
1588
|
+
*
|
|
1589
|
+
* **Late-mount UX.** В отличие от `open()`, модалка не появляется во время
|
|
1590
|
+
* фоновой работы (bootstrap + visibility/trial gates + createCheckout).
|
|
1591
|
+
* Хост на этой фазе показывает busy-state прямо на своей кнопке (через
|
|
1592
|
+
* `state.processing === true` из `paywall.getState()` — или автоматически
|
|
1593
|
+
* через `<PaywallButton priceId>` в sdk-react). Модалка монтируется
|
|
1594
|
+
* ТОЛЬКО когда реально нужна UI:
|
|
1595
|
+
* - `checkout_mode='preauth'` + managed-auth + не залогинен → auth-gate
|
|
1596
|
+
* (форма signin'а); после успеха auto-resume в createCheckout.
|
|
1597
|
+
* - popup провайдера заблокирован браузером → popup_blocked view с
|
|
1598
|
+
* retry-кнопкой под fresh user gesture.
|
|
1599
|
+
* - popup открылся успешно → awaiting_payment view (индикатор «оплати
|
|
1600
|
+
* в новой вкладке» + I've paid).
|
|
1601
|
+
*
|
|
1602
|
+
* Что эмитится без модалки:
|
|
1603
|
+
* - `purchase_completed{restored:true, priceId}` когда юзер уже подписан
|
|
1604
|
+
* (cached user, fresh bootstrap, или 409 hasActivePurchase от бэка) —
|
|
1605
|
+
* headless reject;
|
|
1606
|
+
* - `error` когда createCheckout упал или identity.email отсутствует;
|
|
1607
|
+
* - `visibility_blocked` / `trial_blocked` — стандартные gate-эвенты.
|
|
1608
|
+
*
|
|
1609
|
+
* Что эмитится одновременно с модалкой:
|
|
1610
|
+
* - `checkout_started{priceId, url, acquiring}` ровно когда headless URL
|
|
1611
|
+
* получен, ДО mount'а awaiting_payment/popup_blocked.
|
|
1361
1612
|
*
|
|
1362
|
-
*
|
|
1363
|
-
*
|
|
1364
|
-
*
|
|
1613
|
+
* Offer (countdown-скидка) автоматически резолвится из cached offers'ов
|
|
1614
|
+
* через `getOfferForPrice(priceId)` и передаётся в createCheckout как
|
|
1615
|
+
* `offerId` — чтобы duration_minutes-офферы тоже применились на бэке
|
|
1616
|
+
* (для них нет server-side таймера, без явного offer-id скидка теряется).
|
|
1365
1617
|
*
|
|
1366
|
-
*
|
|
1367
|
-
*
|
|
1368
|
-
*
|
|
1618
|
+
* Требования:
|
|
1619
|
+
* - `identity.email` должен быть выставлен (через `opts.identity`, либо
|
|
1620
|
+
* managed-auth, либо ранний `setIdentity`/`paywall.open({identity})`).
|
|
1621
|
+
* Без email бэк `/start-checkout` 400'нёт; SDK эмитнет `error`.
|
|
1622
|
+
* - В `checkout_mode='preauth'` без managed-auth — backend требует
|
|
1623
|
+
* email-юзера; убедись что `identity.email` явно задан.
|
|
1624
|
+
*
|
|
1625
|
+
* Без модалки совсем (когда host рендерит свой awaiting-payment экран) —
|
|
1626
|
+
* используй `paywall.billing.createCheckout({priceId, offerId})` напрямую,
|
|
1627
|
+
* но тогда auth-gate / popup_blocked / awaiting_payment придётся рисовать
|
|
1628
|
+
* самостоятельно.
|
|
1369
1629
|
*/
|
|
1370
|
-
|
|
1630
|
+
checkout(priceId: string, opts?: OpenOptions): void;
|
|
1631
|
+
/** Headless prep-work для `checkout(priceId, opts)`: bootstrap → gates →
|
|
1632
|
+
* preauth check → createCheckout → mount модалки с финальным view.
|
|
1633
|
+
* Вынесено отдельным методом ради чистого async/await flow вместо вложенных
|
|
1634
|
+
* then-chain'ов (5+ ветвей). Любая ошибка не пробрасывается наружу: эмитим
|
|
1635
|
+
* через `paywall.emit('error')` и выходим — host подписан на `error`-event. */
|
|
1636
|
+
private runDirectCheckout;
|
|
1637
|
+
/** Trial-check без mount'а (для late-mount direct-checkout). Возвращает
|
|
1638
|
+
* true если trial заблокировал — caller должен прекратить flow. На любой
|
|
1639
|
+
* storage-ошибке log+продолжаем (не блокируем продажу). */
|
|
1640
|
+
private checkTrialBeforeCheckout;
|
|
1641
|
+
private applyProcessing;
|
|
1642
|
+
/**
|
|
1643
|
+
* Headless anonymous signin без открытия модалки. Внутри:
|
|
1644
|
+
* idempotent (если уже анон — instant return) → resume через сохранённый
|
|
1645
|
+
* refresh_token → fresh /auth/anonymous/signin. Дедуплицирует
|
|
1646
|
+
* параллельные вызовы внутри AuthClient'а.
|
|
1647
|
+
*
|
|
1648
|
+
* Удобно для host-кнопок типа «Continue as guest» — host сам управляет
|
|
1649
|
+
* loading-стейтом на своей кнопке, без полупустой модалки со спиннером.
|
|
1650
|
+
* Без managed-auth — резолвится rejected promise'ом (нет AuthClient'а
|
|
1651
|
+
* чтобы делать signin).
|
|
1652
|
+
*/
|
|
1653
|
+
signInAnonymously(): Promise<AuthSession>;
|
|
1371
1654
|
private openInternal;
|
|
1372
1655
|
/** Применить gates ПОСЛЕ того, как модалка уже смонтирована (mount-then-load
|
|
1373
1656
|
* путь). Если gate блокирует — close() + emit. Если юзер уже сам закрыл
|
|
@@ -1422,6 +1705,26 @@ export declare class PaywallUI {
|
|
|
1422
1705
|
}): Promise<PaywallPrice[]>;
|
|
1423
1706
|
/** Sync-снимок цен. null — bootstrap ещё не загружали. */
|
|
1424
1707
|
getCachedPrices(): PaywallPrice[] | null;
|
|
1708
|
+
/** Sync-снимок офферов. null = bootstrap не загружали, [] = пейвол без офферов.
|
|
1709
|
+
* Бэк уже применил серверный targeting (страны/email/режим) — наружу
|
|
1710
|
+
* выезжает только то, что применимо к текущему юзеру. */
|
|
1711
|
+
getCachedOffers(): PaywallOffer[] | null;
|
|
1712
|
+
/**
|
|
1713
|
+
* Резолвит активный offer для конкретной цены: price_id-таргетинг +
|
|
1714
|
+
* countdown (`expires_at` ИЛИ `duration_minutes` от первого открытия
|
|
1715
|
+
* пейвола, см. clientStorage `pw-offer-{id}-start`).
|
|
1716
|
+
*
|
|
1717
|
+
* Read-only — НЕ записывает start для `duration_minutes`-офферов. Запись
|
|
1718
|
+
* стартует только когда модалка реально открыта (renderer'ом). До этого
|
|
1719
|
+
* `getOfferForPrice` вернёт `null` для duration-only офферов, чтобы
|
|
1720
|
+
* страницы-хосты вне модалки (pricing, landing) не активировали countdown
|
|
1721
|
+
* раньше времени.
|
|
1722
|
+
*
|
|
1723
|
+
* Хост-странице нужен countdown, который тикает каждую секунду — для
|
|
1724
|
+
* этого использовать React-хук `usePaywallOffer(priceId)` из sdk-react
|
|
1725
|
+
* либо обёртку поверх `setInterval(1000)` + повторный вызов этого метода.
|
|
1726
|
+
*/
|
|
1727
|
+
getOfferForPrice(priceId: string): ResolvedOffer | null;
|
|
1425
1728
|
/** Снимок текущего «языка юзера» — proxy над `billing.getUserLanguage()`.
|
|
1426
1729
|
* Используй, чтобы синхронизировать i18n host'а с тем, что фактически
|
|
1427
1730
|
* показывает пейвол. См. подробности в `BillingClient.getUserLanguage`. */
|
|
@@ -1498,6 +1801,8 @@ export declare interface PaywallUIOptions extends Omit<BillingClientOptions, 'au
|
|
|
1498
1801
|
* флеш на blocked-странах/устройствах хуже воспринимаемой латентности.
|
|
1499
1802
|
*/
|
|
1500
1803
|
mountThenLoad?: boolean;
|
|
1804
|
+
/* Excluded from this release type: inline */
|
|
1805
|
+
/* Excluded from this release type: locale */
|
|
1501
1806
|
}
|
|
1502
1807
|
|
|
1503
1808
|
declare interface PaywallUser {
|
|
@@ -1509,6 +1814,12 @@ declare interface PaywallUser {
|
|
|
1509
1814
|
started_at: string | null;
|
|
1510
1815
|
expires_at: string | null;
|
|
1511
1816
|
} | null;
|
|
1817
|
+
/** Был ли у юзера хотя бы один trial по этому пейволу когда-либо (включая
|
|
1818
|
+
* истёкшие и отменённые). Anti-abuse флаг для UI: CtaButton скрывает
|
|
1819
|
+
* "Start N-Day Free Trial" если true. Серверный enforcement в
|
|
1820
|
+
* `/start-checkout` дублирует — даже если UI обмануть, бэк не отдаст
|
|
1821
|
+
* trial_days в Stripe/Paddle. */
|
|
1822
|
+
had_previous_trial: boolean;
|
|
1512
1823
|
}
|
|
1513
1824
|
|
|
1514
1825
|
declare interface PaywallUserPurchase {
|
|
@@ -1533,6 +1844,27 @@ declare class QuotaExceededError extends PaywallError {
|
|
|
1533
1844
|
});
|
|
1534
1845
|
}
|
|
1535
1846
|
|
|
1847
|
+
/**
|
|
1848
|
+
* Resolved view of a paywall offer — what host UI actually needs to render
|
|
1849
|
+
* a strike-through price + countdown without re-implementing the math.
|
|
1850
|
+
*
|
|
1851
|
+
* `remainingMs` ticks down with wall-clock time and reaches 0 on expiry.
|
|
1852
|
+
* `totalMs` stays constant — useful for progress bars / share-of-time UX.
|
|
1853
|
+
* `expiresAt` is the Date.now()-comparable epoch ms of expiry.
|
|
1854
|
+
*
|
|
1855
|
+
* For offers without an expiry mechanism (no `expires_at` and no
|
|
1856
|
+
* `duration_minutes`), `remainingMs`/`totalMs`/`expiresAt` are all `null`,
|
|
1857
|
+
* but the resolved view is still returned — discount badge / strike-through
|
|
1858
|
+
* still make sense for "perpetual sale" offers.
|
|
1859
|
+
*/
|
|
1860
|
+
declare interface ResolvedOffer {
|
|
1861
|
+
offer: PaywallOffer;
|
|
1862
|
+
discountPercent: number;
|
|
1863
|
+
remainingMs: number | null;
|
|
1864
|
+
totalMs: number | null;
|
|
1865
|
+
expiresAt: number | null;
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1536
1868
|
declare type SignUpResult = {
|
|
1537
1869
|
kind: 'signed_in';
|
|
1538
1870
|
session: AuthSession;
|