@monetize.software/sdk 3.0.0-alpha.12 → 3.0.0-alpha.14

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/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-CSgfmhHq.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;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./core.cjs"),r=require("./chunks/PaywallUI-DA8Kj9fJ.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
@@ -770,6 +770,17 @@ export declare class BillingClient {
770
770
  errorUrl?: string;
771
771
  shopUrl?: string;
772
772
  trialDays?: number;
773
+ /** Активный offer для этой цены — резолвится host'ом через
774
+ * `paywall.getOfferForPrice(priceId)?.offer.id` или
775
+ * `findApplicableOffer(client.getCachedOffers(), priceId)?.id`. Без
776
+ * явной передачи бэк сделает auto-resolve по email — но только для
777
+ * end_date-офферов. duration_minutes-офферы тикают в clientStorage и
778
+ * сервер их не видит: для них offerId ОБЯЗАН прийти от клиента, иначе
779
+ * скидка не применится на чекауте, хотя UI её показывал.
780
+ *
781
+ * Передавать offer-id всегда безопасно — бэк сам проверит applicable
782
+ * ли offer к этому юзеру (страна/email/режим) и игнорирует если нет. */
783
+ offerId?: string;
773
784
  /**
774
785
  * Stage 1 защиты от дубликатов покупок. Идемпотентный ключ запроса
775
786
  * (UUID). Повторный вызов с тем же ключом вернёт тот же checkout-URL
@@ -1469,12 +1480,25 @@ declare type PaywallStateListener = (state: PaywallStateSnapshot) => void;
1469
1480
  * один call onState; повторы (`useSyncExternalStore`-friendly).
1470
1481
  */
1471
1482
  export declare interface PaywallStateSnapshot {
1472
- /** Модалка отрендерена и видна. False — closed (или ещё не открывалась). */
1483
+ /** Модалка отрендерена и видна. False — closed (или ещё не открывалась).
1484
+ * Может быть false при `processing=true` — direct-checkout (paywall.checkout)
1485
+ * делает bootstrap + createCheckout headless до того, как решит надо ли
1486
+ * монтировать модалку. */
1473
1487
  open: boolean;
1474
1488
  /** Что показывается в модалке. null когда `open=false`. */
1475
1489
  view: 'loading' | 'error' | 'layout' | 'auth' | 'support' | 'awaiting_payment' | 'popup_blocked' | 'purchased' | null;
1476
1490
  /** Заполнено только когда `view === 'error'`. */
1477
1491
  error: PaywallError | null;
1492
+ /** SDK делает фоновую работу для `paywall.checkout(priceId)` — bootstrap,
1493
+ * visibility/trial-gates, createCheckout — до того, как реально нужна
1494
+ * UI-модалка. Хост на этой фазе может задизейблить свою кнопку и
1495
+ * показать спиннер прямо на ней, чтобы у юзера не было ощущения «клик
1496
+ * ничего не сделал». Сбрасывается в false сразу после mountAndShow
1497
+ * (модалка взяла на себя UI), либо после headless reject (already-paid,
1498
+ * ошибка createCheckout без модалки). Для `paywall.open()`-flow всегда
1499
+ * false: там модалка появляется мгновенно со своим LoadingView и
1500
+ * отдельный «processing» не нужен. */
1501
+ processing: boolean;
1478
1502
  }
1479
1503
 
1480
1504
  export declare class PaywallUI {
@@ -1616,26 +1640,39 @@ export declare class PaywallUI {
1616
1640
  */
1617
1641
  openSignup(opts?: OpenOptions): void;
1618
1642
  /**
1619
- * Direct-checkout: открыть модалку и сразу перейти к /start-checkout по
1620
- * конкретной цене, минуя layout с тарифами. Полезно когда host-приложение
1621
- * рендерит pricing-карточки/таблицу собственным UI и хочет, чтобы клик по
1622
- * «Buy / Get this plan» вёл прямо в платёжного провайдера, без второго
1623
- * выбора плана в модалке SDK.
1624
- *
1625
- * Что переиспользуется из обычного `open()`-flow:
1626
- * - `checkout_mode='preauth'` + managed-auth auth-gate (форма signin'а),
1627
- * после успеха auto-resume в createCheckout;
1628
- * - popup_blocked / awaiting_payment / purchase_success views;
1629
- * - UserWatcher polling после `checkout_started`;
1630
- * - аналитика `checkout_started`/`purchase_completed`/`purchase_failed`.
1631
- *
1632
- * Что отличается от `open()`:
1633
- * - layout с тарифами не показывается ни на один кадр (включая откат после
1634
- * ошибки модалка закрывается, эмитится `error`);
1635
- * - already-paid сценарий (cached user, fresh bootstrap, preauth-resume,
1636
- * 409 hasActivePurchase от бэка) — НЕ показывает restored success-view,
1637
- * эмитит `purchase_completed{restored:true}` и закрывает/не открывает
1638
- * модалку. Host сам решает как сообщить юзеру.
1643
+ * Direct-checkout: создать checkout-URL по конкретной цене и сразу открыть
1644
+ * платёжного провайдера, минуя layout с тарифами. Полезно когда
1645
+ * host-приложение рендерит pricing-карточки/таблицу собственным UI и
1646
+ * хочет, чтобы клик по «Buy / Get this plan» вёл прямо в Stripe/Paddle.
1647
+ *
1648
+ * **Late-mount UX.** В отличие от `open()`, модалка не появляется во время
1649
+ * фоновой работы (bootstrap + visibility/trial gates + createCheckout).
1650
+ * Хост на этой фазе показывает busy-state прямо на своей кнопке (через
1651
+ * `state.processing === true` из `paywall.getState()` — или автоматически
1652
+ * через `<PaywallButton priceId>` в sdk-react). Модалка монтируется
1653
+ * ТОЛЬКО когда реально нужна UI:
1654
+ * - `checkout_mode='preauth'` + managed-auth + не залогинен → auth-gate
1655
+ * (форма signin'а); после успеха auto-resume в createCheckout.
1656
+ * - popup провайдера заблокирован браузером → popup_blocked view с
1657
+ * retry-кнопкой под fresh user gesture.
1658
+ * - popup открылся успешно awaiting_payment view (индикатор «оплати
1659
+ * в новой вкладке» + I've paid).
1660
+ *
1661
+ * Что эмитится без модалки:
1662
+ * - `purchase_completed{restored:true, priceId}` когда юзер уже подписан
1663
+ * (cached user, fresh bootstrap, или 409 hasActivePurchase от бэка) —
1664
+ * headless reject;
1665
+ * - `error` когда createCheckout упал или identity.email отсутствует;
1666
+ * - `visibility_blocked` / `trial_blocked` — стандартные gate-эвенты.
1667
+ *
1668
+ * Что эмитится одновременно с модалкой:
1669
+ * - `checkout_started{priceId, url, acquiring}` ровно когда headless URL
1670
+ * получен, ДО mount'а awaiting_payment/popup_blocked.
1671
+ *
1672
+ * Offer (countdown-скидка) автоматически резолвится из cached offers'ов
1673
+ * через `getOfferForPrice(priceId)` и передаётся в createCheckout как
1674
+ * `offerId` — чтобы duration_minutes-офферы тоже применились на бэке
1675
+ * (для них нет server-side таймера, без явного offer-id скидка теряется).
1639
1676
  *
1640
1677
  * Требования:
1641
1678
  * - `identity.email` должен быть выставлен (через `opts.identity`, либо
@@ -1644,12 +1681,23 @@ export declare class PaywallUI {
1644
1681
  * - В `checkout_mode='preauth'` без managed-auth — backend требует
1645
1682
  * email-юзера; убедись что `identity.email` явно задан.
1646
1683
  *
1647
- * Без модалки/полностью headless (когда host рендерит свой checkout-UI и
1648
- * хочет только URL) — используй `paywall.billing.createCheckout({priceId})`
1649
- * напрямую, но тогда auth-gate / popup_blocked / awaiting_payment придётся
1650
- * рисовать самостоятельно.
1684
+ * Без модалки совсем (когда host рендерит свой awaiting-payment экран) —
1685
+ * используй `paywall.billing.createCheckout({priceId, offerId})` напрямую,
1686
+ * но тогда auth-gate / popup_blocked / awaiting_payment придётся рисовать
1687
+ * самостоятельно.
1651
1688
  */
1652
1689
  checkout(priceId: string, opts?: OpenOptions): void;
1690
+ /** Headless prep-work для `checkout(priceId, opts)`: bootstrap → gates →
1691
+ * preauth check → createCheckout → mount модалки с финальным view.
1692
+ * Вынесено отдельным методом ради чистого async/await flow вместо вложенных
1693
+ * then-chain'ов (5+ ветвей). Любая ошибка не пробрасывается наружу: эмитим
1694
+ * через `paywall.emit('error')` и выходим — host подписан на `error`-event. */
1695
+ private runDirectCheckout;
1696
+ /** Trial-check без mount'а (для late-mount direct-checkout). Возвращает
1697
+ * true если trial заблокировал — caller должен прекратить flow. На любой
1698
+ * storage-ошибке log+продолжаем (не блокируем продажу). */
1699
+ private checkTrialBeforeCheckout;
1700
+ private applyProcessing;
1653
1701
  /**
1654
1702
  * Headless anonymous signin без открытия модалки. Внутри:
1655
1703
  * idempotent (если уже анон — instant return) → resume через сохранённый
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ApiClient as t, ApiGatewayClient as a, AuthClient as i, BillingClient as o, EventTracker as l, PaywallError as f, QuotaExceededError as n, SDK_VERSION as s, STORAGE_KEYS as S, createStorage as E, ensureVisitorId as d, findApplicableOffer as p, generateVisitorId as c, offerStartStorageKey as g, readBrowserOfferStart as y, resolveOffer as A } from "./core.js";
2
- import { P as w, b as C } from "./chunks/PaywallUI-pb7JpLr6.js";
2
+ import { P as w, b as C } from "./chunks/PaywallUI-vv6Hw8su.js";
3
3
  export {
4
4
  t as ApiClient,
5
5
  a as ApiGatewayClient,
package/dist/ui.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./chunks/PaywallUI-CSgfmhHq.js");exports.PaywallUI=e.PaywallUI;exports.blockRegistry=e.blockRegistry;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./chunks/PaywallUI-DA8Kj9fJ.js");exports.PaywallUI=e.PaywallUI;exports.blockRegistry=e.blockRegistry;
2
2
  //# sourceMappingURL=ui.cjs.map
package/dist/ui.d.ts CHANGED
@@ -756,6 +756,17 @@ declare class BillingClient {
756
756
  errorUrl?: string;
757
757
  shopUrl?: string;
758
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;
759
770
  /**
760
771
  * Stage 1 защиты от дубликатов покупок. Идемпотентный ключ запроса
761
772
  * (UUID). Повторный вызов с тем же ключом вернёт тот же checkout-URL
@@ -1398,12 +1409,25 @@ declare type PaywallStateListener = (state: PaywallStateSnapshot) => void;
1398
1409
  * один call onState; повторы (`useSyncExternalStore`-friendly).
1399
1410
  */
1400
1411
  export declare interface PaywallStateSnapshot {
1401
- /** Модалка отрендерена и видна. False — closed (или ещё не открывалась). */
1412
+ /** Модалка отрендерена и видна. False — closed (или ещё не открывалась).
1413
+ * Может быть false при `processing=true` — direct-checkout (paywall.checkout)
1414
+ * делает bootstrap + createCheckout headless до того, как решит надо ли
1415
+ * монтировать модалку. */
1402
1416
  open: boolean;
1403
1417
  /** Что показывается в модалке. null когда `open=false`. */
1404
1418
  view: 'loading' | 'error' | 'layout' | 'auth' | 'support' | 'awaiting_payment' | 'popup_blocked' | 'purchased' | null;
1405
1419
  /** Заполнено только когда `view === 'error'`. */
1406
1420
  error: PaywallError | null;
1421
+ /** SDK делает фоновую работу для `paywall.checkout(priceId)` — bootstrap,
1422
+ * visibility/trial-gates, createCheckout — до того, как реально нужна
1423
+ * UI-модалка. Хост на этой фазе может задизейблить свою кнопку и
1424
+ * показать спиннер прямо на ней, чтобы у юзера не было ощущения «клик
1425
+ * ничего не сделал». Сбрасывается в false сразу после mountAndShow
1426
+ * (модалка взяла на себя UI), либо после headless reject (already-paid,
1427
+ * ошибка createCheckout без модалки). Для `paywall.open()`-flow всегда
1428
+ * false: там модалка появляется мгновенно со своим LoadingView и
1429
+ * отдельный «processing» не нужен. */
1430
+ processing: boolean;
1407
1431
  }
1408
1432
 
1409
1433
  export declare class PaywallUI {
@@ -1545,26 +1569,39 @@ export declare class PaywallUI {
1545
1569
  */
1546
1570
  openSignup(opts?: OpenOptions): void;
1547
1571
  /**
1548
- * Direct-checkout: открыть модалку и сразу перейти к /start-checkout по
1549
- * конкретной цене, минуя layout с тарифами. Полезно когда host-приложение
1550
- * рендерит pricing-карточки/таблицу собственным UI и хочет, чтобы клик по
1551
- * «Buy / Get this plan» вёл прямо в платёжного провайдера, без второго
1552
- * выбора плана в модалке SDK.
1553
- *
1554
- * Что переиспользуется из обычного `open()`-flow:
1555
- * - `checkout_mode='preauth'` + managed-auth auth-gate (форма signin'а),
1556
- * после успеха auto-resume в createCheckout;
1557
- * - popup_blocked / awaiting_payment / purchase_success views;
1558
- * - UserWatcher polling после `checkout_started`;
1559
- * - аналитика `checkout_started`/`purchase_completed`/`purchase_failed`.
1560
- *
1561
- * Что отличается от `open()`:
1562
- * - layout с тарифами не показывается ни на один кадр (включая откат после
1563
- * ошибки модалка закрывается, эмитится `error`);
1564
- * - already-paid сценарий (cached user, fresh bootstrap, preauth-resume,
1565
- * 409 hasActivePurchase от бэка) — НЕ показывает restored success-view,
1566
- * эмитит `purchase_completed{restored:true}` и закрывает/не открывает
1567
- * модалку. Host сам решает как сообщить юзеру.
1572
+ * Direct-checkout: создать checkout-URL по конкретной цене и сразу открыть
1573
+ * платёжного провайдера, минуя layout с тарифами. Полезно когда
1574
+ * host-приложение рендерит pricing-карточки/таблицу собственным UI и
1575
+ * хочет, чтобы клик по «Buy / Get this plan» вёл прямо в Stripe/Paddle.
1576
+ *
1577
+ * **Late-mount UX.** В отличие от `open()`, модалка не появляется во время
1578
+ * фоновой работы (bootstrap + visibility/trial gates + createCheckout).
1579
+ * Хост на этой фазе показывает busy-state прямо на своей кнопке (через
1580
+ * `state.processing === true` из `paywall.getState()` — или автоматически
1581
+ * через `<PaywallButton priceId>` в sdk-react). Модалка монтируется
1582
+ * ТОЛЬКО когда реально нужна UI:
1583
+ * - `checkout_mode='preauth'` + managed-auth + не залогинен → auth-gate
1584
+ * (форма signin'а); после успеха auto-resume в createCheckout.
1585
+ * - popup провайдера заблокирован браузером → popup_blocked view с
1586
+ * retry-кнопкой под fresh user gesture.
1587
+ * - popup открылся успешно awaiting_payment view (индикатор «оплати
1588
+ * в новой вкладке» + I've paid).
1589
+ *
1590
+ * Что эмитится без модалки:
1591
+ * - `purchase_completed{restored:true, priceId}` когда юзер уже подписан
1592
+ * (cached user, fresh bootstrap, или 409 hasActivePurchase от бэка) —
1593
+ * headless reject;
1594
+ * - `error` когда createCheckout упал или identity.email отсутствует;
1595
+ * - `visibility_blocked` / `trial_blocked` — стандартные gate-эвенты.
1596
+ *
1597
+ * Что эмитится одновременно с модалкой:
1598
+ * - `checkout_started{priceId, url, acquiring}` ровно когда headless URL
1599
+ * получен, ДО mount'а awaiting_payment/popup_blocked.
1600
+ *
1601
+ * Offer (countdown-скидка) автоматически резолвится из cached offers'ов
1602
+ * через `getOfferForPrice(priceId)` и передаётся в createCheckout как
1603
+ * `offerId` — чтобы duration_minutes-офферы тоже применились на бэке
1604
+ * (для них нет server-side таймера, без явного offer-id скидка теряется).
1568
1605
  *
1569
1606
  * Требования:
1570
1607
  * - `identity.email` должен быть выставлен (через `opts.identity`, либо
@@ -1573,12 +1610,23 @@ export declare class PaywallUI {
1573
1610
  * - В `checkout_mode='preauth'` без managed-auth — backend требует
1574
1611
  * email-юзера; убедись что `identity.email` явно задан.
1575
1612
  *
1576
- * Без модалки/полностью headless (когда host рендерит свой checkout-UI и
1577
- * хочет только URL) — используй `paywall.billing.createCheckout({priceId})`
1578
- * напрямую, но тогда auth-gate / popup_blocked / awaiting_payment придётся
1579
- * рисовать самостоятельно.
1613
+ * Без модалки совсем (когда host рендерит свой awaiting-payment экран) —
1614
+ * используй `paywall.billing.createCheckout({priceId, offerId})` напрямую,
1615
+ * но тогда auth-gate / popup_blocked / awaiting_payment придётся рисовать
1616
+ * самостоятельно.
1580
1617
  */
1581
1618
  checkout(priceId: string, opts?: OpenOptions): void;
1619
+ /** Headless prep-work для `checkout(priceId, opts)`: bootstrap → gates →
1620
+ * preauth check → createCheckout → mount модалки с финальным view.
1621
+ * Вынесено отдельным методом ради чистого async/await flow вместо вложенных
1622
+ * then-chain'ов (5+ ветвей). Любая ошибка не пробрасывается наружу: эмитим
1623
+ * через `paywall.emit('error')` и выходим — host подписан на `error`-event. */
1624
+ private runDirectCheckout;
1625
+ /** Trial-check без mount'а (для late-mount direct-checkout). Возвращает
1626
+ * true если trial заблокировал — caller должен прекратить flow. На любой
1627
+ * storage-ошибке log+продолжаем (не блокируем продажу). */
1628
+ private checkTrialBeforeCheckout;
1629
+ private applyProcessing;
1582
1630
  /**
1583
1631
  * Headless anonymous signin без открытия модалки. Внутри:
1584
1632
  * idempotent (если уже анон — instant return) → resume через сохранённый
package/dist/ui.js CHANGED
@@ -1,4 +1,4 @@
1
- import { P as o, b as r } from "./chunks/PaywallUI-pb7JpLr6.js";
1
+ import { P as o, b as r } from "./chunks/PaywallUI-vv6Hw8su.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.12",
3
+ "version": "3.0.0-alpha.14",
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,