@monetize.software/sdk 3.0.0-alpha.8 → 3.0.0-beta.0

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 (213) hide show
  1. package/dist/chunks/PaywallUI-CCwYgagL.js +26 -0
  2. package/dist/chunks/PaywallUI-CCwYgagL.js.map +1 -0
  3. package/dist/chunks/PaywallUI-CDlJL5Em.js +3599 -0
  4. package/dist/chunks/PaywallUI-CDlJL5Em.js.map +1 -0
  5. package/dist/chunks/ar-CViBaj16.js +2 -0
  6. package/dist/chunks/ar-CViBaj16.js.map +1 -0
  7. package/dist/chunks/{ar-CHae8g-2.js → ar-ClwBmll7.js} +6 -2
  8. package/dist/chunks/ar-ClwBmll7.js.map +1 -0
  9. package/dist/chunks/{cs-eZTedzaK.js → cs-Cc_D0W4S.js} +6 -2
  10. package/dist/chunks/cs-Cc_D0W4S.js.map +1 -0
  11. package/dist/chunks/cs-DQJWP65K.js +2 -0
  12. package/dist/chunks/cs-DQJWP65K.js.map +1 -0
  13. package/dist/chunks/{da-Dca6j8fp.js → da-BtKcMSxH.js} +6 -2
  14. package/dist/chunks/da-BtKcMSxH.js.map +1 -0
  15. package/dist/chunks/da-Cyr_IXhb.js +2 -0
  16. package/dist/chunks/da-Cyr_IXhb.js.map +1 -0
  17. package/dist/chunks/de-BOCUj1pF.js +2 -0
  18. package/dist/chunks/de-BOCUj1pF.js.map +1 -0
  19. package/dist/chunks/{de-BCjn3PUI.js → de-iwQW5eYl.js} +6 -2
  20. package/dist/chunks/de-iwQW5eYl.js.map +1 -0
  21. package/dist/chunks/{el-BpXtDTez.js → el-BoH65CeJ.js} +6 -2
  22. package/dist/chunks/el-BoH65CeJ.js.map +1 -0
  23. package/dist/chunks/el-C6jLHiEF.js +2 -0
  24. package/dist/chunks/el-C6jLHiEF.js.map +1 -0
  25. package/dist/chunks/es-CARHLxHR.js +2 -0
  26. package/dist/chunks/es-CARHLxHR.js.map +1 -0
  27. package/dist/chunks/{es-B3P4nlMw.js → es-CkP16_8K.js} +6 -2
  28. package/dist/chunks/es-CkP16_8K.js.map +1 -0
  29. package/dist/chunks/fi-B8OhRbwY.js +2 -0
  30. package/dist/chunks/fi-B8OhRbwY.js.map +1 -0
  31. package/dist/chunks/{fi-BbQ_Bs0Z.js → fi-yUXSmK1E.js} +6 -2
  32. package/dist/chunks/fi-yUXSmK1E.js.map +1 -0
  33. package/dist/chunks/fr-CoM18zzM.js +2 -0
  34. package/dist/chunks/fr-CoM18zzM.js.map +1 -0
  35. package/dist/chunks/{fr-BKDUXceO.js → fr-DSZRGsxI.js} +6 -2
  36. package/dist/chunks/fr-DSZRGsxI.js.map +1 -0
  37. package/dist/chunks/he-DTDVc3lA.js +2 -0
  38. package/dist/chunks/he-DTDVc3lA.js.map +1 -0
  39. package/dist/chunks/{he-BVCHlTtT.js → he-ZUo7cQjk.js} +8 -4
  40. package/dist/chunks/he-ZUo7cQjk.js.map +1 -0
  41. package/dist/chunks/hi-BjnS9UeE.js +2 -0
  42. package/dist/chunks/hi-BjnS9UeE.js.map +1 -0
  43. package/dist/chunks/{hi-H_Hshh-7.js → hi-CEutBKiG.js} +6 -2
  44. package/dist/chunks/hi-CEutBKiG.js.map +1 -0
  45. package/dist/chunks/hu-CN06FMhV.js +2 -0
  46. package/dist/chunks/hu-CN06FMhV.js.map +1 -0
  47. package/dist/chunks/{hu-ZWiNfzvN.js → hu-DvEAWGS7.js} +6 -2
  48. package/dist/chunks/hu-DvEAWGS7.js.map +1 -0
  49. package/dist/chunks/id-BITgaBxq.js +2 -0
  50. package/dist/chunks/id-BITgaBxq.js.map +1 -0
  51. package/dist/chunks/{id-DeiRYsJ1.js → id-_eEMrYMW.js} +6 -2
  52. package/dist/chunks/id-_eEMrYMW.js.map +1 -0
  53. package/dist/chunks/index-CLB1AgLg.js +2074 -0
  54. package/dist/chunks/index-CLB1AgLg.js.map +1 -0
  55. package/dist/chunks/index-CzDSBl4d.js +2 -0
  56. package/dist/chunks/index-CzDSBl4d.js.map +1 -0
  57. package/dist/chunks/{it-UH9OzFhg.js → it-BAmsQbIl.js} +6 -2
  58. package/dist/chunks/it-BAmsQbIl.js.map +1 -0
  59. package/dist/chunks/it-DVcsq015.js +2 -0
  60. package/dist/chunks/it-DVcsq015.js.map +1 -0
  61. package/dist/chunks/ja-Bim7Ok2e.js +2 -0
  62. package/dist/chunks/ja-Bim7Ok2e.js.map +1 -0
  63. package/dist/chunks/{ja-BYC8FRN8.js → ja-BqCZWVKK.js} +8 -4
  64. package/dist/chunks/ja-BqCZWVKK.js.map +1 -0
  65. package/dist/chunks/{ko-Bjs2ZRcF.js → ko-CkIzeOzb.js} +8 -4
  66. package/dist/chunks/ko-CkIzeOzb.js.map +1 -0
  67. package/dist/chunks/ko-DqEfcVCB.js +2 -0
  68. package/dist/chunks/ko-DqEfcVCB.js.map +1 -0
  69. package/dist/chunks/nl-DSNuJWIo.js +2 -0
  70. package/dist/chunks/nl-DSNuJWIo.js.map +1 -0
  71. package/dist/chunks/{nl-Ch5HFWQO.js → nl-Mu_KNzli.js} +6 -2
  72. package/dist/chunks/nl-Mu_KNzli.js.map +1 -0
  73. package/dist/chunks/{no-CljpinWz.js → no-9HMjljBs.js} +6 -2
  74. package/dist/chunks/no-9HMjljBs.js.map +1 -0
  75. package/dist/chunks/no-B5HY_A8_.js +2 -0
  76. package/dist/chunks/no-B5HY_A8_.js.map +1 -0
  77. package/dist/chunks/{pl-CUcSS0zZ.js → pl-Cbr2qDwv.js} +6 -2
  78. package/dist/chunks/pl-Cbr2qDwv.js.map +1 -0
  79. package/dist/chunks/pl-ChGLn9Sy.js +2 -0
  80. package/dist/chunks/pl-ChGLn9Sy.js.map +1 -0
  81. package/dist/chunks/pt-CDLEktT9.js +2 -0
  82. package/dist/chunks/pt-CDLEktT9.js.map +1 -0
  83. package/dist/chunks/{pt-BHK0LwkC.js → pt-_jirA6IR.js} +6 -2
  84. package/dist/chunks/pt-_jirA6IR.js.map +1 -0
  85. package/dist/chunks/ro-BHCHiXY3.js +2 -0
  86. package/dist/chunks/ro-BHCHiXY3.js.map +1 -0
  87. package/dist/chunks/{ro-Bj8cwU2n.js → ro-oZLxhwHc.js} +6 -2
  88. package/dist/chunks/ro-oZLxhwHc.js.map +1 -0
  89. package/dist/chunks/ru-B6HgmINj.js +2 -0
  90. package/dist/chunks/ru-B6HgmINj.js.map +1 -0
  91. package/dist/chunks/{ru-CgqNy0Gb.js → ru-C2-sqY7B.js} +6 -2
  92. package/dist/chunks/ru-C2-sqY7B.js.map +1 -0
  93. package/dist/chunks/sv-DoSs4a9n.js +2 -0
  94. package/dist/chunks/sv-DoSs4a9n.js.map +1 -0
  95. package/dist/chunks/{sv-H7jroOQ5.js → sv-y385MWVy.js} +6 -2
  96. package/dist/chunks/sv-y385MWVy.js.map +1 -0
  97. package/dist/chunks/{th-Dqm-gpGe.js → th-Bjbv4M1s.js} +6 -2
  98. package/dist/chunks/th-Bjbv4M1s.js.map +1 -0
  99. package/dist/chunks/th-UeweOhwg.js +2 -0
  100. package/dist/chunks/th-UeweOhwg.js.map +1 -0
  101. package/dist/chunks/tr-BbBr5tyB.js +2 -0
  102. package/dist/chunks/tr-BbBr5tyB.js.map +1 -0
  103. package/dist/chunks/{tr-D3zPcNtT.js → tr-DmHo9F8i.js} +8 -4
  104. package/dist/chunks/tr-DmHo9F8i.js.map +1 -0
  105. package/dist/chunks/uk-CJTA1SJK.js +2 -0
  106. package/dist/chunks/uk-CJTA1SJK.js.map +1 -0
  107. package/dist/chunks/{uk-CoIIs3QI.js → uk-DwvAoTe5.js} +6 -2
  108. package/dist/chunks/uk-DwvAoTe5.js.map +1 -0
  109. package/dist/chunks/{vi-C_fruIbh.js → vi-BEpwsVLR.js} +6 -2
  110. package/dist/chunks/vi-BEpwsVLR.js.map +1 -0
  111. package/dist/chunks/vi-ZvBo7PbB.js +2 -0
  112. package/dist/chunks/vi-ZvBo7PbB.js.map +1 -0
  113. package/dist/chunks/zh-CPZBEb3d.js +2 -0
  114. package/dist/chunks/zh-CPZBEb3d.js.map +1 -0
  115. package/dist/chunks/{zh-LDkEV2D9.js → zh-DrG18oGe.js} +7 -3
  116. package/dist/chunks/zh-DrG18oGe.js.map +1 -0
  117. package/dist/core.cjs +1 -1
  118. package/dist/core.cjs.map +1 -1
  119. package/dist/core.d.ts +110 -17
  120. package/dist/core.js +17 -1984
  121. package/dist/core.js.map +1 -1
  122. package/dist/index.cjs +1 -1
  123. package/dist/index.d.ts +209 -18
  124. package/dist/index.js +17 -13
  125. package/dist/ui.cjs +1 -1
  126. package/dist/ui.d.ts +174 -17
  127. package/dist/ui.js +1 -1
  128. package/package.json +1 -1
  129. package/dist/chunks/PaywallUI-BrDiS6zg.js +0 -3219
  130. package/dist/chunks/PaywallUI-BrDiS6zg.js.map +0 -1
  131. package/dist/chunks/PaywallUI-Bvx8nRL0.js +0 -26
  132. package/dist/chunks/PaywallUI-Bvx8nRL0.js.map +0 -1
  133. package/dist/chunks/ar-CHae8g-2.js.map +0 -1
  134. package/dist/chunks/ar-E1mc8SO_.js +0 -2
  135. package/dist/chunks/ar-E1mc8SO_.js.map +0 -1
  136. package/dist/chunks/cs-Dccq6LAT.js +0 -2
  137. package/dist/chunks/cs-Dccq6LAT.js.map +0 -1
  138. package/dist/chunks/cs-eZTedzaK.js.map +0 -1
  139. package/dist/chunks/da-C_4MbEh5.js +0 -2
  140. package/dist/chunks/da-C_4MbEh5.js.map +0 -1
  141. package/dist/chunks/da-Dca6j8fp.js.map +0 -1
  142. package/dist/chunks/de-BCjn3PUI.js.map +0 -1
  143. package/dist/chunks/de-DulxcJj-.js +0 -2
  144. package/dist/chunks/de-DulxcJj-.js.map +0 -1
  145. package/dist/chunks/el-BpXtDTez.js.map +0 -1
  146. package/dist/chunks/el-CVG_1iKB.js +0 -2
  147. package/dist/chunks/el-CVG_1iKB.js.map +0 -1
  148. package/dist/chunks/es-B3P4nlMw.js.map +0 -1
  149. package/dist/chunks/es-ri0uKzUW.js +0 -2
  150. package/dist/chunks/es-ri0uKzUW.js.map +0 -1
  151. package/dist/chunks/fi-BbQ_Bs0Z.js.map +0 -1
  152. package/dist/chunks/fi-CNZqWHjw.js +0 -2
  153. package/dist/chunks/fi-CNZqWHjw.js.map +0 -1
  154. package/dist/chunks/fr-BKDUXceO.js.map +0 -1
  155. package/dist/chunks/fr-CfFOw4hD.js +0 -2
  156. package/dist/chunks/fr-CfFOw4hD.js.map +0 -1
  157. package/dist/chunks/he-BVCHlTtT.js.map +0 -1
  158. package/dist/chunks/he-DN2JEtQb.js +0 -2
  159. package/dist/chunks/he-DN2JEtQb.js.map +0 -1
  160. package/dist/chunks/hi-DxfOerNP.js +0 -2
  161. package/dist/chunks/hi-DxfOerNP.js.map +0 -1
  162. package/dist/chunks/hi-H_Hshh-7.js.map +0 -1
  163. package/dist/chunks/hu-BTImywuV.js +0 -2
  164. package/dist/chunks/hu-BTImywuV.js.map +0 -1
  165. package/dist/chunks/hu-ZWiNfzvN.js.map +0 -1
  166. package/dist/chunks/id-DeiRYsJ1.js.map +0 -1
  167. package/dist/chunks/id-YFuArJA6.js +0 -2
  168. package/dist/chunks/id-YFuArJA6.js.map +0 -1
  169. package/dist/chunks/it-UH9OzFhg.js.map +0 -1
  170. package/dist/chunks/it-mhkzXBM9.js +0 -2
  171. package/dist/chunks/it-mhkzXBM9.js.map +0 -1
  172. package/dist/chunks/ja-6l_z_G9k.js +0 -2
  173. package/dist/chunks/ja-6l_z_G9k.js.map +0 -1
  174. package/dist/chunks/ja-BYC8FRN8.js.map +0 -1
  175. package/dist/chunks/ko-Bjs2ZRcF.js.map +0 -1
  176. package/dist/chunks/ko-YAl4XwHu.js +0 -2
  177. package/dist/chunks/ko-YAl4XwHu.js.map +0 -1
  178. package/dist/chunks/nl-C-9zHtfb.js +0 -2
  179. package/dist/chunks/nl-C-9zHtfb.js.map +0 -1
  180. package/dist/chunks/nl-Ch5HFWQO.js.map +0 -1
  181. package/dist/chunks/no-CljpinWz.js.map +0 -1
  182. package/dist/chunks/no-qzPitLlx.js +0 -2
  183. package/dist/chunks/no-qzPitLlx.js.map +0 -1
  184. package/dist/chunks/pl-CUcSS0zZ.js.map +0 -1
  185. package/dist/chunks/pl-MAIYeuhW.js +0 -2
  186. package/dist/chunks/pl-MAIYeuhW.js.map +0 -1
  187. package/dist/chunks/pt-BHK0LwkC.js.map +0 -1
  188. package/dist/chunks/pt-DqDabE4v.js +0 -2
  189. package/dist/chunks/pt-DqDabE4v.js.map +0 -1
  190. package/dist/chunks/ro-BVs-lHH-.js +0 -2
  191. package/dist/chunks/ro-BVs-lHH-.js.map +0 -1
  192. package/dist/chunks/ro-Bj8cwU2n.js.map +0 -1
  193. package/dist/chunks/ru-CgqNy0Gb.js.map +0 -1
  194. package/dist/chunks/ru-DP7qDAmE.js +0 -2
  195. package/dist/chunks/ru-DP7qDAmE.js.map +0 -1
  196. package/dist/chunks/sv-B3QEYGgd.js +0 -2
  197. package/dist/chunks/sv-B3QEYGgd.js.map +0 -1
  198. package/dist/chunks/sv-H7jroOQ5.js.map +0 -1
  199. package/dist/chunks/th-Dqm-gpGe.js.map +0 -1
  200. package/dist/chunks/th-DzQau9aW.js +0 -2
  201. package/dist/chunks/th-DzQau9aW.js.map +0 -1
  202. package/dist/chunks/tr-D3zPcNtT.js.map +0 -1
  203. package/dist/chunks/tr-cG1YuE1E.js +0 -2
  204. package/dist/chunks/tr-cG1YuE1E.js.map +0 -1
  205. package/dist/chunks/uk-CoIIs3QI.js.map +0 -1
  206. package/dist/chunks/uk-Cvbo0IBW.js +0 -2
  207. package/dist/chunks/uk-Cvbo0IBW.js.map +0 -1
  208. package/dist/chunks/vi-BRtYSBUp.js +0 -2
  209. package/dist/chunks/vi-BRtYSBUp.js.map +0 -1
  210. package/dist/chunks/vi-C_fruIbh.js.map +0 -1
  211. package/dist/chunks/zh-CwczPMPp.js +0 -2
  212. package/dist/chunks/zh-CwczPMPp.js.map +0 -1
  213. package/dist/chunks/zh-LDkEV2D9.js.map +0 -1
package/dist/ui.d.ts CHANGED
@@ -248,10 +248,8 @@ declare class AuthClient {
248
248
  * когда сервер начнёт возвращать challenge_required в риск-сценариях,
249
249
  * SDK сможет передать proof-of-something обратно без breaking change.
250
250
  *
251
- * `forceCaptcha: true` пропускает шаги 1-2 и сразу делает /signin (создаёт
252
- * нового anon-юзера). Используется в switch-account flow. Имя поля исторически
253
- * остаётся `forceCaptcha`, хотя капчи там больше нет — менять имя ломает
254
- * host-сигнатуру; смысл «принудительно новая anon-сессия» сохранён.
251
+ * `forceNewAnon: true` пропускает шаги 1-2 и сразу делает /signin (создаёт
252
+ * нового anon-юзера). Используется в switch-account flow.
255
253
  *
256
254
  * Параллельные вызовы дедуплицируются через `inflightAnonSignin` — два
257
255
  * click'а на «Войти как гость» не создадут двух anon-юзеров (два /signup =
@@ -260,7 +258,7 @@ declare class AuthClient {
260
258
  signInAnonymously(input?: {
261
259
  captchaToken?: string;
262
260
  userMeta?: Record<string, string>;
263
- forceCaptcha?: boolean;
261
+ forceNewAnon?: boolean;
264
262
  }): Promise<AuthSession>;
265
263
  /**
266
264
  * Внутренний resume — пробует /auth/refresh с сохранённым anon refresh_token.
@@ -625,6 +623,13 @@ declare class BillingClient {
625
623
  }): Promise<PaywallPrice[]>;
626
624
  /** Sync-снимок цен из последнего bootstrap'а. null = ещё не загружали. */
627
625
  getCachedPrices(): PaywallPrice[] | null;
626
+ /** Sync-снимок офферов из последнего bootstrap'а. null = bootstrap ещё не
627
+ * загружали, пустой массив = бэк отдал пейвол без офферов. Бэк уже
628
+ * применил серверный таргетинг (target_countries / target_emails /
629
+ * targeting_mode из offer_settings) — наружу выезжает только то, что
630
+ * применимо к текущему юзеру. Клиентская сторона остаётся ответственной
631
+ * за price_id-matching и countdown (см. core/offer.ts → resolveOffer). */
632
+ getCachedOffers(): PaywallOffer[] | null;
628
633
  /**
629
634
  * Снимок того, какой язык SDK сейчас считает «языком юзера». Полезно для
630
635
  * синхронизации i18n хоста с тем, что фактически показывает пейвол — чтобы
@@ -751,6 +756,17 @@ declare class BillingClient {
751
756
  errorUrl?: string;
752
757
  shopUrl?: string;
753
758
  trialDays?: number;
759
+ /** Активный offer для этой цены — резолвится host'ом через
760
+ * `paywall.getOfferForPrice(priceId)?.offer.id` или
761
+ * `findApplicableOffer(client.getCachedOffers(), priceId)?.id`. Без
762
+ * явной передачи бэк сделает auto-resolve по email — но только для
763
+ * end_date-офферов. duration_minutes-офферы тикают в clientStorage и
764
+ * сервер их не видит: для них offerId ОБЯЗАН прийти от клиента, иначе
765
+ * скидка не применится на чекауте, хотя UI её показывал.
766
+ *
767
+ * Передавать offer-id всегда безопасно — бэк сам проверит applicable
768
+ * ли offer к этому юзеру (страна/email/режим) и игнорирует если нет. */
769
+ offerId?: string;
754
770
  /**
755
771
  * Stage 1 защиты от дубликатов покупок. Идемпотентный ключ запроса
756
772
  * (UUID). Повторный вызов с тем же ключом вернёт тот же checkout-URL
@@ -777,7 +793,9 @@ declare class BillingClient {
777
793
  * инвойсы). Опен-флоу управляется host'ом:
778
794
  *
779
795
  * ```ts
780
- * const { url } = await billing.getCustomerPortalUrl();
796
+ * const { url } = await billing.getCustomerPortalUrl({
797
+ * returnUrl: 'https://your-app.com/account'
798
+ * });
781
799
  * window.open(url, '_blank');
782
800
  * ```
783
801
  *
@@ -789,6 +807,14 @@ declare class BillingClient {
789
807
  */
790
808
  getCustomerPortalUrl(opts?: {
791
809
  signal?: AbortSignal;
810
+ /** URL для return-button у провайдера (Stripe «Return to ...», Paddle
811
+ * и Chargebee redirect_url'ы). Передавай туда страницу-аккаунт твоего
812
+ * app'а — `https://your-app.com/account`. Без явного returnUrl бэк
813
+ * применяет fallback в порядке: `paywall_settings.shop_url` →
814
+ * custom_domain пейвола → NEXT_PUBLIC_ONLINE_ORIGIN (последнее — это
815
+ * страница в самом online-сервисе, годится только для legacy
816
+ * v2-iframe-флоу). */
817
+ returnUrl?: string;
792
818
  }): Promise<{
793
819
  url: string;
794
820
  }>;
@@ -799,21 +825,31 @@ declare class BillingClient {
799
825
  * `/api/v1/paywall/[id]/user` без unstable_cache, потому что list для UI
800
826
  * должен быть свежим после cancel-а.
801
827
  *
802
- * Auth: Bearer обязателен (через AuthClient). Без Bearer — 401 от бэка,
803
- * пробрасываем как PaywallError('http_401'). Гость пустой список.
828
+ * Auth (два пути):
829
+ * - Bearer (через AuthClient) — user.id резолвится из сессии, identity
830
+ * в query игнорируется.
831
+ * - `apiKey` + `identity.email`/`identity.userId` — server-SDK путь для
832
+ * интеграций со своей авторизацией. Бэк проверяет, что identity линкована
833
+ * к этому пейволу (защита от cross-paywall lookup).
834
+ * Без auth и без apiKey+identity — `identity_required`.
804
835
  */
805
836
  listPurchases(opts?: {
806
837
  signal?: AbortSignal;
807
838
  }): Promise<PaywallPurchaseDetailed[]>;
808
839
  /**
809
- * Отменить подписку. Бэк проверит что subscription принадлежит auth-юзеру
810
- * и сделает cancel у acquiring'а (Stripe/Paddle/Chargebee). По умолчанию
811
- * cancel в конце текущего периода — юзер сохраняет access до renewal date'ы.
840
+ * Отменить подписку. Бэк проверит, что subscription принадлежит юзеру
841
+ * (Bearer-путь из сессии; apiKey-путь — из identity), и сделает cancel у
842
+ * acquiring'а (Stripe/Paddle/Chargebee/Overpay). По умолчанию cancel в
843
+ * конце текущего периода — юзер сохраняет access до renewal date'ы.
812
844
  *
813
- * `reason` обязательна (валидация на бэке). Удобно собрать через select
814
- * причин в host-UI, как в legacy customer portal'е.
845
+ * `reason` обязательна (валидация на бэке).
815
846
  *
816
- * Auth: Bearer обязателен.
847
+ * Auth (два пути):
848
+ * - Bearer (через AuthClient) — стандартный путь для UI customer-portal'a.
849
+ * - `apiKey` + `identity.email`/`identity.userId` — для self-service UI на
850
+ * бэке клиента со своей авторизацией. Бэк дополнительно фильтрует
851
+ * subscription по paywall_id, чтобы owner пейвола A не отменил подписку
852
+ * пейвола B.
817
853
  */
818
854
  cancelSubscription(params: {
819
855
  subscriptionId: string;
@@ -1266,8 +1302,10 @@ declare interface PaywallOffer {
1266
1302
  expires_at: string | null;
1267
1303
  /** Относительный таймер: сколько минут offer живёт **от первого просмотра
1268
1304
  * пейвола** данным юзером. Старт хранится в clientStorage под ключом
1269
- * `pw-offer-{id}-start`, по истечении auto-cleanup. Используется, когда
1270
- * бэк хочет показывать "remaining time" без жёсткой server-time, а считать
1305
+ * `pw-offer-{id}-start` и остаётся там **после** expiry — это
1306
+ * forever-marker, чтобы юзер не мог «фармить» offer (re-open пейвола
1307
+ * не запускает countdown заново). Используется, когда бэк хочет
1308
+ * показывать "remaining time" без жёсткой server-time, а считать
1271
1309
  * относительно сессии юзера. expires_at имеет приоритет если задано. */
1272
1310
  duration_minutes?: number | null;
1273
1311
  price_id: string | null;
@@ -1383,12 +1421,25 @@ declare type PaywallStateListener = (state: PaywallStateSnapshot) => void;
1383
1421
  * один call onState; повторы (`useSyncExternalStore`-friendly).
1384
1422
  */
1385
1423
  export declare interface PaywallStateSnapshot {
1386
- /** Модалка отрендерена и видна. False — closed (или ещё не открывалась). */
1424
+ /** Модалка отрендерена и видна. False — closed (или ещё не открывалась).
1425
+ * Может быть false при `processing=true` — direct-checkout (paywall.checkout)
1426
+ * делает bootstrap + createCheckout headless до того, как решит надо ли
1427
+ * монтировать модалку. */
1387
1428
  open: boolean;
1388
1429
  /** Что показывается в модалке. null когда `open=false`. */
1389
1430
  view: 'loading' | 'error' | 'layout' | 'auth' | 'support' | 'awaiting_payment' | 'popup_blocked' | 'purchased' | null;
1390
1431
  /** Заполнено только когда `view === 'error'`. */
1391
1432
  error: PaywallError | null;
1433
+ /** SDK делает фоновую работу для `paywall.checkout(priceId)` — bootstrap,
1434
+ * visibility/trial-gates, createCheckout — до того, как реально нужна
1435
+ * UI-модалка. Хост на этой фазе может задизейблить свою кнопку и
1436
+ * показать спиннер прямо на ней, чтобы у юзера не было ощущения «клик
1437
+ * ничего не сделал». Сбрасывается в false сразу после mountAndShow
1438
+ * (модалка взяла на себя UI), либо после headless reject (already-paid,
1439
+ * ошибка createCheckout без модалки). Для `paywall.open()`-flow всегда
1440
+ * false: там модалка появляется мгновенно со своим LoadingView и
1441
+ * отдельный «processing» не нужен. */
1442
+ processing: boolean;
1392
1443
  }
1393
1444
 
1394
1445
  export declare class PaywallUI {
@@ -1408,6 +1459,12 @@ export declare class PaywallUI {
1408
1459
  private watcher;
1409
1460
  private tracker;
1410
1461
  private purchased;
1462
+ /** View, с которым последний раз монтировалась модалка. Гейтит аналитику
1463
+ * `paywall_opened`/`paywall_viewed` на реальный пейвол (`'layout'`): открытие
1464
+ * support / standalone-auth / awaiting_payment эмитит публичный `'open'` и
1465
+ * `'ready'`, но это не «пейвол открыт/просмотрен» — иначе саппорт-клик шлёт
1466
+ * ложный `paywall_opened`. */
1467
+ private lastMountedView;
1411
1468
  /** Lazy-инстанс TrialStore. Резолвится при первом open(), когда уже знаем
1412
1469
  * `bootstrap.settings.trial`. null — триал отключён в конфиге пейвола. */
1413
1470
  private trialStore;
@@ -1529,6 +1586,65 @@ export declare class PaywallUI {
1529
1586
  * Без managed-auth — no-op.
1530
1587
  */
1531
1588
  openSignup(opts?: OpenOptions): void;
1589
+ /**
1590
+ * Direct-checkout: создать checkout-URL по конкретной цене и сразу открыть
1591
+ * платёжного провайдера, минуя layout с тарифами. Полезно когда
1592
+ * host-приложение рендерит pricing-карточки/таблицу собственным UI и
1593
+ * хочет, чтобы клик по «Buy / Get this plan» вёл прямо в Stripe/Paddle.
1594
+ *
1595
+ * **Late-mount UX.** В отличие от `open()`, модалка не появляется во время
1596
+ * фоновой работы (bootstrap + visibility/trial gates + createCheckout).
1597
+ * Хост на этой фазе показывает busy-state прямо на своей кнопке (через
1598
+ * `state.processing === true` из `paywall.getState()` — или автоматически
1599
+ * через `<PaywallButton priceId>` в sdk-react). Модалка монтируется
1600
+ * ТОЛЬКО когда реально нужна UI:
1601
+ * - `checkout_mode='preauth'` + managed-auth + не залогинен → auth-gate
1602
+ * (форма signin'а); после успеха auto-resume в createCheckout.
1603
+ * - popup провайдера заблокирован браузером → popup_blocked view с
1604
+ * retry-кнопкой под fresh user gesture.
1605
+ * - popup открылся успешно → awaiting_payment view (индикатор «оплати
1606
+ * в новой вкладке» + I've paid).
1607
+ *
1608
+ * Что эмитится без модалки:
1609
+ * - `purchase_completed{restored:true, priceId}` когда юзер уже подписан
1610
+ * (cached user, fresh bootstrap, или 409 hasActivePurchase от бэка) —
1611
+ * headless reject;
1612
+ * - `error` когда createCheckout упал или identity.email отсутствует;
1613
+ * - `visibility_blocked` / `trial_blocked` — стандартные gate-эвенты.
1614
+ *
1615
+ * Что эмитится одновременно с модалкой:
1616
+ * - `checkout_started{priceId, url, acquiring}` ровно когда headless URL
1617
+ * получен, ДО mount'а awaiting_payment/popup_blocked.
1618
+ *
1619
+ * Offer (countdown-скидка) автоматически резолвится из cached offers'ов
1620
+ * через `getOfferForPrice(priceId)` и передаётся в createCheckout как
1621
+ * `offerId` — чтобы duration_minutes-офферы тоже применились на бэке
1622
+ * (для них нет server-side таймера, без явного offer-id скидка теряется).
1623
+ *
1624
+ * Требования:
1625
+ * - `identity.email` должен быть выставлен (через `opts.identity`, либо
1626
+ * managed-auth, либо ранний `setIdentity`/`paywall.open({identity})`).
1627
+ * Без email бэк `/start-checkout` 400'нёт; SDK эмитнет `error`.
1628
+ * - В `checkout_mode='preauth'` без managed-auth — backend требует
1629
+ * email-юзера; убедись что `identity.email` явно задан.
1630
+ *
1631
+ * Без модалки совсем (когда host рендерит свой awaiting-payment экран) —
1632
+ * используй `paywall.billing.createCheckout({priceId, offerId})` напрямую,
1633
+ * но тогда auth-gate / popup_blocked / awaiting_payment придётся рисовать
1634
+ * самостоятельно.
1635
+ */
1636
+ checkout(priceId: string, opts?: OpenOptions): void;
1637
+ /** Headless prep-work для `checkout(priceId, opts)`: bootstrap → gates →
1638
+ * preauth check → createCheckout → mount модалки с финальным view.
1639
+ * Вынесено отдельным методом ради чистого async/await flow вместо вложенных
1640
+ * then-chain'ов (5+ ветвей). Любая ошибка не пробрасывается наружу: эмитим
1641
+ * через `paywall.emit('error')` и выходим — host подписан на `error`-event. */
1642
+ private runDirectCheckout;
1643
+ /** Trial-check без mount'а (для late-mount direct-checkout). Возвращает
1644
+ * true если trial заблокировал — caller должен прекратить flow. На любой
1645
+ * storage-ошибке log+продолжаем (не блокируем продажу). */
1646
+ private checkTrialBeforeCheckout;
1647
+ private applyProcessing;
1532
1648
  /**
1533
1649
  * Headless anonymous signin без открытия модалки. Внутри:
1534
1650
  * idempotent (если уже анон — instant return) → resume через сохранённый
@@ -1595,6 +1711,26 @@ export declare class PaywallUI {
1595
1711
  }): Promise<PaywallPrice[]>;
1596
1712
  /** Sync-снимок цен. null — bootstrap ещё не загружали. */
1597
1713
  getCachedPrices(): PaywallPrice[] | null;
1714
+ /** Sync-снимок офферов. null = bootstrap не загружали, [] = пейвол без офферов.
1715
+ * Бэк уже применил серверный targeting (страны/email/режим) — наружу
1716
+ * выезжает только то, что применимо к текущему юзеру. */
1717
+ getCachedOffers(): PaywallOffer[] | null;
1718
+ /**
1719
+ * Резолвит активный offer для конкретной цены: price_id-таргетинг +
1720
+ * countdown (`expires_at` ИЛИ `duration_minutes` от первого открытия
1721
+ * пейвола, см. clientStorage `pw-offer-{id}-start`).
1722
+ *
1723
+ * Read-only — НЕ записывает start для `duration_minutes`-офферов. Запись
1724
+ * стартует только когда модалка реально открыта (renderer'ом). До этого
1725
+ * `getOfferForPrice` вернёт `null` для duration-only офферов, чтобы
1726
+ * страницы-хосты вне модалки (pricing, landing) не активировали countdown
1727
+ * раньше времени.
1728
+ *
1729
+ * Хост-странице нужен countdown, который тикает каждую секунду — для
1730
+ * этого использовать React-хук `usePaywallOffer(priceId)` из sdk-react
1731
+ * либо обёртку поверх `setInterval(1000)` + повторный вызов этого метода.
1732
+ */
1733
+ getOfferForPrice(priceId: string): ResolvedOffer | null;
1598
1734
  /** Снимок текущего «языка юзера» — proxy над `billing.getUserLanguage()`.
1599
1735
  * Используй, чтобы синхронизировать i18n host'а с тем, что фактически
1600
1736
  * показывает пейвол. См. подробности в `BillingClient.getUserLanguage`. */
@@ -1714,6 +1850,27 @@ declare class QuotaExceededError extends PaywallError {
1714
1850
  });
1715
1851
  }
1716
1852
 
1853
+ /**
1854
+ * Resolved view of a paywall offer — what host UI actually needs to render
1855
+ * a strike-through price + countdown without re-implementing the math.
1856
+ *
1857
+ * `remainingMs` ticks down with wall-clock time and reaches 0 on expiry.
1858
+ * `totalMs` stays constant — useful for progress bars / share-of-time UX.
1859
+ * `expiresAt` is the Date.now()-comparable epoch ms of expiry.
1860
+ *
1861
+ * For offers without an expiry mechanism (no `expires_at` and no
1862
+ * `duration_minutes`), `remainingMs`/`totalMs`/`expiresAt` are all `null`,
1863
+ * but the resolved view is still returned — discount badge / strike-through
1864
+ * still make sense for "perpetual sale" offers.
1865
+ */
1866
+ declare interface ResolvedOffer {
1867
+ offer: PaywallOffer;
1868
+ discountPercent: number;
1869
+ remainingMs: number | null;
1870
+ totalMs: number | null;
1871
+ expiresAt: number | null;
1872
+ }
1873
+
1717
1874
  declare type SignUpResult = {
1718
1875
  kind: 'signed_in';
1719
1876
  session: AuthSession;
package/dist/ui.js CHANGED
@@ -1,4 +1,4 @@
1
- import { P as o, b as r } from "./chunks/PaywallUI-BrDiS6zg.js";
1
+ import { P as o, b as r } from "./chunks/PaywallUI-CDlJL5Em.js";
2
2
  export {
3
3
  o as PaywallUI,
4
4
  r as blockRegistry
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monetize.software/sdk",
3
- "version": "3.0.0-alpha.8",
3
+ "version": "3.0.0-beta.0",
4
4
  "description": "Monetize SDK — bundled billing client and paywall render engine for web and Chrome extensions",
5
5
  "type": "module",
6
6
  "sideEffects": false,