@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/core.d.ts
CHANGED
|
@@ -46,7 +46,9 @@ export declare class ApiGatewayClient {
|
|
|
46
46
|
|
|
47
47
|
export 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 @@ export 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
|
+
export declare type AuthChangeListener = (event: AuthChangeEvent, session: AuthSession | null) => void;
|
|
70
93
|
|
|
71
94
|
export declare class AuthClient {
|
|
72
95
|
readonly paywallId: string;
|
|
@@ -225,10 +248,8 @@ export 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 @@ export 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 @@ export 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 @@ export 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 @@ export declare class AuthClient {
|
|
|
424
468
|
|
|
425
469
|
export 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;
|
|
@@ -564,6 +610,13 @@ export declare class BillingClient {
|
|
|
564
610
|
}): Promise<PaywallPrice[]>;
|
|
565
611
|
/** Sync-снимок цен из последнего bootstrap'а. null = ещё не загружали. */
|
|
566
612
|
getCachedPrices(): PaywallPrice[] | null;
|
|
613
|
+
/** Sync-снимок офферов из последнего bootstrap'а. null = bootstrap ещё не
|
|
614
|
+
* загружали, пустой массив = бэк отдал пейвол без офферов. Бэк уже
|
|
615
|
+
* применил серверный таргетинг (target_countries / target_emails /
|
|
616
|
+
* targeting_mode из offer_settings) — наружу выезжает только то, что
|
|
617
|
+
* применимо к текущему юзеру. Клиентская сторона остаётся ответственной
|
|
618
|
+
* за price_id-matching и countdown (см. core/offer.ts → resolveOffer). */
|
|
619
|
+
getCachedOffers(): PaywallOffer[] | null;
|
|
567
620
|
/**
|
|
568
621
|
* Снимок того, какой язык SDK сейчас считает «языком юзера». Полезно для
|
|
569
622
|
* синхронизации i18n хоста с тем, что фактически показывает пейвол — чтобы
|
|
@@ -690,6 +743,17 @@ export declare class BillingClient {
|
|
|
690
743
|
errorUrl?: string;
|
|
691
744
|
shopUrl?: string;
|
|
692
745
|
trialDays?: number;
|
|
746
|
+
/** Активный offer для этой цены — резолвится host'ом через
|
|
747
|
+
* `paywall.getOfferForPrice(priceId)?.offer.id` или
|
|
748
|
+
* `findApplicableOffer(client.getCachedOffers(), priceId)?.id`. Без
|
|
749
|
+
* явной передачи бэк сделает auto-resolve по email — но только для
|
|
750
|
+
* end_date-офферов. duration_minutes-офферы тикают в clientStorage и
|
|
751
|
+
* сервер их не видит: для них offerId ОБЯЗАН прийти от клиента, иначе
|
|
752
|
+
* скидка не применится на чекауте, хотя UI её показывал.
|
|
753
|
+
*
|
|
754
|
+
* Передавать offer-id всегда безопасно — бэк сам проверит applicable
|
|
755
|
+
* ли offer к этому юзеру (страна/email/режим) и игнорирует если нет. */
|
|
756
|
+
offerId?: string;
|
|
693
757
|
/**
|
|
694
758
|
* Stage 1 защиты от дубликатов покупок. Идемпотентный ключ запроса
|
|
695
759
|
* (UUID). Повторный вызов с тем же ключом вернёт тот же checkout-URL
|
|
@@ -716,7 +780,9 @@ export declare class BillingClient {
|
|
|
716
780
|
* инвойсы). Опен-флоу управляется host'ом:
|
|
717
781
|
*
|
|
718
782
|
* ```ts
|
|
719
|
-
* const { url } = await billing.getCustomerPortalUrl(
|
|
783
|
+
* const { url } = await billing.getCustomerPortalUrl({
|
|
784
|
+
* returnUrl: 'https://your-app.com/account'
|
|
785
|
+
* });
|
|
720
786
|
* window.open(url, '_blank');
|
|
721
787
|
* ```
|
|
722
788
|
*
|
|
@@ -728,6 +794,14 @@ export declare class BillingClient {
|
|
|
728
794
|
*/
|
|
729
795
|
getCustomerPortalUrl(opts?: {
|
|
730
796
|
signal?: AbortSignal;
|
|
797
|
+
/** URL для return-button у провайдера (Stripe «Return to ...», Paddle
|
|
798
|
+
* и Chargebee redirect_url'ы). Передавай туда страницу-аккаунт твоего
|
|
799
|
+
* app'а — `https://your-app.com/account`. Без явного returnUrl бэк
|
|
800
|
+
* применяет fallback в порядке: `paywall_settings.shop_url` →
|
|
801
|
+
* custom_domain пейвола → NEXT_PUBLIC_ONLINE_ORIGIN (последнее — это
|
|
802
|
+
* страница в самом online-сервисе, годится только для legacy
|
|
803
|
+
* v2-iframe-флоу). */
|
|
804
|
+
returnUrl?: string;
|
|
731
805
|
}): Promise<{
|
|
732
806
|
url: string;
|
|
733
807
|
}>;
|
|
@@ -738,21 +812,31 @@ export declare class BillingClient {
|
|
|
738
812
|
* `/api/v1/paywall/[id]/user` без unstable_cache, потому что list для UI
|
|
739
813
|
* должен быть свежим после cancel-а.
|
|
740
814
|
*
|
|
741
|
-
* Auth
|
|
742
|
-
*
|
|
815
|
+
* Auth (два пути):
|
|
816
|
+
* - Bearer (через AuthClient) — user.id резолвится из сессии, identity
|
|
817
|
+
* в query игнорируется.
|
|
818
|
+
* - `apiKey` + `identity.email`/`identity.userId` — server-SDK путь для
|
|
819
|
+
* интеграций со своей авторизацией. Бэк проверяет, что identity линкована
|
|
820
|
+
* к этому пейволу (защита от cross-paywall lookup).
|
|
821
|
+
* Без auth и без apiKey+identity — `identity_required`.
|
|
743
822
|
*/
|
|
744
823
|
listPurchases(opts?: {
|
|
745
824
|
signal?: AbortSignal;
|
|
746
825
|
}): Promise<PaywallPurchaseDetailed[]>;
|
|
747
826
|
/**
|
|
748
|
-
* Отменить подписку. Бэк
|
|
749
|
-
*
|
|
750
|
-
*
|
|
827
|
+
* Отменить подписку. Бэк проверит, что subscription принадлежит юзеру
|
|
828
|
+
* (Bearer-путь — из сессии; apiKey-путь — из identity), и сделает cancel у
|
|
829
|
+
* acquiring'а (Stripe/Paddle/Chargebee/Overpay). По умолчанию cancel в
|
|
830
|
+
* конце текущего периода — юзер сохраняет access до renewal date'ы.
|
|
751
831
|
*
|
|
752
|
-
* `reason` обязательна (валидация на бэке).
|
|
753
|
-
* причин в host-UI, как в legacy customer portal'е.
|
|
832
|
+
* `reason` обязательна (валидация на бэке).
|
|
754
833
|
*
|
|
755
|
-
* Auth
|
|
834
|
+
* Auth (два пути):
|
|
835
|
+
* - Bearer (через AuthClient) — стандартный путь для UI customer-portal'a.
|
|
836
|
+
* - `apiKey` + `identity.email`/`identity.userId` — для self-service UI на
|
|
837
|
+
* бэке клиента со своей авторизацией. Бэк дополнительно фильтрует
|
|
838
|
+
* subscription по paywall_id, чтобы owner пейвола A не отменил подписку
|
|
839
|
+
* пейвола B.
|
|
756
840
|
*/
|
|
757
841
|
cancelSubscription(params: {
|
|
758
842
|
subscriptionId: string;
|
|
@@ -789,7 +873,15 @@ export declare class BillingClient {
|
|
|
789
873
|
|
|
790
874
|
export declare interface BillingClientOptions {
|
|
791
875
|
paywallId: string;
|
|
792
|
-
|
|
876
|
+
/**
|
|
877
|
+
* Origin серверного API SDK — обязательное поле. Должно совпадать с
|
|
878
|
+
* `custom_domain`, заданным для пейвола в платформе (модерация привязывает
|
|
879
|
+
* домен к paywall_id). SDK сверяет это значение с `bootstrap.settings.custom_domain`
|
|
880
|
+
* на первом ответе и кидает `invalid_config` при расхождении — защита от
|
|
881
|
+
* опечаток интегратора. Промежуточный `appbox.space` в новом SDK НЕ
|
|
882
|
+
* используется (это только для legacy v2).
|
|
883
|
+
*/
|
|
884
|
+
apiOrigin: string;
|
|
793
885
|
identity?: Identity;
|
|
794
886
|
storage?: StorageAdapter;
|
|
795
887
|
capabilities?: string[];
|
|
@@ -875,6 +967,11 @@ export declare interface EventTrackerOptions {
|
|
|
875
967
|
sendBeacon?: (url: string, data: BodyInit) => boolean;
|
|
876
968
|
}
|
|
877
969
|
|
|
970
|
+
/** Pick the offer applicable to a price. Targeted (`price_id === id`) wins
|
|
971
|
+
* over the global default (`price_id === null`). Offers without a positive
|
|
972
|
+
* `discount_percent` are ignored. */
|
|
973
|
+
export declare function findApplicableOffer(offers: PaywallOffer[] | null | undefined, priceId: string): PaywallOffer | null;
|
|
974
|
+
|
|
878
975
|
export declare function generateVisitorId(): string;
|
|
879
976
|
|
|
880
977
|
export declare interface Identity {
|
|
@@ -883,6 +980,18 @@ export declare interface Identity {
|
|
|
883
980
|
anonymousId?: string;
|
|
884
981
|
}
|
|
885
982
|
|
|
983
|
+
export declare interface LastLogin {
|
|
984
|
+
method: LastLoginMethod;
|
|
985
|
+
email: string | null;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
/** Метод, которым юзер залогинился в последний раз на этом пейволе.
|
|
989
|
+
* Хранится per-paywall в storage и используется UI чтобы:
|
|
990
|
+
* - предзаполнить email-инпут last-known email'ом;
|
|
991
|
+
* - подсветить ту же OAuth-кнопку / email-форму бейджем "Last used".
|
|
992
|
+
* `email` — email/password forms (signin или signup → confirm). */
|
|
993
|
+
export declare type LastLoginMethod = OAuthProvider | 'email';
|
|
994
|
+
|
|
886
995
|
export declare interface Layout {
|
|
887
996
|
type: 'modal';
|
|
888
997
|
blocks: LayoutBlock[];
|
|
@@ -898,9 +1007,13 @@ export declare type LayoutBlock = {
|
|
|
898
1007
|
} | {
|
|
899
1008
|
type: 'price_grid';
|
|
900
1009
|
priceIds?: string[];
|
|
901
|
-
/** Раскладка карточек
|
|
902
|
-
* `
|
|
903
|
-
|
|
1010
|
+
/** Раскладка карточек цен:
|
|
1011
|
+
* - `vertical` (default) — стек карточек сверху вниз;
|
|
1012
|
+
* - `compact` — компактный список (одна строка на цену, без карточки,
|
|
1013
|
+
* с разделителем); v2-аналог `view: 'telegram'`;
|
|
1014
|
+
* - `horizontal` — несколько карточек рядом в ряд; v2-only с момента
|
|
1015
|
+
* SDK 3.0 (legacy не показывает выбор этой опции в админке). */
|
|
1016
|
+
view?: 'vertical' | 'compact' | 'horizontal';
|
|
904
1017
|
/** ID цены, которая помечается лейблом «популярный план». v2-аналог
|
|
905
1018
|
* пары `price_label_id` + `price_label`. */
|
|
906
1019
|
popular_price_id?: string;
|
|
@@ -909,7 +1022,10 @@ export declare type LayoutBlock = {
|
|
|
909
1022
|
popular_label?: string;
|
|
910
1023
|
} | {
|
|
911
1024
|
type: 'cta_button';
|
|
912
|
-
|
|
1025
|
+
/** Текст на кнопке. Если не задан — рендерер сам подберёт по
|
|
1026
|
+
* selected price'у и `trial_days`: "Start N-Day Free Trial",
|
|
1027
|
+
* "Get Lifetime Access", "Get Monthly Plan" и т.п. */
|
|
1028
|
+
label?: string;
|
|
913
1029
|
action: 'checkout' | 'close';
|
|
914
1030
|
priceId?: string;
|
|
915
1031
|
} | {
|
|
@@ -928,8 +1044,23 @@ export declare type LayoutBlock = {
|
|
|
928
1044
|
/** Скрывать панель, если юзер уже залогинен. По умолчанию true.
|
|
929
1045
|
* false — показываем "Signed in as ... [Sign out]" даже после логина. */
|
|
930
1046
|
hide_when_authenticated?: boolean;
|
|
931
|
-
/**
|
|
1047
|
+
/** Кастомный заголовок над формой. Если задан — отображается вместо
|
|
1048
|
+
* дефолтного (определяется по mode'у — "Welcome back!" / "Welcome!" /
|
|
1049
|
+
* "Forgot password?" / ...). Без `submit_label` также используется как
|
|
1050
|
+
* submit-лейбл для signin (например `heading="Restore Purchases"` →
|
|
1051
|
+
* submit тоже "Restore Purchases"). Длинные heading (типа "Войдите,
|
|
1052
|
+
* чтобы продолжить покупку") в кнопку влезают плохо — задай
|
|
1053
|
+
* `submit_label` отдельно. */
|
|
932
1054
|
heading?: string;
|
|
1055
|
+
/** Подпись под заголовком. Если опущен — подставляется default-текст
|
|
1056
|
+
* для текущего mode'а. Передай пустую строку чтобы скрыть подпись. */
|
|
1057
|
+
subheading?: string;
|
|
1058
|
+
/** Явный текст submit-кнопки. Имеет приоритет над heading-эхо. Нужен
|
|
1059
|
+
* для интентов с длинным descriptive heading'ом (preauth: "Войдите,
|
|
1060
|
+
* чтобы продолжить покупку" — кнопка только "Войти"). Для коротких
|
|
1061
|
+
* action-headings (restore: "Restore Purchases") опускай — эхо
|
|
1062
|
+
* даёт правильный UX. */
|
|
1063
|
+
submit_label?: string;
|
|
933
1064
|
} | {
|
|
934
1065
|
/** Список фич/преимуществ продукта. v2-аналог `features_list` + `features_view`.
|
|
935
1066
|
* До 5 элементов — рендерим как чек-лист с заголовком и описанием. */
|
|
@@ -953,6 +1084,35 @@ export declare type LayoutBlock = {
|
|
|
953
1084
|
desc: string;
|
|
954
1085
|
count: number;
|
|
955
1086
|
}>;
|
|
1087
|
+
} | {
|
|
1088
|
+
/** Money-back guarantee badge под cta_button: иконка + жирный заголовок +
|
|
1089
|
+
* пояснение мелким шрифтом + bottom divider, который визуально стыкуется
|
|
1090
|
+
* с current_session ниже. v2-аналог inline-блока в `PaywallPricing`. */
|
|
1091
|
+
type: 'guarantee_badge';
|
|
1092
|
+
/** Заголовок жирным. По умолчанию "100% Money-Back Guarantee". */
|
|
1093
|
+
title?: string;
|
|
1094
|
+
/** Подзаголовок мелким серым. По умолчанию
|
|
1095
|
+
* "Not satisfied? We'll refund you — no questions asked.". */
|
|
1096
|
+
subtitle?: string;
|
|
1097
|
+
/** Иконка слева от заголовка. По умолчанию `dollar_shield` —
|
|
1098
|
+
* зелёный shield с долларом (legacy-вид). `none` — без иконки. */
|
|
1099
|
+
icon?: 'dollar_shield' | 'none';
|
|
1100
|
+
} | {
|
|
1101
|
+
/** Urgency-баннер с countdown'ом до конца offer'а. Берёт первый offer
|
|
1102
|
+
* из `bootstrap.offers` с валидным `expires_at` или `duration_minutes`.
|
|
1103
|
+
* Авто-скрывается по истечении, чтобы не показывать "0d 0h 0m 0s".
|
|
1104
|
+
* Размещение — обычно первый блок в layout (над heading). */
|
|
1105
|
+
type: 'offer_banner';
|
|
1106
|
+
/** ID конкретного offer'а из bootstrap.offers. Если не задано — берётся
|
|
1107
|
+
* первый offer с активным таймером. */
|
|
1108
|
+
offer_id?: string;
|
|
1109
|
+
/** Текст слева от countdown'а. Если опущен — берётся `offer.label`,
|
|
1110
|
+
* иначе fallback "Limited-time offer". К нему дописывается процент:
|
|
1111
|
+
* "{title} {discount_percent}%" если discount задан. */
|
|
1112
|
+
title?: string;
|
|
1113
|
+
/** В превью админки — игнорировать expired-state, всё равно показывать
|
|
1114
|
+
* banner с нулями. Прод-режим — false (banner исчезает). */
|
|
1115
|
+
force?: boolean;
|
|
956
1116
|
};
|
|
957
1117
|
|
|
958
1118
|
/** Локализационные оверрайды для одного языка. Накатываются поверх дефолтного
|
|
@@ -972,6 +1132,11 @@ export declare interface LocaleOverrides {
|
|
|
972
1132
|
|
|
973
1133
|
export declare type OAuthProvider = 'google' | 'apple' | 'github' | 'facebook';
|
|
974
1134
|
|
|
1135
|
+
/** Storage key under which a relative `duration_minutes` offer records its
|
|
1136
|
+
* first-view timestamp. Shared between the renderer (which writes the
|
|
1137
|
+
* start on first open) and the host SDK helpers (which read it). */
|
|
1138
|
+
export declare function offerStartStorageKey(offerId: string): string;
|
|
1139
|
+
|
|
975
1140
|
export declare type OtpVerifyType = 'email' | 'recovery' | 'signup' | 'magiclink' | 'invite';
|
|
976
1141
|
|
|
977
1142
|
export declare interface PaywallBootstrap {
|
|
@@ -1007,7 +1172,17 @@ export declare class PaywallError extends Error {
|
|
|
1007
1172
|
export declare interface PaywallOffer {
|
|
1008
1173
|
id: string;
|
|
1009
1174
|
discount_percent: number | null;
|
|
1175
|
+
/** Абсолютная expiration date (ISO 8601). Если задана — countdown отсчитывает
|
|
1176
|
+
* до этого момента, по истечении offer считается истёкшим. */
|
|
1010
1177
|
expires_at: string | null;
|
|
1178
|
+
/** Относительный таймер: сколько минут offer живёт **от первого просмотра
|
|
1179
|
+
* пейвола** данным юзером. Старт хранится в clientStorage под ключом
|
|
1180
|
+
* `pw-offer-{id}-start` и остаётся там **после** expiry — это
|
|
1181
|
+
* forever-marker, чтобы юзер не мог «фармить» offer (re-open пейвола
|
|
1182
|
+
* не запускает countdown заново). Используется, когда бэк хочет
|
|
1183
|
+
* показывать "remaining time" без жёсткой server-time, а считать
|
|
1184
|
+
* относительно сессии юзера. expires_at имеет приоритет если задано. */
|
|
1185
|
+
duration_minutes?: number | null;
|
|
1011
1186
|
price_id: string | null;
|
|
1012
1187
|
label?: string | null;
|
|
1013
1188
|
}
|
|
@@ -1032,7 +1207,7 @@ export declare interface PaywallPrice {
|
|
|
1032
1207
|
* идёт из `/user-state` и имеет минимум для access-gate'а), этот shape
|
|
1033
1208
|
* включает цену/валюту/discount — чтобы host мог нарисовать список подписок
|
|
1034
1209
|
* как в legacy customer portal'е. */
|
|
1035
|
-
declare interface PaywallPurchaseDetailed {
|
|
1210
|
+
export declare interface PaywallPurchaseDetailed {
|
|
1036
1211
|
id: string;
|
|
1037
1212
|
status: string | null;
|
|
1038
1213
|
cancel_at: string | null;
|
|
@@ -1057,6 +1232,14 @@ export declare interface PaywallSettings {
|
|
|
1057
1232
|
brand_color?: string | null;
|
|
1058
1233
|
custom_css?: string | null;
|
|
1059
1234
|
locale_default?: string | null;
|
|
1235
|
+
/** Origin, на котором живёт бэк пейвола (тот же, что мерчант передаёт в
|
|
1236
|
+
* `BillingClientOptions.apiOrigin` при инициализации SDK). Бэк присылает
|
|
1237
|
+
* его на каждом bootstrap'е, SDK сверяет с init.apiOrigin — расхождение
|
|
1238
|
+
* даёт `invalid_config` (защита от опечатки интегратора). Без схемы:
|
|
1239
|
+
* "pay.your-domain.com" или "https://pay.your-domain.com" — оба валидны.
|
|
1240
|
+
* Для новых пейволов поле всегда заполнено (модерация требует custom_domain);
|
|
1241
|
+
* для legacy v2 может быть null/undefined. */
|
|
1242
|
+
custom_domain?: string | null;
|
|
1060
1243
|
runtime_mode?: 'client' | 'hybrid' | 'server' | 'client-native' | 'hybrid-native';
|
|
1061
1244
|
/** true, если эквайринг пейвола в test-mode — SDK рисует TEST MODE бейдж. */
|
|
1062
1245
|
is_test_mode?: boolean;
|
|
@@ -1114,6 +1297,12 @@ export declare interface PaywallUser {
|
|
|
1114
1297
|
started_at: string | null;
|
|
1115
1298
|
expires_at: string | null;
|
|
1116
1299
|
} | null;
|
|
1300
|
+
/** Был ли у юзера хотя бы один trial по этому пейволу когда-либо (включая
|
|
1301
|
+
* истёкшие и отменённые). Anti-abuse флаг для UI: CtaButton скрывает
|
|
1302
|
+
* "Start N-Day Free Trial" если true. Серверный enforcement в
|
|
1303
|
+
* `/start-checkout` дублирует — даже если UI обмануть, бэк не отдаст
|
|
1304
|
+
* trial_days в Stripe/Paddle. */
|
|
1305
|
+
had_previous_trial: boolean;
|
|
1117
1306
|
}
|
|
1118
1307
|
|
|
1119
1308
|
export declare interface PaywallUserPurchase {
|
|
@@ -1138,6 +1327,51 @@ export declare class QuotaExceededError extends PaywallError {
|
|
|
1138
1327
|
});
|
|
1139
1328
|
}
|
|
1140
1329
|
|
|
1330
|
+
/** Safe browser localStorage getter — returns null in SSR / private mode. */
|
|
1331
|
+
export declare function readBrowserOfferStart(offerId: string): string | null;
|
|
1332
|
+
|
|
1333
|
+
/**
|
|
1334
|
+
* Resolved view of a paywall offer — what host UI actually needs to render
|
|
1335
|
+
* a strike-through price + countdown without re-implementing the math.
|
|
1336
|
+
*
|
|
1337
|
+
* `remainingMs` ticks down with wall-clock time and reaches 0 on expiry.
|
|
1338
|
+
* `totalMs` stays constant — useful for progress bars / share-of-time UX.
|
|
1339
|
+
* `expiresAt` is the Date.now()-comparable epoch ms of expiry.
|
|
1340
|
+
*
|
|
1341
|
+
* For offers without an expiry mechanism (no `expires_at` and no
|
|
1342
|
+
* `duration_minutes`), `remainingMs`/`totalMs`/`expiresAt` are all `null`,
|
|
1343
|
+
* but the resolved view is still returned — discount badge / strike-through
|
|
1344
|
+
* still make sense for "perpetual sale" offers.
|
|
1345
|
+
*/
|
|
1346
|
+
export declare interface ResolvedOffer {
|
|
1347
|
+
offer: PaywallOffer;
|
|
1348
|
+
discountPercent: number;
|
|
1349
|
+
remainingMs: number | null;
|
|
1350
|
+
totalMs: number | null;
|
|
1351
|
+
expiresAt: number | null;
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
/** Compute the resolved view of an offer. Pure, no side-effects. */
|
|
1355
|
+
export declare function resolveOffer(offer: PaywallOffer, opts?: ResolveOfferOptions): ResolvedOffer | null;
|
|
1356
|
+
|
|
1357
|
+
export declare interface ResolveOfferOptions {
|
|
1358
|
+
/** Current epoch ms. Inject for deterministic tests; default `Date.now()`. */
|
|
1359
|
+
now?: number;
|
|
1360
|
+
/**
|
|
1361
|
+
* Synchronous reader for the `duration_minutes` start-timestamp ISO string.
|
|
1362
|
+
* Host passes a closure over its sync storage (browser → `localStorage`,
|
|
1363
|
+
* memory → in-process map). Return `null` if no start has been recorded.
|
|
1364
|
+
*
|
|
1365
|
+
* Intentionally synchronous, because consumers call this from UI render —
|
|
1366
|
+
* an async StorageAdapter would force every price card to suspend.
|
|
1367
|
+
*
|
|
1368
|
+
* If omitted, `duration_minutes`-only offers return `expiresAt = null`,
|
|
1369
|
+
* which makes the resolved view treat them as "not yet started" (the
|
|
1370
|
+
* renderer is responsible for writing the start on first paywall view).
|
|
1371
|
+
*/
|
|
1372
|
+
readStart?: (offerId: string) => string | null;
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1141
1375
|
export declare const SDK_VERSION = "3.0.0-alpha.0";
|
|
1142
1376
|
|
|
1143
1377
|
export declare type SignUpResult = {
|