@monetize.software/sdk 3.0.0-alpha.0 → 3.0.0-alpha.10
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 +62 -41
- package/dist/chunks/PaywallUI-CQG9HCwo.js +3245 -0
- package/dist/chunks/PaywallUI-CQG9HCwo.js.map +1 -0
- package/dist/chunks/PaywallUI-DQ1Jke8b.js +26 -0
- package/dist/chunks/PaywallUI-DQ1Jke8b.js.map +1 -0
- package/dist/chunks/ar-7cgIM-Vl.js +2 -0
- package/dist/chunks/ar-7cgIM-Vl.js.map +1 -0
- package/dist/chunks/ar-B2Wg_IrC.js +126 -0
- package/dist/chunks/ar-B2Wg_IrC.js.map +1 -0
- package/dist/chunks/cs-BNo9Dx0Q.js +122 -0
- package/dist/chunks/cs-BNo9Dx0Q.js.map +1 -0
- package/dist/chunks/cs-S05PC5AC.js +2 -0
- package/dist/chunks/cs-S05PC5AC.js.map +1 -0
- package/dist/chunks/da-Bi4zBG14.js +2 -0
- package/dist/chunks/da-Bi4zBG14.js.map +1 -0
- package/dist/chunks/da-Do9Lq6En.js +122 -0
- package/dist/chunks/da-Do9Lq6En.js.map +1 -0
- package/dist/chunks/de-C8pDZNvx.js +141 -0
- package/dist/chunks/de-C8pDZNvx.js.map +1 -0
- package/dist/chunks/de-nCDB6D2W.js +2 -0
- package/dist/chunks/de-nCDB6D2W.js.map +1 -0
- package/dist/chunks/el-BrKaa978.js +2 -0
- package/dist/chunks/el-BrKaa978.js.map +1 -0
- package/dist/chunks/el-DzMNX-_P.js +126 -0
- package/dist/chunks/el-DzMNX-_P.js.map +1 -0
- package/dist/chunks/es-B-Wtyzrl.js +2 -0
- package/dist/chunks/es-B-Wtyzrl.js.map +1 -0
- package/dist/chunks/es-YrKt-q4w.js +141 -0
- package/dist/chunks/es-YrKt-q4w.js.map +1 -0
- package/dist/chunks/fi-Bh44pwZ4.js +122 -0
- package/dist/chunks/fi-Bh44pwZ4.js.map +1 -0
- package/dist/chunks/fi-D1SGXjnO.js +2 -0
- package/dist/chunks/fi-D1SGXjnO.js.map +1 -0
- package/dist/chunks/fr-Bc0pw4ws.js +141 -0
- package/dist/chunks/fr-Bc0pw4ws.js.map +1 -0
- package/dist/chunks/fr-BhYf-iKk.js +2 -0
- package/dist/chunks/fr-BhYf-iKk.js.map +1 -0
- package/dist/chunks/he-BXAaFv6Y.js +2 -0
- package/dist/chunks/he-BXAaFv6Y.js.map +1 -0
- package/dist/chunks/he-Bfm-bhe3.js +126 -0
- package/dist/chunks/he-Bfm-bhe3.js.map +1 -0
- package/dist/chunks/hi-D-O-B9Dn.js +126 -0
- package/dist/chunks/hi-D-O-B9Dn.js.map +1 -0
- package/dist/chunks/hi-xblDO0O7.js +2 -0
- package/dist/chunks/hi-xblDO0O7.js.map +1 -0
- package/dist/chunks/hu-CmIuAbLL.js +122 -0
- package/dist/chunks/hu-CmIuAbLL.js.map +1 -0
- package/dist/chunks/hu-Wa46p0y4.js +2 -0
- package/dist/chunks/hu-Wa46p0y4.js.map +1 -0
- package/dist/chunks/id-CQEo5X94.js +2 -0
- package/dist/chunks/id-CQEo5X94.js.map +1 -0
- package/dist/chunks/id-DN7IES-A.js +122 -0
- package/dist/chunks/id-DN7IES-A.js.map +1 -0
- package/dist/chunks/it-8AYCm0xz.js +2 -0
- package/dist/chunks/it-8AYCm0xz.js.map +1 -0
- package/dist/chunks/it-Cz5Nmqx5.js +141 -0
- package/dist/chunks/it-Cz5Nmqx5.js.map +1 -0
- package/dist/chunks/ja-BH9BlBh2.js +145 -0
- package/dist/chunks/ja-BH9BlBh2.js.map +1 -0
- package/dist/chunks/ja-q-COVayn.js +2 -0
- package/dist/chunks/ja-q-COVayn.js.map +1 -0
- package/dist/chunks/ko-B6HRCscZ.js +2 -0
- package/dist/chunks/ko-B6HRCscZ.js.map +1 -0
- package/dist/chunks/ko-CYV9QuYs.js +145 -0
- package/dist/chunks/ko-CYV9QuYs.js.map +1 -0
- package/dist/chunks/nl-BvkB900D.js +141 -0
- package/dist/chunks/nl-BvkB900D.js.map +1 -0
- package/dist/chunks/nl-CAd6_xlm.js +2 -0
- package/dist/chunks/nl-CAd6_xlm.js.map +1 -0
- package/dist/chunks/no-3s9_ormb.js +122 -0
- package/dist/chunks/no-3s9_ormb.js.map +1 -0
- package/dist/chunks/no-CAmz6bz6.js +2 -0
- package/dist/chunks/no-CAmz6bz6.js.map +1 -0
- package/dist/chunks/pl-C9WTGQtb.js +122 -0
- package/dist/chunks/pl-C9WTGQtb.js.map +1 -0
- package/dist/chunks/pl-DqUSTCaF.js +2 -0
- package/dist/chunks/pl-DqUSTCaF.js.map +1 -0
- package/dist/chunks/pt-8ARZnH0_.js +2 -0
- package/dist/chunks/pt-8ARZnH0_.js.map +1 -0
- package/dist/chunks/pt-uFVUv_Op.js +141 -0
- package/dist/chunks/pt-uFVUv_Op.js.map +1 -0
- package/dist/chunks/ro-BrqQ8Au-.js +122 -0
- package/dist/chunks/ro-BrqQ8Au-.js.map +1 -0
- package/dist/chunks/ro-D-NMbp2F.js +2 -0
- package/dist/chunks/ro-D-NMbp2F.js.map +1 -0
- package/dist/chunks/ru-8gbHPh0g.js +2 -0
- package/dist/chunks/ru-8gbHPh0g.js.map +1 -0
- package/dist/chunks/ru-DK594dA8.js +144 -0
- package/dist/chunks/ru-DK594dA8.js.map +1 -0
- package/dist/chunks/sv-CHNH8-mq.js +122 -0
- package/dist/chunks/sv-CHNH8-mq.js.map +1 -0
- package/dist/chunks/sv-D8a8hmx9.js +2 -0
- package/dist/chunks/sv-D8a8hmx9.js.map +1 -0
- package/dist/chunks/th-DfjUK0Y7.js +2 -0
- package/dist/chunks/th-DfjUK0Y7.js.map +1 -0
- package/dist/chunks/th-l24Pm5q-.js +126 -0
- package/dist/chunks/th-l24Pm5q-.js.map +1 -0
- package/dist/chunks/tr-ADpigSY5.js +122 -0
- package/dist/chunks/tr-ADpigSY5.js.map +1 -0
- package/dist/chunks/tr-BdBpz4tL.js +2 -0
- package/dist/chunks/tr-BdBpz4tL.js.map +1 -0
- package/dist/chunks/uk-CGqo4jek.js +144 -0
- package/dist/chunks/uk-CGqo4jek.js.map +1 -0
- package/dist/chunks/uk-Cx1zv1ao.js +2 -0
- package/dist/chunks/uk-Cx1zv1ao.js.map +1 -0
- package/dist/chunks/vi-Dk9bTu6f.js +122 -0
- package/dist/chunks/vi-Dk9bTu6f.js.map +1 -0
- package/dist/chunks/vi-oe2dW21I.js +2 -0
- package/dist/chunks/vi-oe2dW21I.js.map +1 -0
- package/dist/chunks/zh-CwczPMPp.js +2 -0
- package/dist/chunks/zh-CwczPMPp.js.map +1 -0
- package/dist/chunks/zh-LDkEV2D9.js +145 -0
- package/dist/chunks/zh-LDkEV2D9.js.map +1 -0
- package/dist/core.cjs +1 -1
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.ts +265 -24
- package/dist/core.js +519 -313
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +355 -43
- package/dist/index.js +14 -10
- package/dist/ui.cjs +1 -1
- package/dist/ui.d.ts +322 -44
- package/dist/ui.js +1 -1
- package/package.json +32 -31
- package/dist/chunks/PaywallUI-BHp9afFC.js +0 -2209
- package/dist/chunks/PaywallUI-BHp9afFC.js.map +0 -1
- package/dist/chunks/PaywallUI-Dr-6q-HL.js +0 -26
- package/dist/chunks/PaywallUI-Dr-6q-HL.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./core.cjs"),r=require("./chunks/PaywallUI-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./core.cjs"),r=require("./chunks/PaywallUI-DQ1Jke8b.js");exports.ApiClient=e.ApiClient;exports.ApiGatewayClient=e.ApiGatewayClient;exports.AuthClient=e.AuthClient;exports.BillingClient=e.BillingClient;exports.EventTracker=e.EventTracker;exports.PaywallError=e.PaywallError;exports.QuotaExceededError=e.QuotaExceededError;exports.SDK_VERSION=e.SDK_VERSION;exports.STORAGE_KEYS=e.STORAGE_KEYS;exports.createStorage=e.createStorage;exports.ensureVisitorId=e.ensureVisitorId;exports.findApplicableOffer=e.findApplicableOffer;exports.generateVisitorId=e.generateVisitorId;exports.offerStartStorageKey=e.offerStartStorageKey;exports.readBrowserOfferStart=e.readBrowserOfferStart;exports.resolveOffer=e.resolveOffer;exports.PaywallUI=r.PaywallUI;exports.blockRegistry=r.blockRegistry;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
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;
|
|
@@ -514,6 +560,8 @@ export declare class BillingClient {
|
|
|
514
560
|
private balancesStorageUnwatch;
|
|
515
561
|
private inflightBalances;
|
|
516
562
|
private balanceListeners;
|
|
563
|
+
private readonly previewMode;
|
|
564
|
+
private previewVersionCounter;
|
|
517
565
|
constructor(opts: BillingClientOptions);
|
|
518
566
|
/**
|
|
519
567
|
* Stable visitor_id (UUID v4). Первый вызов awaitит первичный резолв из
|
|
@@ -546,6 +594,24 @@ export declare class BillingClient {
|
|
|
546
594
|
* unsubscribe.
|
|
547
595
|
*/
|
|
548
596
|
onBootstrapChange(cb: (b: PaywallBootstrap) => void): () => void;
|
|
597
|
+
/**
|
|
598
|
+
* Заменить cachedBootstrap частичными или полными данными и эмитнуть всем
|
|
599
|
+
* подписчикам. Используется host'ом в preview-mode (редактор админки) для
|
|
600
|
+
* live-обновления открытой модалки без сетевого revalidate'а.
|
|
601
|
+
*
|
|
602
|
+
* Поведение:
|
|
603
|
+
* - Без `cachedBootstrap` ожидаются как минимум `settings` + `prices` —
|
|
604
|
+
* иначе PaywallRoot не сможет отрендерить тарифы и упадёт.
|
|
605
|
+
* - С существующим кешем партиал мёрджится поверх: `settings` глубокий мёрдж
|
|
606
|
+
* на 1 уровень (поля настроек), массивы `prices`/`offers` перезаписываются.
|
|
607
|
+
* - Каждый вызов бампит `version` ("preview:<n>"), чтобы applyBootstrap'овая
|
|
608
|
+
* проверка `versionChanged` всегда срабатывала и listener'ы дёргались.
|
|
609
|
+
* - Persist в storage НЕ делаем — preview не должен утекать в другие вкладки.
|
|
610
|
+
*
|
|
611
|
+
* В non-preview режиме метод доступен, но это редкий путь (например, для
|
|
612
|
+
* тестов host'а) — production-код должен полагаться на bootstrap() + revalidate.
|
|
613
|
+
*/
|
|
614
|
+
setBootstrap(partial: Partial<PaywallBootstrap>): void;
|
|
549
615
|
private fetchBootstrap;
|
|
550
616
|
private revalidateBootstrap;
|
|
551
617
|
private applyBootstrap;
|
|
@@ -571,6 +637,13 @@ export declare class BillingClient {
|
|
|
571
637
|
}): Promise<PaywallPrice[]>;
|
|
572
638
|
/** Sync-снимок цен из последнего bootstrap'а. null = ещё не загружали. */
|
|
573
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;
|
|
574
647
|
/**
|
|
575
648
|
* Снимок того, какой язык SDK сейчас считает «языком юзера». Полезно для
|
|
576
649
|
* синхронизации i18n хоста с тем, что фактически показывает пейвол — чтобы
|
|
@@ -745,21 +818,31 @@ export declare class BillingClient {
|
|
|
745
818
|
* `/api/v1/paywall/[id]/user` без unstable_cache, потому что list для UI
|
|
746
819
|
* должен быть свежим после cancel-а.
|
|
747
820
|
*
|
|
748
|
-
* Auth
|
|
749
|
-
*
|
|
821
|
+
* Auth (два пути):
|
|
822
|
+
* - Bearer (через AuthClient) — user.id резолвится из сессии, identity
|
|
823
|
+
* в query игнорируется.
|
|
824
|
+
* - `apiKey` + `identity.email`/`identity.userId` — server-SDK путь для
|
|
825
|
+
* интеграций со своей авторизацией. Бэк проверяет, что identity линкована
|
|
826
|
+
* к этому пейволу (защита от cross-paywall lookup).
|
|
827
|
+
* Без auth и без apiKey+identity — `identity_required`.
|
|
750
828
|
*/
|
|
751
829
|
listPurchases(opts?: {
|
|
752
830
|
signal?: AbortSignal;
|
|
753
831
|
}): Promise<PaywallPurchaseDetailed[]>;
|
|
754
832
|
/**
|
|
755
|
-
* Отменить подписку. Бэк
|
|
756
|
-
*
|
|
757
|
-
*
|
|
833
|
+
* Отменить подписку. Бэк проверит, что subscription принадлежит юзеру
|
|
834
|
+
* (Bearer-путь — из сессии; apiKey-путь — из identity), и сделает cancel у
|
|
835
|
+
* acquiring'а (Stripe/Paddle/Chargebee/Overpay). По умолчанию cancel в
|
|
836
|
+
* конце текущего периода — юзер сохраняет access до renewal date'ы.
|
|
758
837
|
*
|
|
759
|
-
* `reason` обязательна (валидация на бэке).
|
|
760
|
-
* причин в host-UI, как в legacy customer portal'е.
|
|
838
|
+
* `reason` обязательна (валидация на бэке).
|
|
761
839
|
*
|
|
762
|
-
* Auth
|
|
840
|
+
* Auth (два пути):
|
|
841
|
+
* - Bearer (через AuthClient) — стандартный путь для UI customer-portal'a.
|
|
842
|
+
* - `apiKey` + `identity.email`/`identity.userId` — для self-service UI на
|
|
843
|
+
* бэке клиента со своей авторизацией. Бэк дополнительно фильтрует
|
|
844
|
+
* subscription по paywall_id, чтобы owner пейвола A не отменил подписку
|
|
845
|
+
* пейвола B.
|
|
763
846
|
*/
|
|
764
847
|
cancelSubscription(params: {
|
|
765
848
|
subscriptionId: string;
|
|
@@ -796,7 +879,15 @@ export declare class BillingClient {
|
|
|
796
879
|
|
|
797
880
|
export declare interface BillingClientOptions {
|
|
798
881
|
paywallId: string;
|
|
799
|
-
|
|
882
|
+
/**
|
|
883
|
+
* Origin серверного API SDK — обязательное поле. Должно совпадать с
|
|
884
|
+
* `custom_domain`, заданным для пейвола в платформе (модерация привязывает
|
|
885
|
+
* домен к paywall_id). SDK сверяет это значение с `bootstrap.settings.custom_domain`
|
|
886
|
+
* на первом ответе и кидает `invalid_config` при расхождении — защита от
|
|
887
|
+
* опечаток интегратора. Промежуточный `appbox.space` в новом SDK НЕ
|
|
888
|
+
* используется (это только для legacy v2).
|
|
889
|
+
*/
|
|
890
|
+
apiOrigin: string;
|
|
800
891
|
identity?: Identity;
|
|
801
892
|
storage?: StorageAdapter;
|
|
802
893
|
capabilities?: string[];
|
|
@@ -817,6 +908,16 @@ export declare interface BillingClientOptions {
|
|
|
817
908
|
* через `setIdentity`, Bearer не отправляется.
|
|
818
909
|
*/
|
|
819
910
|
auth?: AuthClient;
|
|
911
|
+
/**
|
|
912
|
+
* Preview/editor-mode. Когда true:
|
|
913
|
+
* - `bootstrap()` НЕ ходит в сеть — отдаёт только `cachedBootstrap`, заданный
|
|
914
|
+
* через `setBootstrap()`. Без seed'а throw'ает (caller обязан засидить до open).
|
|
915
|
+
* - Storage.watch / persist отключены (preview редактора локален для текущей вкладки).
|
|
916
|
+
* - `setBootstrap(partial)` доступен как публичный setter — host'у разрешено
|
|
917
|
+
* мутировать кеш для live-обновления модалки в редакторе админки.
|
|
918
|
+
* Дефолт false — обычный production-режим.
|
|
919
|
+
*/
|
|
920
|
+
preview?: boolean;
|
|
820
921
|
}
|
|
821
922
|
|
|
822
923
|
export declare type BlockComponent<B extends LayoutBlock = LayoutBlock> = ComponentType<BlockProps<B>>;
|
|
@@ -832,6 +933,10 @@ export declare interface BlockContext {
|
|
|
832
933
|
/** Текущая auth-session (snapshot из AuthClient). null = разлогинен. PaywallRoot
|
|
833
934
|
* подписан на onAuthChange и пробрасывает свежий snapshot сюда. */
|
|
834
935
|
authSession: AuthSession | null;
|
|
936
|
+
/** Стартовый mode для AuthPanel — переопределяет дефолт 'signin'.
|
|
937
|
+
* Выставляется AuthGate'ом когда host вызвал openSignup()/openSignin().
|
|
938
|
+
* Остальные блоки игнорируют. */
|
|
939
|
+
initialAuthMode?: 'signin' | 'signup';
|
|
835
940
|
}
|
|
836
941
|
|
|
837
942
|
export declare interface BlockProps<B extends LayoutBlock = LayoutBlock> {
|
|
@@ -894,6 +999,11 @@ export declare interface EventTrackerOptions {
|
|
|
894
999
|
sendBeacon?: (url: string, data: BodyInit) => boolean;
|
|
895
1000
|
}
|
|
896
1001
|
|
|
1002
|
+
/** Pick the offer applicable to a price. Targeted (`price_id === id`) wins
|
|
1003
|
+
* over the global default (`price_id === null`). Offers without a positive
|
|
1004
|
+
* `discount_percent` are ignored. */
|
|
1005
|
+
export declare function findApplicableOffer(offers: PaywallOffer[] | null | undefined, priceId: string): PaywallOffer | null;
|
|
1006
|
+
|
|
897
1007
|
export declare function generateVisitorId(): string;
|
|
898
1008
|
|
|
899
1009
|
export declare interface GetAccessOptions {
|
|
@@ -908,6 +1018,18 @@ export declare interface Identity {
|
|
|
908
1018
|
anonymousId?: string;
|
|
909
1019
|
}
|
|
910
1020
|
|
|
1021
|
+
export declare interface LastLogin {
|
|
1022
|
+
method: LastLoginMethod;
|
|
1023
|
+
email: string | null;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
/** Метод, которым юзер залогинился в последний раз на этом пейволе.
|
|
1027
|
+
* Хранится per-paywall в storage и используется UI чтобы:
|
|
1028
|
+
* - предзаполнить email-инпут last-known email'ом;
|
|
1029
|
+
* - подсветить ту же OAuth-кнопку / email-форму бейджем "Last used".
|
|
1030
|
+
* `email` — email/password forms (signin или signup → confirm). */
|
|
1031
|
+
export declare type LastLoginMethod = OAuthProvider | 'email';
|
|
1032
|
+
|
|
911
1033
|
export declare interface Layout {
|
|
912
1034
|
type: 'modal';
|
|
913
1035
|
blocks: LayoutBlock[];
|
|
@@ -923,9 +1045,13 @@ export declare type LayoutBlock = {
|
|
|
923
1045
|
} | {
|
|
924
1046
|
type: 'price_grid';
|
|
925
1047
|
priceIds?: string[];
|
|
926
|
-
/** Раскладка карточек
|
|
927
|
-
* `
|
|
928
|
-
|
|
1048
|
+
/** Раскладка карточек цен:
|
|
1049
|
+
* - `vertical` (default) — стек карточек сверху вниз;
|
|
1050
|
+
* - `compact` — компактный список (одна строка на цену, без карточки,
|
|
1051
|
+
* с разделителем); v2-аналог `view: 'telegram'`;
|
|
1052
|
+
* - `horizontal` — несколько карточек рядом в ряд; v2-only с момента
|
|
1053
|
+
* SDK 3.0 (legacy не показывает выбор этой опции в админке). */
|
|
1054
|
+
view?: 'vertical' | 'compact' | 'horizontal';
|
|
929
1055
|
/** ID цены, которая помечается лейблом «популярный план». v2-аналог
|
|
930
1056
|
* пары `price_label_id` + `price_label`. */
|
|
931
1057
|
popular_price_id?: string;
|
|
@@ -934,7 +1060,10 @@ export declare type LayoutBlock = {
|
|
|
934
1060
|
popular_label?: string;
|
|
935
1061
|
} | {
|
|
936
1062
|
type: 'cta_button';
|
|
937
|
-
|
|
1063
|
+
/** Текст на кнопке. Если не задан — рендерер сам подберёт по
|
|
1064
|
+
* selected price'у и `trial_days`: "Start N-Day Free Trial",
|
|
1065
|
+
* "Get Lifetime Access", "Get Monthly Plan" и т.п. */
|
|
1066
|
+
label?: string;
|
|
938
1067
|
action: 'checkout' | 'close';
|
|
939
1068
|
priceId?: string;
|
|
940
1069
|
} | {
|
|
@@ -953,8 +1082,23 @@ export declare type LayoutBlock = {
|
|
|
953
1082
|
/** Скрывать панель, если юзер уже залогинен. По умолчанию true.
|
|
954
1083
|
* false — показываем "Signed in as ... [Sign out]" даже после логина. */
|
|
955
1084
|
hide_when_authenticated?: boolean;
|
|
956
|
-
/**
|
|
1085
|
+
/** Кастомный заголовок над формой. Если задан — отображается вместо
|
|
1086
|
+
* дефолтного (определяется по mode'у — "Welcome back!" / "Welcome!" /
|
|
1087
|
+
* "Forgot password?" / ...). Без `submit_label` также используется как
|
|
1088
|
+
* submit-лейбл для signin (например `heading="Restore Purchases"` →
|
|
1089
|
+
* submit тоже "Restore Purchases"). Длинные heading (типа "Войдите,
|
|
1090
|
+
* чтобы продолжить покупку") в кнопку влезают плохо — задай
|
|
1091
|
+
* `submit_label` отдельно. */
|
|
957
1092
|
heading?: string;
|
|
1093
|
+
/** Подпись под заголовком. Если опущен — подставляется default-текст
|
|
1094
|
+
* для текущего mode'а. Передай пустую строку чтобы скрыть подпись. */
|
|
1095
|
+
subheading?: string;
|
|
1096
|
+
/** Явный текст submit-кнопки. Имеет приоритет над heading-эхо. Нужен
|
|
1097
|
+
* для интентов с длинным descriptive heading'ом (preauth: "Войдите,
|
|
1098
|
+
* чтобы продолжить покупку" — кнопка только "Войти"). Для коротких
|
|
1099
|
+
* action-headings (restore: "Restore Purchases") опускай — эхо
|
|
1100
|
+
* даёт правильный UX. */
|
|
1101
|
+
submit_label?: string;
|
|
958
1102
|
} | {
|
|
959
1103
|
/** Список фич/преимуществ продукта. v2-аналог `features_list` + `features_view`.
|
|
960
1104
|
* До 5 элементов — рендерим как чек-лист с заголовком и описанием. */
|
|
@@ -978,6 +1122,35 @@ export declare type LayoutBlock = {
|
|
|
978
1122
|
desc: string;
|
|
979
1123
|
count: number;
|
|
980
1124
|
}>;
|
|
1125
|
+
} | {
|
|
1126
|
+
/** Money-back guarantee badge под cta_button: иконка + жирный заголовок +
|
|
1127
|
+
* пояснение мелким шрифтом + bottom divider, который визуально стыкуется
|
|
1128
|
+
* с current_session ниже. v2-аналог inline-блока в `PaywallPricing`. */
|
|
1129
|
+
type: 'guarantee_badge';
|
|
1130
|
+
/** Заголовок жирным. По умолчанию "100% Money-Back Guarantee". */
|
|
1131
|
+
title?: string;
|
|
1132
|
+
/** Подзаголовок мелким серым. По умолчанию
|
|
1133
|
+
* "Not satisfied? We'll refund you — no questions asked.". */
|
|
1134
|
+
subtitle?: string;
|
|
1135
|
+
/** Иконка слева от заголовка. По умолчанию `dollar_shield` —
|
|
1136
|
+
* зелёный shield с долларом (legacy-вид). `none` — без иконки. */
|
|
1137
|
+
icon?: 'dollar_shield' | 'none';
|
|
1138
|
+
} | {
|
|
1139
|
+
/** Urgency-баннер с countdown'ом до конца offer'а. Берёт первый offer
|
|
1140
|
+
* из `bootstrap.offers` с валидным `expires_at` или `duration_minutes`.
|
|
1141
|
+
* Авто-скрывается по истечении, чтобы не показывать "0d 0h 0m 0s".
|
|
1142
|
+
* Размещение — обычно первый блок в layout (над heading). */
|
|
1143
|
+
type: 'offer_banner';
|
|
1144
|
+
/** ID конкретного offer'а из bootstrap.offers. Если не задано — берётся
|
|
1145
|
+
* первый offer с активным таймером. */
|
|
1146
|
+
offer_id?: string;
|
|
1147
|
+
/** Текст слева от countdown'а. Если опущен — берётся `offer.label`,
|
|
1148
|
+
* иначе fallback "Limited-time offer". К нему дописывается процент:
|
|
1149
|
+
* "{title} {discount_percent}%" если discount задан. */
|
|
1150
|
+
title?: string;
|
|
1151
|
+
/** В превью админки — игнорировать expired-state, всё равно показывать
|
|
1152
|
+
* banner с нулями. Прод-режим — false (banner исчезает). */
|
|
1153
|
+
force?: boolean;
|
|
981
1154
|
};
|
|
982
1155
|
|
|
983
1156
|
/** Локализационные оверрайды для одного языка. Накатываются поверх дефолтного
|
|
@@ -997,6 +1170,11 @@ export declare interface LocaleOverrides {
|
|
|
997
1170
|
|
|
998
1171
|
export declare type OAuthProvider = 'google' | 'apple' | 'github' | 'facebook';
|
|
999
1172
|
|
|
1173
|
+
/** Storage key under which a relative `duration_minutes` offer records its
|
|
1174
|
+
* first-view timestamp. Shared between the renderer (which writes the
|
|
1175
|
+
* start on first open) and the host SDK helpers (which read it). */
|
|
1176
|
+
export declare function offerStartStorageKey(offerId: string): string;
|
|
1177
|
+
|
|
1000
1178
|
export declare interface OpenOptions {
|
|
1001
1179
|
identity?: Identity;
|
|
1002
1180
|
/** Принудительно открыть, минуя pre-paywall trial check. По умолчанию SDK
|
|
@@ -1137,9 +1315,19 @@ declare interface PaywallEventPayloads {
|
|
|
1137
1315
|
/** User-state изменился (bootstrap snapshot, getUser refresh, watcher tick).
|
|
1138
1316
|
* Дёргается также сразу с last-known user после первой подписки. */
|
|
1139
1317
|
userChange: PaywallUser;
|
|
1140
|
-
/** Auth-session
|
|
1141
|
-
*
|
|
1142
|
-
|
|
1318
|
+
/** Auth-session изменилась. Payload содержит `event` (см. AuthChangeEvent —
|
|
1319
|
+
* INITIAL_SESSION / SIGNED_IN / SIGNED_OUT / TOKEN_REFRESHED / USER_UPDATED /
|
|
1320
|
+
* PASSWORD_RECOVERY) и `session` (null = разлогинен).
|
|
1321
|
+
*
|
|
1322
|
+
* Гарантированный контракт: первый callback каждому subscriber'у — всегда
|
|
1323
|
+
* INITIAL_SESSION с восстановленной из storage сессией (или null если нет).
|
|
1324
|
+
* Дальше — реальные переходы. Listener'у с побочными эффектами вроде
|
|
1325
|
+
* force-refetch balances ловить SIGNED_IN, а не любой truthy session,
|
|
1326
|
+
* иначе reload страницы будет триггерить лишний запрос. */
|
|
1327
|
+
authChange: {
|
|
1328
|
+
event: AuthChangeEvent;
|
|
1329
|
+
session: AuthSession | null;
|
|
1330
|
+
};
|
|
1143
1331
|
/** Триал заблокировал показ модалки. payload содержит свежий статус (после
|
|
1144
1332
|
* recordBlock). Для `mode: 'time'` — startedAt/expiresAt/remainingMs;
|
|
1145
1333
|
* для `mode: 'opens'` — remainingActions/totalActions. Хост может
|
|
@@ -1159,7 +1347,15 @@ declare interface PaywallEventPayloads {
|
|
|
1159
1347
|
export declare interface PaywallOffer {
|
|
1160
1348
|
id: string;
|
|
1161
1349
|
discount_percent: number | null;
|
|
1350
|
+
/** Абсолютная expiration date (ISO 8601). Если задана — countdown отсчитывает
|
|
1351
|
+
* до этого момента, по истечении offer считается истёкшим. */
|
|
1162
1352
|
expires_at: string | null;
|
|
1353
|
+
/** Относительный таймер: сколько минут offer живёт **от первого просмотра
|
|
1354
|
+
* пейвола** данным юзером. Старт хранится в clientStorage под ключом
|
|
1355
|
+
* `pw-offer-{id}-start`, по истечении — auto-cleanup. Используется, когда
|
|
1356
|
+
* бэк хочет показывать "remaining time" без жёсткой server-time, а считать
|
|
1357
|
+
* относительно сессии юзера. expires_at имеет приоритет если задано. */
|
|
1358
|
+
duration_minutes?: number | null;
|
|
1163
1359
|
price_id: string | null;
|
|
1164
1360
|
label?: string | null;
|
|
1165
1361
|
}
|
|
@@ -1209,6 +1405,14 @@ export declare interface PaywallSettings {
|
|
|
1209
1405
|
brand_color?: string | null;
|
|
1210
1406
|
custom_css?: string | null;
|
|
1211
1407
|
locale_default?: string | null;
|
|
1408
|
+
/** Origin, на котором живёт бэк пейвола (тот же, что мерчант передаёт в
|
|
1409
|
+
* `BillingClientOptions.apiOrigin` при инициализации SDK). Бэк присылает
|
|
1410
|
+
* его на каждом bootstrap'е, SDK сверяет с init.apiOrigin — расхождение
|
|
1411
|
+
* даёт `invalid_config` (защита от опечатки интегратора). Без схемы:
|
|
1412
|
+
* "pay.your-domain.com" или "https://pay.your-domain.com" — оба валидны.
|
|
1413
|
+
* Для новых пейволов поле всегда заполнено (модерация требует custom_domain);
|
|
1414
|
+
* для legacy v2 может быть null/undefined. */
|
|
1415
|
+
custom_domain?: string | null;
|
|
1212
1416
|
runtime_mode?: 'client' | 'hybrid' | 'server' | 'client-native' | 'hybrid-native';
|
|
1213
1417
|
/** true, если эквайринг пейвола в test-mode — SDK рисует TEST MODE бейдж. */
|
|
1214
1418
|
is_test_mode?: boolean;
|
|
@@ -1268,7 +1472,7 @@ export declare interface PaywallStateSnapshot {
|
|
|
1268
1472
|
/** Модалка отрендерена и видна. False — closed (или ещё не открывалась). */
|
|
1269
1473
|
open: boolean;
|
|
1270
1474
|
/** Что показывается в модалке. null когда `open=false`. */
|
|
1271
|
-
view: 'loading' | 'error' | 'layout' | 'auth' | '
|
|
1475
|
+
view: 'loading' | 'error' | 'layout' | 'auth' | 'support' | 'awaiting_payment' | 'popup_blocked' | 'purchased' | null;
|
|
1272
1476
|
/** Заполнено только когда `view === 'error'`. */
|
|
1273
1477
|
error: PaywallError | null;
|
|
1274
1478
|
}
|
|
@@ -1305,6 +1509,10 @@ export declare class PaywallUI {
|
|
|
1305
1509
|
private lastVisibility;
|
|
1306
1510
|
/** Поведение open() при холодном bootstrap'е. См. PaywallUIOptions.mountThenLoad. */
|
|
1307
1511
|
private mountThenLoad;
|
|
1512
|
+
/** Inline-режим (live-preview редактора). См. PaywallUIOptions.inline. */
|
|
1513
|
+
private inline;
|
|
1514
|
+
/** Force-locale для I18nProvider. См. PaywallUIOptions.locale. */
|
|
1515
|
+
private forceLocale;
|
|
1308
1516
|
/** Текущий snapshot UI state-machine. Обновляется PaywallRoot'ом через
|
|
1309
1517
|
* `onState` prop; при close сбрасывается обратно в CLOSED_STATE. */
|
|
1310
1518
|
private currentState;
|
|
@@ -1327,6 +1535,26 @@ export declare class PaywallUI {
|
|
|
1327
1535
|
* last-known user из кеша синхронно через microtask, если он есть.
|
|
1328
1536
|
*/
|
|
1329
1537
|
onUserChange(handler: PaywallEventHandler<'userChange'>): () => void;
|
|
1538
|
+
/**
|
|
1539
|
+
* Заменить cachedBootstrap живыми данными — для preview-режима в редакторе
|
|
1540
|
+
* админки. Если модалка открыта, PaywallRoot подписан на onBootstrapChange
|
|
1541
|
+
* и перерендерится мгновенно. До open() — затравка для bootstrap()-effect'а.
|
|
1542
|
+
*
|
|
1543
|
+
* См. {@link BillingClientOptions.preview} — обычно эту опцию ставят на
|
|
1544
|
+
* клиент, чтобы заодно отключить сетевой revalidate. setBootstrap технически
|
|
1545
|
+
* работает и в production-режиме, но конкуренция с revalidate'ом из сети
|
|
1546
|
+
* почти всегда нежелательна.
|
|
1547
|
+
*/
|
|
1548
|
+
setBootstrap(partial: Partial<PaywallBootstrap>): void;
|
|
1549
|
+
/**
|
|
1550
|
+
* Сменить force-locale на лету — для live-preview редактора админки, когда
|
|
1551
|
+
* юзер переключает «Preview as user from <country>». Грузит соответствующий
|
|
1552
|
+
* static-чанк и форсит re-render через handle.update. См. PaywallUIOptions.locale.
|
|
1553
|
+
*
|
|
1554
|
+
* Передай `null`/`undefined`, чтобы вернуть автоматическую резолв-логику
|
|
1555
|
+
* (navigator.language → locale_default).
|
|
1556
|
+
*/
|
|
1557
|
+
setLocale(locale: string | null | undefined): void;
|
|
1330
1558
|
on<E extends PaywallEvent>(event: E, handler: PaywallEventHandler<E>): () => void;
|
|
1331
1559
|
off<E extends PaywallEvent>(event: E, handler: PaywallEventHandler<E>): void;
|
|
1332
1560
|
private emit;
|
|
@@ -1371,23 +1599,34 @@ export declare class PaywallUI {
|
|
|
1371
1599
|
*/
|
|
1372
1600
|
openAuth(opts?: OpenOptions): void;
|
|
1373
1601
|
/**
|
|
1374
|
-
*
|
|
1375
|
-
* `
|
|
1376
|
-
*
|
|
1377
|
-
*
|
|
1378
|
-
*
|
|
1379
|
-
*
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
*
|
|
1384
|
-
*
|
|
1602
|
+
* Шорткат над `openAuth()` — открывает модалку сразу на signin-форме.
|
|
1603
|
+
* Эквивалент `openAuth()` (signin — дефолт). Существует для симметрии с
|
|
1604
|
+
* `openSignup()` и читаемости host-кода:
|
|
1605
|
+
* - `paywall.openSignin()` — «вход в существующий аккаунт»
|
|
1606
|
+
* - `paywall.openSignup()` — «новая регистрация»
|
|
1607
|
+
* Без managed-auth — no-op.
|
|
1608
|
+
*/
|
|
1609
|
+
openSignin(opts?: OpenOptions): void;
|
|
1610
|
+
/**
|
|
1611
|
+
* Открывает модалку с auth-gate сразу в режиме регистрации (signup-mode
|
|
1612
|
+
* AuthPanel'а — email/password/repeat). Если в paywall layout админ
|
|
1613
|
+
* отключил allow_signup, AuthPanel игнорит mode и стартует с signin —
|
|
1614
|
+
* соблюдается admin-конфиг.
|
|
1615
|
+
* Без managed-auth — no-op.
|
|
1616
|
+
*/
|
|
1617
|
+
openSignup(opts?: OpenOptions): void;
|
|
1618
|
+
/**
|
|
1619
|
+
* Headless anonymous signin без открытия модалки. Внутри:
|
|
1620
|
+
* idempotent (если уже анон — instant return) → resume через сохранённый
|
|
1621
|
+
* refresh_token → fresh /auth/anonymous/signin. Дедуплицирует
|
|
1622
|
+
* параллельные вызовы внутри AuthClient'а.
|
|
1385
1623
|
*
|
|
1386
|
-
*
|
|
1387
|
-
*
|
|
1388
|
-
*
|
|
1624
|
+
* Удобно для host-кнопок типа «Continue as guest» — host сам управляет
|
|
1625
|
+
* loading-стейтом на своей кнопке, без полупустой модалки со спиннером.
|
|
1626
|
+
* Без managed-auth — резолвится rejected promise'ом (нет AuthClient'а
|
|
1627
|
+
* чтобы делать signin).
|
|
1389
1628
|
*/
|
|
1390
|
-
|
|
1629
|
+
signInAnonymously(): Promise<AuthSession>;
|
|
1391
1630
|
private openInternal;
|
|
1392
1631
|
/** Применить gates ПОСЛЕ того, как модалка уже смонтирована (mount-then-load
|
|
1393
1632
|
* путь). Если gate блокирует — close() + emit. Если юзер уже сам закрыл
|
|
@@ -1442,6 +1681,26 @@ export declare class PaywallUI {
|
|
|
1442
1681
|
}): Promise<PaywallPrice[]>;
|
|
1443
1682
|
/** Sync-снимок цен. null — bootstrap ещё не загружали. */
|
|
1444
1683
|
getCachedPrices(): PaywallPrice[] | null;
|
|
1684
|
+
/** Sync-снимок офферов. null = bootstrap не загружали, [] = пейвол без офферов.
|
|
1685
|
+
* Бэк уже применил серверный targeting (страны/email/режим) — наружу
|
|
1686
|
+
* выезжает только то, что применимо к текущему юзеру. */
|
|
1687
|
+
getCachedOffers(): PaywallOffer[] | null;
|
|
1688
|
+
/**
|
|
1689
|
+
* Резолвит активный offer для конкретной цены: price_id-таргетинг +
|
|
1690
|
+
* countdown (`expires_at` ИЛИ `duration_minutes` от первого открытия
|
|
1691
|
+
* пейвола, см. clientStorage `pw-offer-{id}-start`).
|
|
1692
|
+
*
|
|
1693
|
+
* Read-only — НЕ записывает start для `duration_minutes`-офферов. Запись
|
|
1694
|
+
* стартует только когда модалка реально открыта (renderer'ом). До этого
|
|
1695
|
+
* `getOfferForPrice` вернёт `null` для duration-only офферов, чтобы
|
|
1696
|
+
* страницы-хосты вне модалки (pricing, landing) не активировали countdown
|
|
1697
|
+
* раньше времени.
|
|
1698
|
+
*
|
|
1699
|
+
* Хост-странице нужен countdown, который тикает каждую секунду — для
|
|
1700
|
+
* этого использовать React-хук `usePaywallOffer(priceId)` из sdk-react
|
|
1701
|
+
* либо обёртку поверх `setInterval(1000)` + повторный вызов этого метода.
|
|
1702
|
+
*/
|
|
1703
|
+
getOfferForPrice(priceId: string): ResolvedOffer | null;
|
|
1445
1704
|
/** Снимок текущего «языка юзера» — proxy над `billing.getUserLanguage()`.
|
|
1446
1705
|
* Используй, чтобы синхронизировать i18n host'а с тем, что фактически
|
|
1447
1706
|
* показывает пейвол. См. подробности в `BillingClient.getUserLanguage`. */
|
|
@@ -1518,6 +1777,8 @@ export declare interface PaywallUIOptions extends Omit<BillingClientOptions, 'au
|
|
|
1518
1777
|
* флеш на blocked-странах/устройствах хуже воспринимаемой латентности.
|
|
1519
1778
|
*/
|
|
1520
1779
|
mountThenLoad?: boolean;
|
|
1780
|
+
/* Excluded from this release type: inline */
|
|
1781
|
+
/* Excluded from this release type: locale */
|
|
1521
1782
|
}
|
|
1522
1783
|
|
|
1523
1784
|
export declare interface PaywallUser {
|
|
@@ -1529,6 +1790,12 @@ export declare interface PaywallUser {
|
|
|
1529
1790
|
started_at: string | null;
|
|
1530
1791
|
expires_at: string | null;
|
|
1531
1792
|
} | null;
|
|
1793
|
+
/** Был ли у юзера хотя бы один trial по этому пейволу когда-либо (включая
|
|
1794
|
+
* истёкшие и отменённые). Anti-abuse флаг для UI: CtaButton скрывает
|
|
1795
|
+
* "Start N-Day Free Trial" если true. Серверный enforcement в
|
|
1796
|
+
* `/start-checkout` дублирует — даже если UI обмануть, бэк не отдаст
|
|
1797
|
+
* trial_days в Stripe/Paddle. */
|
|
1798
|
+
had_previous_trial: boolean;
|
|
1532
1799
|
}
|
|
1533
1800
|
|
|
1534
1801
|
export declare interface PaywallUserPurchase {
|
|
@@ -1553,6 +1820,51 @@ export declare class QuotaExceededError extends PaywallError {
|
|
|
1553
1820
|
});
|
|
1554
1821
|
}
|
|
1555
1822
|
|
|
1823
|
+
/** Safe browser localStorage getter — returns null in SSR / private mode. */
|
|
1824
|
+
export declare function readBrowserOfferStart(offerId: string): string | null;
|
|
1825
|
+
|
|
1826
|
+
/**
|
|
1827
|
+
* Resolved view of a paywall offer — what host UI actually needs to render
|
|
1828
|
+
* a strike-through price + countdown without re-implementing the math.
|
|
1829
|
+
*
|
|
1830
|
+
* `remainingMs` ticks down with wall-clock time and reaches 0 on expiry.
|
|
1831
|
+
* `totalMs` stays constant — useful for progress bars / share-of-time UX.
|
|
1832
|
+
* `expiresAt` is the Date.now()-comparable epoch ms of expiry.
|
|
1833
|
+
*
|
|
1834
|
+
* For offers without an expiry mechanism (no `expires_at` and no
|
|
1835
|
+
* `duration_minutes`), `remainingMs`/`totalMs`/`expiresAt` are all `null`,
|
|
1836
|
+
* but the resolved view is still returned — discount badge / strike-through
|
|
1837
|
+
* still make sense for "perpetual sale" offers.
|
|
1838
|
+
*/
|
|
1839
|
+
export declare interface ResolvedOffer {
|
|
1840
|
+
offer: PaywallOffer;
|
|
1841
|
+
discountPercent: number;
|
|
1842
|
+
remainingMs: number | null;
|
|
1843
|
+
totalMs: number | null;
|
|
1844
|
+
expiresAt: number | null;
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
/** Compute the resolved view of an offer. Pure, no side-effects. */
|
|
1848
|
+
export declare function resolveOffer(offer: PaywallOffer, opts?: ResolveOfferOptions): ResolvedOffer | null;
|
|
1849
|
+
|
|
1850
|
+
export declare interface ResolveOfferOptions {
|
|
1851
|
+
/** Current epoch ms. Inject for deterministic tests; default `Date.now()`. */
|
|
1852
|
+
now?: number;
|
|
1853
|
+
/**
|
|
1854
|
+
* Synchronous reader for the `duration_minutes` start-timestamp ISO string.
|
|
1855
|
+
* Host passes a closure over its sync storage (browser → `localStorage`,
|
|
1856
|
+
* memory → in-process map). Return `null` if no start has been recorded.
|
|
1857
|
+
*
|
|
1858
|
+
* Intentionally synchronous, because consumers call this from UI render —
|
|
1859
|
+
* an async StorageAdapter would force every price card to suspend.
|
|
1860
|
+
*
|
|
1861
|
+
* If omitted, `duration_minutes`-only offers return `expiresAt = null`,
|
|
1862
|
+
* which makes the resolved view treat them as "not yet started" (the
|
|
1863
|
+
* renderer is responsible for writing the start on first paywall view).
|
|
1864
|
+
*/
|
|
1865
|
+
readStart?: (offerId: string) => string | null;
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1556
1868
|
export declare const SDK_VERSION = "3.0.0-alpha.0";
|
|
1557
1869
|
|
|
1558
1870
|
export declare type SignUpResult = {
|