@monetize.software/sdk 3.0.0-alpha.3 → 3.0.0-alpha.5

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.
Files changed (128) hide show
  1. package/dist/chunks/PaywallUI-BD5hRY2P.js +26 -0
  2. package/dist/chunks/PaywallUI-BD5hRY2P.js.map +1 -0
  3. package/dist/chunks/PaywallUI-D7lp-bC5.js +3206 -0
  4. package/dist/chunks/PaywallUI-D7lp-bC5.js.map +1 -0
  5. package/dist/chunks/ar-BCHXVoE2.js +114 -0
  6. package/dist/chunks/ar-BCHXVoE2.js.map +1 -0
  7. package/dist/chunks/ar-CsJNZJSr.js +2 -0
  8. package/dist/chunks/ar-CsJNZJSr.js.map +1 -0
  9. package/dist/chunks/cs-B5NqpTW_.js +110 -0
  10. package/dist/chunks/cs-B5NqpTW_.js.map +1 -0
  11. package/dist/chunks/cs-BydWUC0e.js +2 -0
  12. package/dist/chunks/cs-BydWUC0e.js.map +1 -0
  13. package/dist/chunks/da-BJrGZ3LD.js +110 -0
  14. package/dist/chunks/da-BJrGZ3LD.js.map +1 -0
  15. package/dist/chunks/da-DNhiAQnh.js +2 -0
  16. package/dist/chunks/da-DNhiAQnh.js.map +1 -0
  17. package/dist/chunks/de-H8ztFOie.js +2 -0
  18. package/dist/chunks/de-H8ztFOie.js.map +1 -0
  19. package/dist/chunks/de-aepBKwsb.js +130 -0
  20. package/dist/chunks/de-aepBKwsb.js.map +1 -0
  21. package/dist/chunks/el-DRfoadtI.js +2 -0
  22. package/dist/chunks/el-DRfoadtI.js.map +1 -0
  23. package/dist/chunks/el-DTLQoX2D.js +114 -0
  24. package/dist/chunks/el-DTLQoX2D.js.map +1 -0
  25. package/dist/chunks/es-CLutF-D_.js +130 -0
  26. package/dist/chunks/es-CLutF-D_.js.map +1 -0
  27. package/dist/chunks/es-GlaYesNR.js +2 -0
  28. package/dist/chunks/es-GlaYesNR.js.map +1 -0
  29. package/dist/chunks/fi-BIHFyScH.js +2 -0
  30. package/dist/chunks/fi-BIHFyScH.js.map +1 -0
  31. package/dist/chunks/fi-DZ4csxqk.js +110 -0
  32. package/dist/chunks/fi-DZ4csxqk.js.map +1 -0
  33. package/dist/chunks/fr-BtZILUNZ.js +2 -0
  34. package/dist/chunks/fr-BtZILUNZ.js.map +1 -0
  35. package/dist/chunks/fr-jJU1SSpj.js +130 -0
  36. package/dist/chunks/fr-jJU1SSpj.js.map +1 -0
  37. package/dist/chunks/he-D9obGPNj.js +114 -0
  38. package/dist/chunks/he-D9obGPNj.js.map +1 -0
  39. package/dist/chunks/he-vSDRE4Nn.js +2 -0
  40. package/dist/chunks/he-vSDRE4Nn.js.map +1 -0
  41. package/dist/chunks/hi-B90FsnP6.js +2 -0
  42. package/dist/chunks/hi-B90FsnP6.js.map +1 -0
  43. package/dist/chunks/hi-pM8SQwZ3.js +114 -0
  44. package/dist/chunks/hi-pM8SQwZ3.js.map +1 -0
  45. package/dist/chunks/hu-DWVFODsS.js +2 -0
  46. package/dist/chunks/hu-DWVFODsS.js.map +1 -0
  47. package/dist/chunks/hu-E0m9WgbD.js +110 -0
  48. package/dist/chunks/hu-E0m9WgbD.js.map +1 -0
  49. package/dist/chunks/id-C6poPvby.js +110 -0
  50. package/dist/chunks/id-C6poPvby.js.map +1 -0
  51. package/dist/chunks/id-Ce2gzMVT.js +2 -0
  52. package/dist/chunks/id-Ce2gzMVT.js.map +1 -0
  53. package/dist/chunks/it-B2RSFyVd.js +130 -0
  54. package/dist/chunks/it-B2RSFyVd.js.map +1 -0
  55. package/dist/chunks/it-u-Gu44bl.js +2 -0
  56. package/dist/chunks/it-u-Gu44bl.js.map +1 -0
  57. package/dist/chunks/ja-CM-VgVG6.js +134 -0
  58. package/dist/chunks/ja-CM-VgVG6.js.map +1 -0
  59. package/dist/chunks/ja-CQy8RaRa.js +2 -0
  60. package/dist/chunks/ja-CQy8RaRa.js.map +1 -0
  61. package/dist/chunks/ko-BRnb7vJ7.js +2 -0
  62. package/dist/chunks/ko-BRnb7vJ7.js.map +1 -0
  63. package/dist/chunks/ko-C451fA21.js +134 -0
  64. package/dist/chunks/ko-C451fA21.js.map +1 -0
  65. package/dist/chunks/nl-CJelco6J.js +2 -0
  66. package/dist/chunks/nl-CJelco6J.js.map +1 -0
  67. package/dist/chunks/nl-DzQfJPo2.js +130 -0
  68. package/dist/chunks/nl-DzQfJPo2.js.map +1 -0
  69. package/dist/chunks/no-B51be8KT.js +110 -0
  70. package/dist/chunks/no-B51be8KT.js.map +1 -0
  71. package/dist/chunks/no-BwTjSZ4K.js +2 -0
  72. package/dist/chunks/no-BwTjSZ4K.js.map +1 -0
  73. package/dist/chunks/pl-5rTEkvfY.js +110 -0
  74. package/dist/chunks/pl-5rTEkvfY.js.map +1 -0
  75. package/dist/chunks/pl-kO82vcjb.js +2 -0
  76. package/dist/chunks/pl-kO82vcjb.js.map +1 -0
  77. package/dist/chunks/pt-CsJzaSjg.js +2 -0
  78. package/dist/chunks/pt-CsJzaSjg.js.map +1 -0
  79. package/dist/chunks/pt-JwqffZ9u.js +130 -0
  80. package/dist/chunks/pt-JwqffZ9u.js.map +1 -0
  81. package/dist/chunks/ro-BE_wJ1td.js +110 -0
  82. package/dist/chunks/ro-BE_wJ1td.js.map +1 -0
  83. package/dist/chunks/ro-ue15Ina4.js +2 -0
  84. package/dist/chunks/ro-ue15Ina4.js.map +1 -0
  85. package/dist/chunks/ru-B1iMOhX0.js +2 -0
  86. package/dist/chunks/ru-B1iMOhX0.js.map +1 -0
  87. package/dist/chunks/ru-BviATvLb.js +124 -0
  88. package/dist/chunks/ru-BviATvLb.js.map +1 -0
  89. package/dist/chunks/sv-CkNYpUVy.js +2 -0
  90. package/dist/chunks/sv-CkNYpUVy.js.map +1 -0
  91. package/dist/chunks/sv-DabGF9WL.js +110 -0
  92. package/dist/chunks/sv-DabGF9WL.js.map +1 -0
  93. package/dist/chunks/th-BiF-bNo0.js +114 -0
  94. package/dist/chunks/th-BiF-bNo0.js.map +1 -0
  95. package/dist/chunks/th-Cu80HK4y.js +2 -0
  96. package/dist/chunks/th-Cu80HK4y.js.map +1 -0
  97. package/dist/chunks/tr-B7c0afXV.js +2 -0
  98. package/dist/chunks/tr-B7c0afXV.js.map +1 -0
  99. package/dist/chunks/tr-xZuly8X8.js +110 -0
  100. package/dist/chunks/tr-xZuly8X8.js.map +1 -0
  101. package/dist/chunks/uk-BO106B0H.js +2 -0
  102. package/dist/chunks/uk-BO106B0H.js.map +1 -0
  103. package/dist/chunks/uk-KlkAaHuy.js +124 -0
  104. package/dist/chunks/uk-KlkAaHuy.js.map +1 -0
  105. package/dist/chunks/vi-BVCeumNE.js +110 -0
  106. package/dist/chunks/vi-BVCeumNE.js.map +1 -0
  107. package/dist/chunks/vi-CZ6ow40D.js +2 -0
  108. package/dist/chunks/vi-CZ6ow40D.js.map +1 -0
  109. package/dist/chunks/zh-BhP80WI1.js +2 -0
  110. package/dist/chunks/zh-BhP80WI1.js.map +1 -0
  111. package/dist/chunks/zh-C_ghwmqi.js +134 -0
  112. package/dist/chunks/zh-C_ghwmqi.js.map +1 -0
  113. package/dist/core.cjs +1 -1
  114. package/dist/core.cjs.map +1 -1
  115. package/dist/core.d.ts +152 -11
  116. package/dist/core.js +433 -348
  117. package/dist/core.js.map +1 -1
  118. package/dist/index.cjs +1 -1
  119. package/dist/index.d.ts +166 -22
  120. package/dist/index.js +1 -1
  121. package/dist/ui.cjs +1 -1
  122. package/dist/ui.d.ts +166 -22
  123. package/dist/ui.js +1 -1
  124. package/package.json +32 -31
  125. package/dist/chunks/PaywallUI-BWU_1hsh.js +0 -26
  126. package/dist/chunks/PaywallUI-BWU_1hsh.js.map +0 -1
  127. package/dist/chunks/PaywallUI-C3W0eKDo.js +0 -2233
  128. package/dist/chunks/PaywallUI-C3W0eKDo.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
- apiOrigin?: string;
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
- export declare type AuthChangeListener = (session: AuthSession | null) => void;
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;
@@ -385,8 +408,19 @@ export declare class AuthClient {
385
408
  }): Promise<void>;
386
409
  /**
387
410
  * Подписка на изменения session: signin/signup/refresh/signOut/expired-401.
388
- * Колбек вызывается с текущим snapshot через microtask (если session есть)
389
- * + на каждое реальное изменение. Возвращает unsubscribe.
411
+ *
412
+ * Гарантированный контракт: ПЕРВЫЙ callback каждому subscriber'у — всегда
413
+ * `event = 'INITIAL_SESSION'`, дёргается асинхронно после resolve hydrate'а
414
+ * (даже если session=null — listener получает explicit «нет сессии», а не
415
+ * молчание). Все последующие callback'и — реальные переходы с конкретным
416
+ * event'ом (SIGNED_IN / SIGNED_OUT / TOKEN_REFRESHED / USER_UPDATED /
417
+ * PASSWORD_RECOVERY).
418
+ *
419
+ * Это позволяет listener'у безопасно делать «only on real signin» побочные
420
+ * эффекты (force refetch balances и т.п.) через `event === 'SIGNED_IN'`,
421
+ * не путая их с восстановлением из storage.
422
+ *
423
+ * Возвращает unsubscribe.
390
424
  */
391
425
  onAuthChange(cb: AuthChangeListener): () => void;
392
426
  private isFresh;
@@ -412,6 +446,18 @@ export declare class AuthClient {
412
446
  private readAnonRefreshToken;
413
447
  private writeAnonRefreshToken;
414
448
  private clearAnonRefreshToken;
449
+ /**
450
+ * Last-used auth method + email — для UI бейджа "Last used" и pre-fill'а
451
+ * email-инпута. Storage paywall-scoped, поэтому переключение между
452
+ * пейволами на одном host'е не пересекает данные. Чтение всегда возвращает
453
+ * объект — отсутствующие поля = null. */
454
+ getLastLogin(): Promise<LastLogin | null>;
455
+ /** Запись method и email атомарно (для email/password flows — оба известны
456
+ * на момент signin/signup'а). OAuth-flows используют раздельные
457
+ * recordLastLoginMethod (до popup) и recordLastLoginEmail (после exchange). */
458
+ private recordLastLogin;
459
+ private recordLastLoginMethod;
460
+ private recordLastLoginEmail;
415
461
  /**
416
462
  * Читает stable visitor_id из storage если он там уже есть. НЕ генерит:
417
463
  * AuthClient может быть инстанцирован раньше BillingClient, а синтетический
@@ -424,7 +470,9 @@ export declare class AuthClient {
424
470
 
425
471
  export declare interface AuthClientOptions {
426
472
  paywallId: string;
427
- apiOrigin?: string;
473
+ /** Origin серверного API SDK — обязательное поле, тот же `custom_domain`, что
474
+ * у BillingClient. См. {@link BillingClientOptions.apiOrigin}. */
475
+ apiOrigin: string;
428
476
  storage?: StorageAdapter;
429
477
  fetch?: typeof fetch;
430
478
  openPopup?: (url: string, name: string) => Window | null;
@@ -789,7 +837,15 @@ export declare class BillingClient {
789
837
 
790
838
  export declare interface BillingClientOptions {
791
839
  paywallId: string;
792
- apiOrigin?: string;
840
+ /**
841
+ * Origin серверного API SDK — обязательное поле. Должно совпадать с
842
+ * `custom_domain`, заданным для пейвола в платформе (модерация привязывает
843
+ * домен к paywall_id). SDK сверяет это значение с `bootstrap.settings.custom_domain`
844
+ * на первом ответе и кидает `invalid_config` при расхождении — защита от
845
+ * опечаток интегратора. Промежуточный `appbox.space` в новом SDK НЕ
846
+ * используется (это только для legacy v2).
847
+ */
848
+ apiOrigin: string;
793
849
  identity?: Identity;
794
850
  storage?: StorageAdapter;
795
851
  capabilities?: string[];
@@ -883,6 +939,18 @@ export declare interface Identity {
883
939
  anonymousId?: string;
884
940
  }
885
941
 
942
+ export declare interface LastLogin {
943
+ method: LastLoginMethod;
944
+ email: string | null;
945
+ }
946
+
947
+ /** Метод, которым юзер залогинился в последний раз на этом пейволе.
948
+ * Хранится per-paywall в storage и используется UI чтобы:
949
+ * - предзаполнить email-инпут last-known email'ом;
950
+ * - подсветить ту же OAuth-кнопку / email-форму бейджем "Last used".
951
+ * `email` — email/password forms (signin или signup → confirm). */
952
+ export declare type LastLoginMethod = OAuthProvider | 'email';
953
+
886
954
  export declare interface Layout {
887
955
  type: 'modal';
888
956
  blocks: LayoutBlock[];
@@ -898,9 +966,13 @@ export declare type LayoutBlock = {
898
966
  } | {
899
967
  type: 'price_grid';
900
968
  priceIds?: string[];
901
- /** Раскладка карточек цен. `vertical` (default) — стек сверху вниз;
902
- * `horizontal` — ряд side-by-side. v2-аналог `view: 'default' | 'telegram'`. */
903
- view?: 'vertical' | 'horizontal';
969
+ /** Раскладка карточек цен:
970
+ * - `vertical` (default) стек карточек сверху вниз;
971
+ * - `compact` компактный список (одна строка на цену, без карточки,
972
+ * с разделителем); v2-аналог `view: 'telegram'`;
973
+ * - `horizontal` — несколько карточек рядом в ряд; v2-only с момента
974
+ * SDK 3.0 (legacy не показывает выбор этой опции в админке). */
975
+ view?: 'vertical' | 'compact' | 'horizontal';
904
976
  /** ID цены, которая помечается лейблом «популярный план». v2-аналог
905
977
  * пары `price_label_id` + `price_label`. */
906
978
  popular_price_id?: string;
@@ -909,7 +981,10 @@ export declare type LayoutBlock = {
909
981
  popular_label?: string;
910
982
  } | {
911
983
  type: 'cta_button';
912
- label: string;
984
+ /** Текст на кнопке. Если не задан — рендерер сам подберёт по
985
+ * selected price'у и `trial_days`: "Start N-Day Free Trial",
986
+ * "Get Lifetime Access", "Get Monthly Plan" и т.п. */
987
+ label?: string;
913
988
  action: 'checkout' | 'close';
914
989
  priceId?: string;
915
990
  } | {
@@ -928,8 +1003,23 @@ export declare type LayoutBlock = {
928
1003
  /** Скрывать панель, если юзер уже залогинен. По умолчанию true.
929
1004
  * false — показываем "Signed in as ... [Sign out]" даже после логина. */
930
1005
  hide_when_authenticated?: boolean;
931
- /** Заголовок над формой (h2). Если опущензаголовок не рендерится. */
1006
+ /** Кастомный заголовок над формой. Если заданотображается вместо
1007
+ * дефолтного (определяется по mode'у — "Welcome back!" / "Welcome!" /
1008
+ * "Forgot password?" / ...). Без `submit_label` также используется как
1009
+ * submit-лейбл для signin (например `heading="Restore Purchases"` →
1010
+ * submit тоже "Restore Purchases"). Длинные heading (типа "Войдите,
1011
+ * чтобы продолжить покупку") в кнопку влезают плохо — задай
1012
+ * `submit_label` отдельно. */
932
1013
  heading?: string;
1014
+ /** Подпись под заголовком. Если опущен — подставляется default-текст
1015
+ * для текущего mode'а. Передай пустую строку чтобы скрыть подпись. */
1016
+ subheading?: string;
1017
+ /** Явный текст submit-кнопки. Имеет приоритет над heading-эхо. Нужен
1018
+ * для интентов с длинным descriptive heading'ом (preauth: "Войдите,
1019
+ * чтобы продолжить покупку" — кнопка только "Войти"). Для коротких
1020
+ * action-headings (restore: "Restore Purchases") опускай — эхо
1021
+ * даёт правильный UX. */
1022
+ submit_label?: string;
933
1023
  } | {
934
1024
  /** Список фич/преимуществ продукта. v2-аналог `features_list` + `features_view`.
935
1025
  * До 5 элементов — рендерим как чек-лист с заголовком и описанием. */
@@ -953,6 +1043,35 @@ export declare type LayoutBlock = {
953
1043
  desc: string;
954
1044
  count: number;
955
1045
  }>;
1046
+ } | {
1047
+ /** Money-back guarantee badge под cta_button: иконка + жирный заголовок +
1048
+ * пояснение мелким шрифтом + bottom divider, который визуально стыкуется
1049
+ * с current_session ниже. v2-аналог inline-блока в `PaywallPricing`. */
1050
+ type: 'guarantee_badge';
1051
+ /** Заголовок жирным. По умолчанию "100% Money-Back Guarantee". */
1052
+ title?: string;
1053
+ /** Подзаголовок мелким серым. По умолчанию
1054
+ * "Not satisfied? We'll refund you — no questions asked.". */
1055
+ subtitle?: string;
1056
+ /** Иконка слева от заголовка. По умолчанию `dollar_shield` —
1057
+ * зелёный shield с долларом (legacy-вид). `none` — без иконки. */
1058
+ icon?: 'dollar_shield' | 'none';
1059
+ } | {
1060
+ /** Urgency-баннер с countdown'ом до конца offer'а. Берёт первый offer
1061
+ * из `bootstrap.offers` с валидным `expires_at` или `duration_minutes`.
1062
+ * Авто-скрывается по истечении, чтобы не показывать "0d 0h 0m 0s".
1063
+ * Размещение — обычно первый блок в layout (над heading). */
1064
+ type: 'offer_banner';
1065
+ /** ID конкретного offer'а из bootstrap.offers. Если не задано — берётся
1066
+ * первый offer с активным таймером. */
1067
+ offer_id?: string;
1068
+ /** Текст слева от countdown'а. Если опущен — берётся `offer.label`,
1069
+ * иначе fallback "Limited-time offer". К нему дописывается процент:
1070
+ * "{title} {discount_percent}%" если discount задан. */
1071
+ title?: string;
1072
+ /** В превью админки — игнорировать expired-state, всё равно показывать
1073
+ * banner с нулями. Прод-режим — false (banner исчезает). */
1074
+ force?: boolean;
956
1075
  };
957
1076
 
958
1077
  /** Локализационные оверрайды для одного языка. Накатываются поверх дефолтного
@@ -1007,7 +1126,15 @@ export declare class PaywallError extends Error {
1007
1126
  export declare interface PaywallOffer {
1008
1127
  id: string;
1009
1128
  discount_percent: number | null;
1129
+ /** Абсолютная expiration date (ISO 8601). Если задана — countdown отсчитывает
1130
+ * до этого момента, по истечении offer считается истёкшим. */
1010
1131
  expires_at: string | null;
1132
+ /** Относительный таймер: сколько минут offer живёт **от первого просмотра
1133
+ * пейвола** данным юзером. Старт хранится в clientStorage под ключом
1134
+ * `pw-offer-{id}-start`, по истечении — auto-cleanup. Используется, когда
1135
+ * бэк хочет показывать "remaining time" без жёсткой server-time, а считать
1136
+ * относительно сессии юзера. expires_at имеет приоритет если задано. */
1137
+ duration_minutes?: number | null;
1011
1138
  price_id: string | null;
1012
1139
  label?: string | null;
1013
1140
  }
@@ -1057,6 +1184,14 @@ export declare interface PaywallSettings {
1057
1184
  brand_color?: string | null;
1058
1185
  custom_css?: string | null;
1059
1186
  locale_default?: string | null;
1187
+ /** Origin, на котором живёт бэк пейвола (тот же, что мерчант передаёт в
1188
+ * `BillingClientOptions.apiOrigin` при инициализации SDK). Бэк присылает
1189
+ * его на каждом bootstrap'е, SDK сверяет с init.apiOrigin — расхождение
1190
+ * даёт `invalid_config` (защита от опечатки интегратора). Без схемы:
1191
+ * "pay.your-domain.com" или "https://pay.your-domain.com" — оба валидны.
1192
+ * Для новых пейволов поле всегда заполнено (модерация требует custom_domain);
1193
+ * для legacy v2 может быть null/undefined. */
1194
+ custom_domain?: string | null;
1060
1195
  runtime_mode?: 'client' | 'hybrid' | 'server' | 'client-native' | 'hybrid-native';
1061
1196
  /** true, если эквайринг пейвола в test-mode — SDK рисует TEST MODE бейдж. */
1062
1197
  is_test_mode?: boolean;
@@ -1114,6 +1249,12 @@ export declare interface PaywallUser {
1114
1249
  started_at: string | null;
1115
1250
  expires_at: string | null;
1116
1251
  } | null;
1252
+ /** Был ли у юзера хотя бы один trial по этому пейволу когда-либо (включая
1253
+ * истёкшие и отменённые). Anti-abuse флаг для UI: CtaButton скрывает
1254
+ * "Start N-Day Free Trial" если true. Серверный enforcement в
1255
+ * `/start-checkout` дублирует — даже если UI обмануть, бэк не отдаст
1256
+ * trial_days в Stripe/Paddle. */
1257
+ had_previous_trial: boolean;
1117
1258
  }
1118
1259
 
1119
1260
  export declare interface PaywallUserPurchase {