@monetize.software/sdk 3.0.0-alpha.2 → 3.0.0-alpha.20
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-BXEOgPTK.js +3555 -0
- package/dist/chunks/PaywallUI-BXEOgPTK.js.map +1 -0
- package/dist/chunks/PaywallUI-Cybo6wdO.js +26 -0
- package/dist/chunks/PaywallUI-Cybo6wdO.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/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 +505 -338
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +411 -45
- package/dist/index.js +14 -10
- 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/index.d.ts
CHANGED
|
@@ -60,7 +60,9 @@ export declare class ApiGatewayClient {
|
|
|
60
60
|
|
|
61
61
|
export declare interface ApiGatewayClientOptions {
|
|
62
62
|
paywallId: string;
|
|
63
|
-
|
|
63
|
+
/** Origin серверного API SDK — обязательное поле, тот же `custom_domain`, что
|
|
64
|
+
* у BillingClient/AuthClient. См. {@link BillingClientOptions.apiOrigin}. */
|
|
65
|
+
apiOrigin: string;
|
|
64
66
|
/** AuthClient — Bearer добавляется автоматически. На 401 от gateway клиент
|
|
65
67
|
* не делает refresh: AuthClient уже сделал lazy-refresh в getAccessToken. */
|
|
66
68
|
auth?: AuthClient;
|
|
@@ -80,7 +82,28 @@ export declare interface ApiGatewayClientOptions {
|
|
|
80
82
|
onQuotaExceeded?: (err: QuotaExceededError) => void;
|
|
81
83
|
}
|
|
82
84
|
|
|
83
|
-
|
|
85
|
+
/** Дискриминатор для `onAuthChange`. Позволяет listener'у отличать первый
|
|
86
|
+
* callback (восстановление сессии из storage / синтетический snapshot для
|
|
87
|
+
* свежей подписки) от реальных переходов. Конвенция Supabase, минус события,
|
|
88
|
+
* которых у нас нет (MFA, EMAIL_VERIFIED).
|
|
89
|
+
*
|
|
90
|
+
* - INITIAL_SESSION — единственный гарантированный первый callback на каждую
|
|
91
|
+
* подписку. Дёргается через microtask после resolve hydrated-promise, даже
|
|
92
|
+
* если session=null. Listener'ы по этому event'у НЕ должны делать побочные
|
|
93
|
+
* эффекты типа force-refetch — это просто доставка стартового state'а.
|
|
94
|
+
* - SIGNED_IN — свежий вход: email/OAuth/anon, или появление session в этом
|
|
95
|
+
* инстансе из другого контекста (storage.watch), когда раньше был null.
|
|
96
|
+
* - SIGNED_OUT — signOut, revokeAllSessions, 401 на refresh, удаление session
|
|
97
|
+
* из другого контекста.
|
|
98
|
+
* - TOKEN_REFRESHED — тот же user, обновлённые токены: refresh(), либо
|
|
99
|
+
* storage.watch когда содержимое сменилось но user.id остался.
|
|
100
|
+
* - USER_UPDATED — изменился user.email / user.user_metadata (updatePassword,
|
|
101
|
+
* upgradeAnonymousToEmail) при том же user.id.
|
|
102
|
+
* - PASSWORD_RECOVERY — verifyOtp(type='recovery'). Listener знает, что надо
|
|
103
|
+
* показать «set new password» UI вместо обычного post-login flow'а. */
|
|
104
|
+
declare type AuthChangeEvent = 'INITIAL_SESSION' | 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED' | 'USER_UPDATED' | 'PASSWORD_RECOVERY';
|
|
105
|
+
|
|
106
|
+
export declare type AuthChangeListener = (event: AuthChangeEvent, session: AuthSession | null) => void;
|
|
84
107
|
|
|
85
108
|
export declare class AuthClient {
|
|
86
109
|
readonly paywallId: string;
|
|
@@ -239,10 +262,8 @@ export declare class AuthClient {
|
|
|
239
262
|
* когда сервер начнёт возвращать challenge_required в риск-сценариях,
|
|
240
263
|
* SDK сможет передать proof-of-something обратно без breaking change.
|
|
241
264
|
*
|
|
242
|
-
* `
|
|
243
|
-
* нового anon-юзера). Используется в switch-account flow.
|
|
244
|
-
* остаётся `forceCaptcha`, хотя капчи там больше нет — менять имя ломает
|
|
245
|
-
* host-сигнатуру; смысл «принудительно новая anon-сессия» сохранён.
|
|
265
|
+
* `forceNewAnon: true` пропускает шаги 1-2 и сразу делает /signin (создаёт
|
|
266
|
+
* нового anon-юзера). Используется в switch-account flow.
|
|
246
267
|
*
|
|
247
268
|
* Параллельные вызовы дедуплицируются через `inflightAnonSignin` — два
|
|
248
269
|
* click'а на «Войти как гость» не создадут двух anon-юзеров (два /signup =
|
|
@@ -251,7 +272,7 @@ export declare class AuthClient {
|
|
|
251
272
|
signInAnonymously(input?: {
|
|
252
273
|
captchaToken?: string;
|
|
253
274
|
userMeta?: Record<string, string>;
|
|
254
|
-
|
|
275
|
+
forceNewAnon?: boolean;
|
|
255
276
|
}): Promise<AuthSession>;
|
|
256
277
|
/**
|
|
257
278
|
* Внутренний resume — пробует /auth/refresh с сохранённым anon refresh_token.
|
|
@@ -399,8 +420,19 @@ export declare class AuthClient {
|
|
|
399
420
|
}): Promise<void>;
|
|
400
421
|
/**
|
|
401
422
|
* Подписка на изменения session: signin/signup/refresh/signOut/expired-401.
|
|
402
|
-
*
|
|
403
|
-
*
|
|
423
|
+
*
|
|
424
|
+
* Гарантированный контракт: ПЕРВЫЙ callback каждому subscriber'у — всегда
|
|
425
|
+
* `event = 'INITIAL_SESSION'`, дёргается асинхронно после resolve hydrate'а
|
|
426
|
+
* (даже если session=null — listener получает explicit «нет сессии», а не
|
|
427
|
+
* молчание). Все последующие callback'и — реальные переходы с конкретным
|
|
428
|
+
* event'ом (SIGNED_IN / SIGNED_OUT / TOKEN_REFRESHED / USER_UPDATED /
|
|
429
|
+
* PASSWORD_RECOVERY).
|
|
430
|
+
*
|
|
431
|
+
* Это позволяет listener'у безопасно делать «only on real signin» побочные
|
|
432
|
+
* эффекты (force refetch balances и т.п.) через `event === 'SIGNED_IN'`,
|
|
433
|
+
* не путая их с восстановлением из storage.
|
|
434
|
+
*
|
|
435
|
+
* Возвращает unsubscribe.
|
|
404
436
|
*/
|
|
405
437
|
onAuthChange(cb: AuthChangeListener): () => void;
|
|
406
438
|
private isFresh;
|
|
@@ -426,6 +458,18 @@ export declare class AuthClient {
|
|
|
426
458
|
private readAnonRefreshToken;
|
|
427
459
|
private writeAnonRefreshToken;
|
|
428
460
|
private clearAnonRefreshToken;
|
|
461
|
+
/**
|
|
462
|
+
* Last-used auth method + email — для UI бейджа "Last used" и pre-fill'а
|
|
463
|
+
* email-инпута. Storage paywall-scoped, поэтому переключение между
|
|
464
|
+
* пейволами на одном host'е не пересекает данные. Чтение всегда возвращает
|
|
465
|
+
* объект — отсутствующие поля = null. */
|
|
466
|
+
getLastLogin(): Promise<LastLogin | null>;
|
|
467
|
+
/** Запись method и email атомарно (для email/password flows — оба известны
|
|
468
|
+
* на момент signin/signup'а). OAuth-flows используют раздельные
|
|
469
|
+
* recordLastLoginMethod (до popup) и recordLastLoginEmail (после exchange). */
|
|
470
|
+
private recordLastLogin;
|
|
471
|
+
private recordLastLoginMethod;
|
|
472
|
+
private recordLastLoginEmail;
|
|
429
473
|
/**
|
|
430
474
|
* Читает stable visitor_id из storage если он там уже есть. НЕ генерит:
|
|
431
475
|
* AuthClient может быть инстанцирован раньше BillingClient, а синтетический
|
|
@@ -438,7 +482,9 @@ export declare class AuthClient {
|
|
|
438
482
|
|
|
439
483
|
export declare interface AuthClientOptions {
|
|
440
484
|
paywallId: string;
|
|
441
|
-
|
|
485
|
+
/** Origin серверного API SDK — обязательное поле, тот же `custom_domain`, что
|
|
486
|
+
* у BillingClient. См. {@link BillingClientOptions.apiOrigin}. */
|
|
487
|
+
apiOrigin: string;
|
|
442
488
|
storage?: StorageAdapter;
|
|
443
489
|
fetch?: typeof fetch;
|
|
444
490
|
openPopup?: (url: string, name: string) => Window | null;
|
|
@@ -591,6 +637,13 @@ export declare class BillingClient {
|
|
|
591
637
|
}): Promise<PaywallPrice[]>;
|
|
592
638
|
/** Sync-снимок цен из последнего bootstrap'а. null = ещё не загружали. */
|
|
593
639
|
getCachedPrices(): PaywallPrice[] | null;
|
|
640
|
+
/** Sync-снимок офферов из последнего bootstrap'а. null = bootstrap ещё не
|
|
641
|
+
* загружали, пустой массив = бэк отдал пейвол без офферов. Бэк уже
|
|
642
|
+
* применил серверный таргетинг (target_countries / target_emails /
|
|
643
|
+
* targeting_mode из offer_settings) — наружу выезжает только то, что
|
|
644
|
+
* применимо к текущему юзеру. Клиентская сторона остаётся ответственной
|
|
645
|
+
* за price_id-matching и countdown (см. core/offer.ts → resolveOffer). */
|
|
646
|
+
getCachedOffers(): PaywallOffer[] | null;
|
|
594
647
|
/**
|
|
595
648
|
* Снимок того, какой язык SDK сейчас считает «языком юзера». Полезно для
|
|
596
649
|
* синхронизации i18n хоста с тем, что фактически показывает пейвол — чтобы
|
|
@@ -717,6 +770,17 @@ export declare class BillingClient {
|
|
|
717
770
|
errorUrl?: string;
|
|
718
771
|
shopUrl?: string;
|
|
719
772
|
trialDays?: number;
|
|
773
|
+
/** Активный offer для этой цены — резолвится host'ом через
|
|
774
|
+
* `paywall.getOfferForPrice(priceId)?.offer.id` или
|
|
775
|
+
* `findApplicableOffer(client.getCachedOffers(), priceId)?.id`. Без
|
|
776
|
+
* явной передачи бэк сделает auto-resolve по email — но только для
|
|
777
|
+
* end_date-офферов. duration_minutes-офферы тикают в clientStorage и
|
|
778
|
+
* сервер их не видит: для них offerId ОБЯЗАН прийти от клиента, иначе
|
|
779
|
+
* скидка не применится на чекауте, хотя UI её показывал.
|
|
780
|
+
*
|
|
781
|
+
* Передавать offer-id всегда безопасно — бэк сам проверит applicable
|
|
782
|
+
* ли offer к этому юзеру (страна/email/режим) и игнорирует если нет. */
|
|
783
|
+
offerId?: string;
|
|
720
784
|
/**
|
|
721
785
|
* Stage 1 защиты от дубликатов покупок. Идемпотентный ключ запроса
|
|
722
786
|
* (UUID). Повторный вызов с тем же ключом вернёт тот же checkout-URL
|
|
@@ -743,7 +807,9 @@ export declare class BillingClient {
|
|
|
743
807
|
* инвойсы). Опен-флоу управляется host'ом:
|
|
744
808
|
*
|
|
745
809
|
* ```ts
|
|
746
|
-
* const { url } = await billing.getCustomerPortalUrl(
|
|
810
|
+
* const { url } = await billing.getCustomerPortalUrl({
|
|
811
|
+
* returnUrl: 'https://your-app.com/account'
|
|
812
|
+
* });
|
|
747
813
|
* window.open(url, '_blank');
|
|
748
814
|
* ```
|
|
749
815
|
*
|
|
@@ -755,6 +821,14 @@ export declare class BillingClient {
|
|
|
755
821
|
*/
|
|
756
822
|
getCustomerPortalUrl(opts?: {
|
|
757
823
|
signal?: AbortSignal;
|
|
824
|
+
/** URL для return-button у провайдера (Stripe «Return to ...», Paddle
|
|
825
|
+
* и Chargebee redirect_url'ы). Передавай туда страницу-аккаунт твоего
|
|
826
|
+
* app'а — `https://your-app.com/account`. Без явного returnUrl бэк
|
|
827
|
+
* применяет fallback в порядке: `paywall_settings.shop_url` →
|
|
828
|
+
* custom_domain пейвола → NEXT_PUBLIC_ONLINE_ORIGIN (последнее — это
|
|
829
|
+
* страница в самом online-сервисе, годится только для legacy
|
|
830
|
+
* v2-iframe-флоу). */
|
|
831
|
+
returnUrl?: string;
|
|
758
832
|
}): Promise<{
|
|
759
833
|
url: string;
|
|
760
834
|
}>;
|
|
@@ -765,21 +839,31 @@ export declare class BillingClient {
|
|
|
765
839
|
* `/api/v1/paywall/[id]/user` без unstable_cache, потому что list для UI
|
|
766
840
|
* должен быть свежим после cancel-а.
|
|
767
841
|
*
|
|
768
|
-
* Auth
|
|
769
|
-
*
|
|
842
|
+
* Auth (два пути):
|
|
843
|
+
* - Bearer (через AuthClient) — user.id резолвится из сессии, identity
|
|
844
|
+
* в query игнорируется.
|
|
845
|
+
* - `apiKey` + `identity.email`/`identity.userId` — server-SDK путь для
|
|
846
|
+
* интеграций со своей авторизацией. Бэк проверяет, что identity линкована
|
|
847
|
+
* к этому пейволу (защита от cross-paywall lookup).
|
|
848
|
+
* Без auth и без apiKey+identity — `identity_required`.
|
|
770
849
|
*/
|
|
771
850
|
listPurchases(opts?: {
|
|
772
851
|
signal?: AbortSignal;
|
|
773
852
|
}): Promise<PaywallPurchaseDetailed[]>;
|
|
774
853
|
/**
|
|
775
|
-
* Отменить подписку. Бэк
|
|
776
|
-
*
|
|
777
|
-
*
|
|
854
|
+
* Отменить подписку. Бэк проверит, что subscription принадлежит юзеру
|
|
855
|
+
* (Bearer-путь — из сессии; apiKey-путь — из identity), и сделает cancel у
|
|
856
|
+
* acquiring'а (Stripe/Paddle/Chargebee/Overpay). По умолчанию cancel в
|
|
857
|
+
* конце текущего периода — юзер сохраняет access до renewal date'ы.
|
|
778
858
|
*
|
|
779
|
-
* `reason` обязательна (валидация на бэке).
|
|
780
|
-
* причин в host-UI, как в legacy customer portal'е.
|
|
859
|
+
* `reason` обязательна (валидация на бэке).
|
|
781
860
|
*
|
|
782
|
-
* Auth
|
|
861
|
+
* Auth (два пути):
|
|
862
|
+
* - Bearer (через AuthClient) — стандартный путь для UI customer-portal'a.
|
|
863
|
+
* - `apiKey` + `identity.email`/`identity.userId` — для self-service UI на
|
|
864
|
+
* бэке клиента со своей авторизацией. Бэк дополнительно фильтрует
|
|
865
|
+
* subscription по paywall_id, чтобы owner пейвола A не отменил подписку
|
|
866
|
+
* пейвола B.
|
|
783
867
|
*/
|
|
784
868
|
cancelSubscription(params: {
|
|
785
869
|
subscriptionId: string;
|
|
@@ -816,7 +900,15 @@ export declare class BillingClient {
|
|
|
816
900
|
|
|
817
901
|
export declare interface BillingClientOptions {
|
|
818
902
|
paywallId: string;
|
|
819
|
-
|
|
903
|
+
/**
|
|
904
|
+
* Origin серверного API SDK — обязательное поле. Должно совпадать с
|
|
905
|
+
* `custom_domain`, заданным для пейвола в платформе (модерация привязывает
|
|
906
|
+
* домен к paywall_id). SDK сверяет это значение с `bootstrap.settings.custom_domain`
|
|
907
|
+
* на первом ответе и кидает `invalid_config` при расхождении — защита от
|
|
908
|
+
* опечаток интегратора. Промежуточный `appbox.space` в новом SDK НЕ
|
|
909
|
+
* используется (это только для legacy v2).
|
|
910
|
+
*/
|
|
911
|
+
apiOrigin: string;
|
|
820
912
|
identity?: Identity;
|
|
821
913
|
storage?: StorageAdapter;
|
|
822
914
|
capabilities?: string[];
|
|
@@ -862,6 +954,10 @@ export declare interface BlockContext {
|
|
|
862
954
|
/** Текущая auth-session (snapshot из AuthClient). null = разлогинен. PaywallRoot
|
|
863
955
|
* подписан на onAuthChange и пробрасывает свежий snapshot сюда. */
|
|
864
956
|
authSession: AuthSession | null;
|
|
957
|
+
/** Стартовый mode для AuthPanel — переопределяет дефолт 'signin'.
|
|
958
|
+
* Выставляется AuthGate'ом когда host вызвал openSignup()/openSignin().
|
|
959
|
+
* Остальные блоки игнорируют. */
|
|
960
|
+
initialAuthMode?: 'signin' | 'signup';
|
|
865
961
|
}
|
|
866
962
|
|
|
867
963
|
export declare interface BlockProps<B extends LayoutBlock = LayoutBlock> {
|
|
@@ -924,6 +1020,11 @@ export declare interface EventTrackerOptions {
|
|
|
924
1020
|
sendBeacon?: (url: string, data: BodyInit) => boolean;
|
|
925
1021
|
}
|
|
926
1022
|
|
|
1023
|
+
/** Pick the offer applicable to a price. Targeted (`price_id === id`) wins
|
|
1024
|
+
* over the global default (`price_id === null`). Offers without a positive
|
|
1025
|
+
* `discount_percent` are ignored. */
|
|
1026
|
+
export declare function findApplicableOffer(offers: PaywallOffer[] | null | undefined, priceId: string): PaywallOffer | null;
|
|
1027
|
+
|
|
927
1028
|
export declare function generateVisitorId(): string;
|
|
928
1029
|
|
|
929
1030
|
export declare interface GetAccessOptions {
|
|
@@ -938,6 +1039,18 @@ export declare interface Identity {
|
|
|
938
1039
|
anonymousId?: string;
|
|
939
1040
|
}
|
|
940
1041
|
|
|
1042
|
+
export declare interface LastLogin {
|
|
1043
|
+
method: LastLoginMethod;
|
|
1044
|
+
email: string | null;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
/** Метод, которым юзер залогинился в последний раз на этом пейволе.
|
|
1048
|
+
* Хранится per-paywall в storage и используется UI чтобы:
|
|
1049
|
+
* - предзаполнить email-инпут last-known email'ом;
|
|
1050
|
+
* - подсветить ту же OAuth-кнопку / email-форму бейджем "Last used".
|
|
1051
|
+
* `email` — email/password forms (signin или signup → confirm). */
|
|
1052
|
+
export declare type LastLoginMethod = OAuthProvider | 'email';
|
|
1053
|
+
|
|
941
1054
|
export declare interface Layout {
|
|
942
1055
|
type: 'modal';
|
|
943
1056
|
blocks: LayoutBlock[];
|
|
@@ -953,9 +1066,13 @@ export declare type LayoutBlock = {
|
|
|
953
1066
|
} | {
|
|
954
1067
|
type: 'price_grid';
|
|
955
1068
|
priceIds?: string[];
|
|
956
|
-
/** Раскладка карточек
|
|
957
|
-
* `
|
|
958
|
-
|
|
1069
|
+
/** Раскладка карточек цен:
|
|
1070
|
+
* - `vertical` (default) — стек карточек сверху вниз;
|
|
1071
|
+
* - `compact` — компактный список (одна строка на цену, без карточки,
|
|
1072
|
+
* с разделителем); v2-аналог `view: 'telegram'`;
|
|
1073
|
+
* - `horizontal` — несколько карточек рядом в ряд; v2-only с момента
|
|
1074
|
+
* SDK 3.0 (legacy не показывает выбор этой опции в админке). */
|
|
1075
|
+
view?: 'vertical' | 'compact' | 'horizontal';
|
|
959
1076
|
/** ID цены, которая помечается лейблом «популярный план». v2-аналог
|
|
960
1077
|
* пары `price_label_id` + `price_label`. */
|
|
961
1078
|
popular_price_id?: string;
|
|
@@ -964,7 +1081,10 @@ export declare type LayoutBlock = {
|
|
|
964
1081
|
popular_label?: string;
|
|
965
1082
|
} | {
|
|
966
1083
|
type: 'cta_button';
|
|
967
|
-
|
|
1084
|
+
/** Текст на кнопке. Если не задан — рендерер сам подберёт по
|
|
1085
|
+
* selected price'у и `trial_days`: "Start N-Day Free Trial",
|
|
1086
|
+
* "Get Lifetime Access", "Get Monthly Plan" и т.п. */
|
|
1087
|
+
label?: string;
|
|
968
1088
|
action: 'checkout' | 'close';
|
|
969
1089
|
priceId?: string;
|
|
970
1090
|
} | {
|
|
@@ -983,8 +1103,23 @@ export declare type LayoutBlock = {
|
|
|
983
1103
|
/** Скрывать панель, если юзер уже залогинен. По умолчанию true.
|
|
984
1104
|
* false — показываем "Signed in as ... [Sign out]" даже после логина. */
|
|
985
1105
|
hide_when_authenticated?: boolean;
|
|
986
|
-
/**
|
|
1106
|
+
/** Кастомный заголовок над формой. Если задан — отображается вместо
|
|
1107
|
+
* дефолтного (определяется по mode'у — "Welcome back!" / "Welcome!" /
|
|
1108
|
+
* "Forgot password?" / ...). Без `submit_label` также используется как
|
|
1109
|
+
* submit-лейбл для signin (например `heading="Restore Purchases"` →
|
|
1110
|
+
* submit тоже "Restore Purchases"). Длинные heading (типа "Войдите,
|
|
1111
|
+
* чтобы продолжить покупку") в кнопку влезают плохо — задай
|
|
1112
|
+
* `submit_label` отдельно. */
|
|
987
1113
|
heading?: string;
|
|
1114
|
+
/** Подпись под заголовком. Если опущен — подставляется default-текст
|
|
1115
|
+
* для текущего mode'а. Передай пустую строку чтобы скрыть подпись. */
|
|
1116
|
+
subheading?: string;
|
|
1117
|
+
/** Явный текст submit-кнопки. Имеет приоритет над heading-эхо. Нужен
|
|
1118
|
+
* для интентов с длинным descriptive heading'ом (preauth: "Войдите,
|
|
1119
|
+
* чтобы продолжить покупку" — кнопка только "Войти"). Для коротких
|
|
1120
|
+
* action-headings (restore: "Restore Purchases") опускай — эхо
|
|
1121
|
+
* даёт правильный UX. */
|
|
1122
|
+
submit_label?: string;
|
|
988
1123
|
} | {
|
|
989
1124
|
/** Список фич/преимуществ продукта. v2-аналог `features_list` + `features_view`.
|
|
990
1125
|
* До 5 элементов — рендерим как чек-лист с заголовком и описанием. */
|
|
@@ -1008,6 +1143,35 @@ export declare type LayoutBlock = {
|
|
|
1008
1143
|
desc: string;
|
|
1009
1144
|
count: number;
|
|
1010
1145
|
}>;
|
|
1146
|
+
} | {
|
|
1147
|
+
/** Money-back guarantee badge под cta_button: иконка + жирный заголовок +
|
|
1148
|
+
* пояснение мелким шрифтом + bottom divider, который визуально стыкуется
|
|
1149
|
+
* с current_session ниже. v2-аналог inline-блока в `PaywallPricing`. */
|
|
1150
|
+
type: 'guarantee_badge';
|
|
1151
|
+
/** Заголовок жирным. По умолчанию "100% Money-Back Guarantee". */
|
|
1152
|
+
title?: string;
|
|
1153
|
+
/** Подзаголовок мелким серым. По умолчанию
|
|
1154
|
+
* "Not satisfied? We'll refund you — no questions asked.". */
|
|
1155
|
+
subtitle?: string;
|
|
1156
|
+
/** Иконка слева от заголовка. По умолчанию `dollar_shield` —
|
|
1157
|
+
* зелёный shield с долларом (legacy-вид). `none` — без иконки. */
|
|
1158
|
+
icon?: 'dollar_shield' | 'none';
|
|
1159
|
+
} | {
|
|
1160
|
+
/** Urgency-баннер с countdown'ом до конца offer'а. Берёт первый offer
|
|
1161
|
+
* из `bootstrap.offers` с валидным `expires_at` или `duration_minutes`.
|
|
1162
|
+
* Авто-скрывается по истечении, чтобы не показывать "0d 0h 0m 0s".
|
|
1163
|
+
* Размещение — обычно первый блок в layout (над heading). */
|
|
1164
|
+
type: 'offer_banner';
|
|
1165
|
+
/** ID конкретного offer'а из bootstrap.offers. Если не задано — берётся
|
|
1166
|
+
* первый offer с активным таймером. */
|
|
1167
|
+
offer_id?: string;
|
|
1168
|
+
/** Текст слева от countdown'а. Если опущен — берётся `offer.label`,
|
|
1169
|
+
* иначе fallback "Limited-time offer". К нему дописывается процент:
|
|
1170
|
+
* "{title} {discount_percent}%" если discount задан. */
|
|
1171
|
+
title?: string;
|
|
1172
|
+
/** В превью админки — игнорировать expired-state, всё равно показывать
|
|
1173
|
+
* banner с нулями. Прод-режим — false (banner исчезает). */
|
|
1174
|
+
force?: boolean;
|
|
1011
1175
|
};
|
|
1012
1176
|
|
|
1013
1177
|
/** Локализационные оверрайды для одного языка. Накатываются поверх дефолтного
|
|
@@ -1027,6 +1191,11 @@ export declare interface LocaleOverrides {
|
|
|
1027
1191
|
|
|
1028
1192
|
export declare type OAuthProvider = 'google' | 'apple' | 'github' | 'facebook';
|
|
1029
1193
|
|
|
1194
|
+
/** Storage key under which a relative `duration_minutes` offer records its
|
|
1195
|
+
* first-view timestamp. Shared between the renderer (which writes the
|
|
1196
|
+
* start on first open) and the host SDK helpers (which read it). */
|
|
1197
|
+
export declare function offerStartStorageKey(offerId: string): string;
|
|
1198
|
+
|
|
1030
1199
|
export declare interface OpenOptions {
|
|
1031
1200
|
identity?: Identity;
|
|
1032
1201
|
/** Принудительно открыть, минуя pre-paywall trial check. По умолчанию SDK
|
|
@@ -1167,9 +1336,19 @@ declare interface PaywallEventPayloads {
|
|
|
1167
1336
|
/** User-state изменился (bootstrap snapshot, getUser refresh, watcher tick).
|
|
1168
1337
|
* Дёргается также сразу с last-known user после первой подписки. */
|
|
1169
1338
|
userChange: PaywallUser;
|
|
1170
|
-
/** Auth-session
|
|
1171
|
-
*
|
|
1172
|
-
|
|
1339
|
+
/** Auth-session изменилась. Payload содержит `event` (см. AuthChangeEvent —
|
|
1340
|
+
* INITIAL_SESSION / SIGNED_IN / SIGNED_OUT / TOKEN_REFRESHED / USER_UPDATED /
|
|
1341
|
+
* PASSWORD_RECOVERY) и `session` (null = разлогинен).
|
|
1342
|
+
*
|
|
1343
|
+
* Гарантированный контракт: первый callback каждому subscriber'у — всегда
|
|
1344
|
+
* INITIAL_SESSION с восстановленной из storage сессией (или null если нет).
|
|
1345
|
+
* Дальше — реальные переходы. Listener'у с побочными эффектами вроде
|
|
1346
|
+
* force-refetch balances ловить SIGNED_IN, а не любой truthy session,
|
|
1347
|
+
* иначе reload страницы будет триггерить лишний запрос. */
|
|
1348
|
+
authChange: {
|
|
1349
|
+
event: AuthChangeEvent;
|
|
1350
|
+
session: AuthSession | null;
|
|
1351
|
+
};
|
|
1173
1352
|
/** Триал заблокировал показ модалки. payload содержит свежий статус (после
|
|
1174
1353
|
* recordBlock). Для `mode: 'time'` — startedAt/expiresAt/remainingMs;
|
|
1175
1354
|
* для `mode: 'opens'` — remainingActions/totalActions. Хост может
|
|
@@ -1189,7 +1368,17 @@ declare interface PaywallEventPayloads {
|
|
|
1189
1368
|
export declare interface PaywallOffer {
|
|
1190
1369
|
id: string;
|
|
1191
1370
|
discount_percent: number | null;
|
|
1371
|
+
/** Абсолютная expiration date (ISO 8601). Если задана — countdown отсчитывает
|
|
1372
|
+
* до этого момента, по истечении offer считается истёкшим. */
|
|
1192
1373
|
expires_at: string | null;
|
|
1374
|
+
/** Относительный таймер: сколько минут offer живёт **от первого просмотра
|
|
1375
|
+
* пейвола** данным юзером. Старт хранится в clientStorage под ключом
|
|
1376
|
+
* `pw-offer-{id}-start` и остаётся там **после** expiry — это
|
|
1377
|
+
* forever-marker, чтобы юзер не мог «фармить» offer (re-open пейвола
|
|
1378
|
+
* не запускает countdown заново). Используется, когда бэк хочет
|
|
1379
|
+
* показывать "remaining time" без жёсткой server-time, а считать
|
|
1380
|
+
* относительно сессии юзера. expires_at имеет приоритет если задано. */
|
|
1381
|
+
duration_minutes?: number | null;
|
|
1193
1382
|
price_id: string | null;
|
|
1194
1383
|
label?: string | null;
|
|
1195
1384
|
}
|
|
@@ -1214,7 +1403,7 @@ export declare interface PaywallPrice {
|
|
|
1214
1403
|
* идёт из `/user-state` и имеет минимум для access-gate'а), этот shape
|
|
1215
1404
|
* включает цену/валюту/discount — чтобы host мог нарисовать список подписок
|
|
1216
1405
|
* как в legacy customer portal'е. */
|
|
1217
|
-
declare interface PaywallPurchaseDetailed {
|
|
1406
|
+
export declare interface PaywallPurchaseDetailed {
|
|
1218
1407
|
id: string;
|
|
1219
1408
|
status: string | null;
|
|
1220
1409
|
cancel_at: string | null;
|
|
@@ -1239,6 +1428,14 @@ export declare interface PaywallSettings {
|
|
|
1239
1428
|
brand_color?: string | null;
|
|
1240
1429
|
custom_css?: string | null;
|
|
1241
1430
|
locale_default?: string | null;
|
|
1431
|
+
/** Origin, на котором живёт бэк пейвола (тот же, что мерчант передаёт в
|
|
1432
|
+
* `BillingClientOptions.apiOrigin` при инициализации SDK). Бэк присылает
|
|
1433
|
+
* его на каждом bootstrap'е, SDK сверяет с init.apiOrigin — расхождение
|
|
1434
|
+
* даёт `invalid_config` (защита от опечатки интегратора). Без схемы:
|
|
1435
|
+
* "pay.your-domain.com" или "https://pay.your-domain.com" — оба валидны.
|
|
1436
|
+
* Для новых пейволов поле всегда заполнено (модерация требует custom_domain);
|
|
1437
|
+
* для legacy v2 может быть null/undefined. */
|
|
1438
|
+
custom_domain?: string | null;
|
|
1242
1439
|
runtime_mode?: 'client' | 'hybrid' | 'server' | 'client-native' | 'hybrid-native';
|
|
1243
1440
|
/** true, если эквайринг пейвола в test-mode — SDK рисует TEST MODE бейдж. */
|
|
1244
1441
|
is_test_mode?: boolean;
|
|
@@ -1295,12 +1492,25 @@ declare type PaywallStateListener = (state: PaywallStateSnapshot) => void;
|
|
|
1295
1492
|
* один call onState; повторы (`useSyncExternalStore`-friendly).
|
|
1296
1493
|
*/
|
|
1297
1494
|
export declare interface PaywallStateSnapshot {
|
|
1298
|
-
/** Модалка отрендерена и видна. False — closed (или ещё не открывалась).
|
|
1495
|
+
/** Модалка отрендерена и видна. False — closed (или ещё не открывалась).
|
|
1496
|
+
* Может быть false при `processing=true` — direct-checkout (paywall.checkout)
|
|
1497
|
+
* делает bootstrap + createCheckout headless до того, как решит надо ли
|
|
1498
|
+
* монтировать модалку. */
|
|
1299
1499
|
open: boolean;
|
|
1300
1500
|
/** Что показывается в модалке. null когда `open=false`. */
|
|
1301
|
-
view: 'loading' | 'error' | 'layout' | 'auth' | '
|
|
1501
|
+
view: 'loading' | 'error' | 'layout' | 'auth' | 'support' | 'awaiting_payment' | 'popup_blocked' | 'purchased' | null;
|
|
1302
1502
|
/** Заполнено только когда `view === 'error'`. */
|
|
1303
1503
|
error: PaywallError | null;
|
|
1504
|
+
/** SDK делает фоновую работу для `paywall.checkout(priceId)` — bootstrap,
|
|
1505
|
+
* visibility/trial-gates, createCheckout — до того, как реально нужна
|
|
1506
|
+
* UI-модалка. Хост на этой фазе может задизейблить свою кнопку и
|
|
1507
|
+
* показать спиннер прямо на ней, чтобы у юзера не было ощущения «клик
|
|
1508
|
+
* ничего не сделал». Сбрасывается в false сразу после mountAndShow
|
|
1509
|
+
* (модалка взяла на себя UI), либо после headless reject (already-paid,
|
|
1510
|
+
* ошибка createCheckout без модалки). Для `paywall.open()`-flow всегда
|
|
1511
|
+
* false: там модалка появляется мгновенно со своим LoadingView и
|
|
1512
|
+
* отдельный «processing» не нужен. */
|
|
1513
|
+
processing: boolean;
|
|
1304
1514
|
}
|
|
1305
1515
|
|
|
1306
1516
|
export declare class PaywallUI {
|
|
@@ -1335,6 +1545,10 @@ export declare class PaywallUI {
|
|
|
1335
1545
|
private lastVisibility;
|
|
1336
1546
|
/** Поведение open() при холодном bootstrap'е. См. PaywallUIOptions.mountThenLoad. */
|
|
1337
1547
|
private mountThenLoad;
|
|
1548
|
+
/** Inline-режим (live-preview редактора). См. PaywallUIOptions.inline. */
|
|
1549
|
+
private inline;
|
|
1550
|
+
/** Force-locale для I18nProvider. См. PaywallUIOptions.locale. */
|
|
1551
|
+
private forceLocale;
|
|
1338
1552
|
/** Текущий snapshot UI state-machine. Обновляется PaywallRoot'ом через
|
|
1339
1553
|
* `onState` prop; при close сбрасывается обратно в CLOSED_STATE. */
|
|
1340
1554
|
private currentState;
|
|
@@ -1368,6 +1582,15 @@ export declare class PaywallUI {
|
|
|
1368
1582
|
* почти всегда нежелательна.
|
|
1369
1583
|
*/
|
|
1370
1584
|
setBootstrap(partial: Partial<PaywallBootstrap>): void;
|
|
1585
|
+
/**
|
|
1586
|
+
* Сменить force-locale на лету — для live-preview редактора админки, когда
|
|
1587
|
+
* юзер переключает «Preview as user from <country>». Грузит соответствующий
|
|
1588
|
+
* static-чанк и форсит re-render через handle.update. См. PaywallUIOptions.locale.
|
|
1589
|
+
*
|
|
1590
|
+
* Передай `null`/`undefined`, чтобы вернуть автоматическую резолв-логику
|
|
1591
|
+
* (navigator.language → locale_default).
|
|
1592
|
+
*/
|
|
1593
|
+
setLocale(locale: string | null | undefined): void;
|
|
1371
1594
|
on<E extends PaywallEvent>(event: E, handler: PaywallEventHandler<E>): () => void;
|
|
1372
1595
|
off<E extends PaywallEvent>(event: E, handler: PaywallEventHandler<E>): void;
|
|
1373
1596
|
private emit;
|
|
@@ -1412,23 +1635,93 @@ export declare class PaywallUI {
|
|
|
1412
1635
|
*/
|
|
1413
1636
|
openAuth(opts?: OpenOptions): void;
|
|
1414
1637
|
/**
|
|
1415
|
-
*
|
|
1416
|
-
* `
|
|
1417
|
-
*
|
|
1418
|
-
*
|
|
1419
|
-
*
|
|
1420
|
-
*
|
|
1421
|
-
|
|
1638
|
+
* Шорткат над `openAuth()` — открывает модалку сразу на signin-форме.
|
|
1639
|
+
* Эквивалент `openAuth()` (signin — дефолт). Существует для симметрии с
|
|
1640
|
+
* `openSignup()` и читаемости host-кода:
|
|
1641
|
+
* - `paywall.openSignin()` — «вход в существующий аккаунт»
|
|
1642
|
+
* - `paywall.openSignup()` — «новая регистрация»
|
|
1643
|
+
* Без managed-auth — no-op.
|
|
1644
|
+
*/
|
|
1645
|
+
openSignin(opts?: OpenOptions): void;
|
|
1646
|
+
/**
|
|
1647
|
+
* Открывает модалку с auth-gate сразу в режиме регистрации (signup-mode
|
|
1648
|
+
* AuthPanel'а — email/password/repeat). Если в paywall layout админ
|
|
1649
|
+
* отключил allow_signup, AuthPanel игнорит mode и стартует с signin —
|
|
1650
|
+
* соблюдается admin-конфиг.
|
|
1651
|
+
* Без managed-auth — no-op.
|
|
1652
|
+
*/
|
|
1653
|
+
openSignup(opts?: OpenOptions): void;
|
|
1654
|
+
/**
|
|
1655
|
+
* Direct-checkout: создать checkout-URL по конкретной цене и сразу открыть
|
|
1656
|
+
* платёжного провайдера, минуя layout с тарифами. Полезно когда
|
|
1657
|
+
* host-приложение рендерит pricing-карточки/таблицу собственным UI и
|
|
1658
|
+
* хочет, чтобы клик по «Buy / Get this plan» вёл прямо в Stripe/Paddle.
|
|
1659
|
+
*
|
|
1660
|
+
* **Late-mount UX.** В отличие от `open()`, модалка не появляется во время
|
|
1661
|
+
* фоновой работы (bootstrap + visibility/trial gates + createCheckout).
|
|
1662
|
+
* Хост на этой фазе показывает busy-state прямо на своей кнопке (через
|
|
1663
|
+
* `state.processing === true` из `paywall.getState()` — или автоматически
|
|
1664
|
+
* через `<PaywallButton priceId>` в sdk-react). Модалка монтируется
|
|
1665
|
+
* ТОЛЬКО когда реально нужна UI:
|
|
1666
|
+
* - `checkout_mode='preauth'` + managed-auth + не залогинен → auth-gate
|
|
1667
|
+
* (форма signin'а); после успеха auto-resume в createCheckout.
|
|
1668
|
+
* - popup провайдера заблокирован браузером → popup_blocked view с
|
|
1669
|
+
* retry-кнопкой под fresh user gesture.
|
|
1670
|
+
* - popup открылся успешно → awaiting_payment view (индикатор «оплати
|
|
1671
|
+
* в новой вкладке» + I've paid).
|
|
1672
|
+
*
|
|
1673
|
+
* Что эмитится без модалки:
|
|
1674
|
+
* - `purchase_completed{restored:true, priceId}` когда юзер уже подписан
|
|
1675
|
+
* (cached user, fresh bootstrap, или 409 hasActivePurchase от бэка) —
|
|
1676
|
+
* headless reject;
|
|
1677
|
+
* - `error` когда createCheckout упал или identity.email отсутствует;
|
|
1678
|
+
* - `visibility_blocked` / `trial_blocked` — стандартные gate-эвенты.
|
|
1679
|
+
*
|
|
1680
|
+
* Что эмитится одновременно с модалкой:
|
|
1681
|
+
* - `checkout_started{priceId, url, acquiring}` ровно когда headless URL
|
|
1682
|
+
* получен, ДО mount'а awaiting_payment/popup_blocked.
|
|
1422
1683
|
*
|
|
1423
|
-
*
|
|
1424
|
-
*
|
|
1425
|
-
*
|
|
1684
|
+
* Offer (countdown-скидка) автоматически резолвится из cached offers'ов
|
|
1685
|
+
* через `getOfferForPrice(priceId)` и передаётся в createCheckout как
|
|
1686
|
+
* `offerId` — чтобы duration_minutes-офферы тоже применились на бэке
|
|
1687
|
+
* (для них нет server-side таймера, без явного offer-id скидка теряется).
|
|
1688
|
+
*
|
|
1689
|
+
* Требования:
|
|
1690
|
+
* - `identity.email` должен быть выставлен (через `opts.identity`, либо
|
|
1691
|
+
* managed-auth, либо ранний `setIdentity`/`paywall.open({identity})`).
|
|
1692
|
+
* Без email бэк `/start-checkout` 400'нёт; SDK эмитнет `error`.
|
|
1693
|
+
* - В `checkout_mode='preauth'` без managed-auth — backend требует
|
|
1694
|
+
* email-юзера; убедись что `identity.email` явно задан.
|
|
1695
|
+
*
|
|
1696
|
+
* Без модалки совсем (когда host рендерит свой awaiting-payment экран) —
|
|
1697
|
+
* используй `paywall.billing.createCheckout({priceId, offerId})` напрямую,
|
|
1698
|
+
* но тогда auth-gate / popup_blocked / awaiting_payment придётся рисовать
|
|
1699
|
+
* самостоятельно.
|
|
1700
|
+
*/
|
|
1701
|
+
checkout(priceId: string, opts?: OpenOptions): void;
|
|
1702
|
+
/** Headless prep-work для `checkout(priceId, opts)`: bootstrap → gates →
|
|
1703
|
+
* preauth check → createCheckout → mount модалки с финальным view.
|
|
1704
|
+
* Вынесено отдельным методом ради чистого async/await flow вместо вложенных
|
|
1705
|
+
* then-chain'ов (5+ ветвей). Любая ошибка не пробрасывается наружу: эмитим
|
|
1706
|
+
* через `paywall.emit('error')` и выходим — host подписан на `error`-event. */
|
|
1707
|
+
private runDirectCheckout;
|
|
1708
|
+
/** Trial-check без mount'а (для late-mount direct-checkout). Возвращает
|
|
1709
|
+
* true если trial заблокировал — caller должен прекратить flow. На любой
|
|
1710
|
+
* storage-ошибке log+продолжаем (не блокируем продажу). */
|
|
1711
|
+
private checkTrialBeforeCheckout;
|
|
1712
|
+
private applyProcessing;
|
|
1713
|
+
/**
|
|
1714
|
+
* Headless anonymous signin без открытия модалки. Внутри:
|
|
1715
|
+
* idempotent (если уже анон — instant return) → resume через сохранённый
|
|
1716
|
+
* refresh_token → fresh /auth/anonymous/signin. Дедуплицирует
|
|
1717
|
+
* параллельные вызовы внутри AuthClient'а.
|
|
1426
1718
|
*
|
|
1427
|
-
*
|
|
1428
|
-
*
|
|
1429
|
-
*
|
|
1719
|
+
* Удобно для host-кнопок типа «Continue as guest» — host сам управляет
|
|
1720
|
+
* loading-стейтом на своей кнопке, без полупустой модалки со спиннером.
|
|
1721
|
+
* Без managed-auth — резолвится rejected promise'ом (нет AuthClient'а
|
|
1722
|
+
* чтобы делать signin).
|
|
1430
1723
|
*/
|
|
1431
|
-
|
|
1724
|
+
signInAnonymously(): Promise<AuthSession>;
|
|
1432
1725
|
private openInternal;
|
|
1433
1726
|
/** Применить gates ПОСЛЕ того, как модалка уже смонтирована (mount-then-load
|
|
1434
1727
|
* путь). Если gate блокирует — close() + emit. Если юзер уже сам закрыл
|
|
@@ -1483,6 +1776,26 @@ export declare class PaywallUI {
|
|
|
1483
1776
|
}): Promise<PaywallPrice[]>;
|
|
1484
1777
|
/** Sync-снимок цен. null — bootstrap ещё не загружали. */
|
|
1485
1778
|
getCachedPrices(): PaywallPrice[] | null;
|
|
1779
|
+
/** Sync-снимок офферов. null = bootstrap не загружали, [] = пейвол без офферов.
|
|
1780
|
+
* Бэк уже применил серверный targeting (страны/email/режим) — наружу
|
|
1781
|
+
* выезжает только то, что применимо к текущему юзеру. */
|
|
1782
|
+
getCachedOffers(): PaywallOffer[] | null;
|
|
1783
|
+
/**
|
|
1784
|
+
* Резолвит активный offer для конкретной цены: price_id-таргетинг +
|
|
1785
|
+
* countdown (`expires_at` ИЛИ `duration_minutes` от первого открытия
|
|
1786
|
+
* пейвола, см. clientStorage `pw-offer-{id}-start`).
|
|
1787
|
+
*
|
|
1788
|
+
* Read-only — НЕ записывает start для `duration_minutes`-офферов. Запись
|
|
1789
|
+
* стартует только когда модалка реально открыта (renderer'ом). До этого
|
|
1790
|
+
* `getOfferForPrice` вернёт `null` для duration-only офферов, чтобы
|
|
1791
|
+
* страницы-хосты вне модалки (pricing, landing) не активировали countdown
|
|
1792
|
+
* раньше времени.
|
|
1793
|
+
*
|
|
1794
|
+
* Хост-странице нужен countdown, который тикает каждую секунду — для
|
|
1795
|
+
* этого использовать React-хук `usePaywallOffer(priceId)` из sdk-react
|
|
1796
|
+
* либо обёртку поверх `setInterval(1000)` + повторный вызов этого метода.
|
|
1797
|
+
*/
|
|
1798
|
+
getOfferForPrice(priceId: string): ResolvedOffer | null;
|
|
1486
1799
|
/** Снимок текущего «языка юзера» — proxy над `billing.getUserLanguage()`.
|
|
1487
1800
|
* Используй, чтобы синхронизировать i18n host'а с тем, что фактически
|
|
1488
1801
|
* показывает пейвол. См. подробности в `BillingClient.getUserLanguage`. */
|
|
@@ -1559,6 +1872,8 @@ export declare interface PaywallUIOptions extends Omit<BillingClientOptions, 'au
|
|
|
1559
1872
|
* флеш на blocked-странах/устройствах хуже воспринимаемой латентности.
|
|
1560
1873
|
*/
|
|
1561
1874
|
mountThenLoad?: boolean;
|
|
1875
|
+
/* Excluded from this release type: inline */
|
|
1876
|
+
/* Excluded from this release type: locale */
|
|
1562
1877
|
}
|
|
1563
1878
|
|
|
1564
1879
|
export declare interface PaywallUser {
|
|
@@ -1570,6 +1885,12 @@ export declare interface PaywallUser {
|
|
|
1570
1885
|
started_at: string | null;
|
|
1571
1886
|
expires_at: string | null;
|
|
1572
1887
|
} | null;
|
|
1888
|
+
/** Был ли у юзера хотя бы один trial по этому пейволу когда-либо (включая
|
|
1889
|
+
* истёкшие и отменённые). Anti-abuse флаг для UI: CtaButton скрывает
|
|
1890
|
+
* "Start N-Day Free Trial" если true. Серверный enforcement в
|
|
1891
|
+
* `/start-checkout` дублирует — даже если UI обмануть, бэк не отдаст
|
|
1892
|
+
* trial_days в Stripe/Paddle. */
|
|
1893
|
+
had_previous_trial: boolean;
|
|
1573
1894
|
}
|
|
1574
1895
|
|
|
1575
1896
|
export declare interface PaywallUserPurchase {
|
|
@@ -1594,6 +1915,51 @@ export declare class QuotaExceededError extends PaywallError {
|
|
|
1594
1915
|
});
|
|
1595
1916
|
}
|
|
1596
1917
|
|
|
1918
|
+
/** Safe browser localStorage getter — returns null in SSR / private mode. */
|
|
1919
|
+
export declare function readBrowserOfferStart(offerId: string): string | null;
|
|
1920
|
+
|
|
1921
|
+
/**
|
|
1922
|
+
* Resolved view of a paywall offer — what host UI actually needs to render
|
|
1923
|
+
* a strike-through price + countdown without re-implementing the math.
|
|
1924
|
+
*
|
|
1925
|
+
* `remainingMs` ticks down with wall-clock time and reaches 0 on expiry.
|
|
1926
|
+
* `totalMs` stays constant — useful for progress bars / share-of-time UX.
|
|
1927
|
+
* `expiresAt` is the Date.now()-comparable epoch ms of expiry.
|
|
1928
|
+
*
|
|
1929
|
+
* For offers without an expiry mechanism (no `expires_at` and no
|
|
1930
|
+
* `duration_minutes`), `remainingMs`/`totalMs`/`expiresAt` are all `null`,
|
|
1931
|
+
* but the resolved view is still returned — discount badge / strike-through
|
|
1932
|
+
* still make sense for "perpetual sale" offers.
|
|
1933
|
+
*/
|
|
1934
|
+
export declare interface ResolvedOffer {
|
|
1935
|
+
offer: PaywallOffer;
|
|
1936
|
+
discountPercent: number;
|
|
1937
|
+
remainingMs: number | null;
|
|
1938
|
+
totalMs: number | null;
|
|
1939
|
+
expiresAt: number | null;
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1942
|
+
/** Compute the resolved view of an offer. Pure, no side-effects. */
|
|
1943
|
+
export declare function resolveOffer(offer: PaywallOffer, opts?: ResolveOfferOptions): ResolvedOffer | null;
|
|
1944
|
+
|
|
1945
|
+
export declare interface ResolveOfferOptions {
|
|
1946
|
+
/** Current epoch ms. Inject for deterministic tests; default `Date.now()`. */
|
|
1947
|
+
now?: number;
|
|
1948
|
+
/**
|
|
1949
|
+
* Synchronous reader for the `duration_minutes` start-timestamp ISO string.
|
|
1950
|
+
* Host passes a closure over its sync storage (browser → `localStorage`,
|
|
1951
|
+
* memory → in-process map). Return `null` if no start has been recorded.
|
|
1952
|
+
*
|
|
1953
|
+
* Intentionally synchronous, because consumers call this from UI render —
|
|
1954
|
+
* an async StorageAdapter would force every price card to suspend.
|
|
1955
|
+
*
|
|
1956
|
+
* If omitted, `duration_minutes`-only offers return `expiresAt = null`,
|
|
1957
|
+
* which makes the resolved view treat them as "not yet started" (the
|
|
1958
|
+
* renderer is responsible for writing the start on first paywall view).
|
|
1959
|
+
*/
|
|
1960
|
+
readStart?: (offerId: string) => string | null;
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1597
1963
|
export declare const SDK_VERSION = "3.0.0-alpha.0";
|
|
1598
1964
|
|
|
1599
1965
|
export declare type SignUpResult = {
|