JSPM

  • Created
  • Published
  • Downloads 136
  • Score
    100M100P100Q112434F
  • License MIT

Monetize SDK for Chrome extensions — single source of truth via offscreen document, drop-in compatible with @monetize.software/sdk public API

Package Exports

  • @monetize.software/sdk-extension
  • @monetize.software/sdk-extension/offscreen
  • @monetize.software/sdk-extension/offscreen.html
  • @monetize.software/sdk-extension/sw

Readme

@monetize.software/sdk-extension

SDK для Chrome-расширений. Один offscreen-документ держит BillingClient, AuthClient, EventTracker — единственный source of truth для всех вкладок, popup'ов, side-panel'ов и extension-страниц расширения.

Public API content-script'а drop-in совместим с @monetize.software/sdk — host пишет import { PaywallUI } from '@monetize.software/sdk-extension' и получает тот же класс, тот же метод-сет.

Архитектура

content script (per tab) ──port──▶ service worker ──port──▶ offscreen
        │                              (forwarder)              │
   Shadow DOM modal                                  BillingClient
   RemoteBillingClient                               AuthClient
                                                     EventTracker
                                                     UserWatcher
  • content-script: UI + RemoteBillingClient (proxy через port в offscreen).
  • service worker: маршрутизатор content↔offscreen, OAuth-флоу через chrome.identity (offscreen его не видит).
  • offscreen: реальный SDK state, переживает закрытие вкладок, единственная точка координации auth-refresh / trial-counter / analytics-batch.

Статус

Phase 0 — скелет: package.json, vite multi-entry, wire-protocol типы, заглушки на content/offscreen/sw + demo-extension манифест. Реальная маршрутизация и RemoteBillingClient — следующие фазы.

См. TODO в репозитории и src/shared/protocol.ts для контракта сообщений.

Использование (целевое, в финале)

В extension'е:

// service-worker.ts
import { installRouter } from '@monetize.software/sdk-extension/sw';
installRouter({ offscreenUrl: chrome.runtime.getURL('offscreen.html') });
// offscreen.html → offscreen.ts
import { startOffscreenServer } from '@monetize.software/sdk-extension/offscreen';
startOffscreenServer({ paywallId: '...', apiOrigin: 'https://...' });
// content-script.ts (на каждой вкладке)
import { PaywallUI } from '@monetize.software/sdk-extension';
const paywall = new PaywallUI({ paywallId: '...', apiOrigin: '...' });
paywall.open();  // ровно как в @monetize.software/sdk

На сайтах — продолжаем использовать @monetize.software/sdk, не меняется.

Manifest: что прописывать в host extension'е

SDK сам по себе ничего в манифест не добавляет — host extension решает permissions под свой UX. Минимум для работы SDK:

{
  "permissions": ["offscreen", "storage"],
  "host_permissions": ["https://api.monetize.software/*"],
  "background": { "service_worker": "sw.js", "type": "module" }
}

Опционально:

  • "permissions": ["identity"] — если включаете OAuth-флоу (auth: true + Google/etc.).
  • web_accessible_resources для offscreen.html не нужен — документ создаётся service worker'ом через chrome.offscreen.createDocument, это chrome-API и WAR не требует. Указывать его — лишняя attack surface (любой сайт сможет <iframe>-нить ваш offscreen, плюс это fingerprint вашего extension ID).

host_permissions — что выбрать

host_permissions управляют двумя вещами: куда extension может делать fetch (из offscreen / SW / content-script) и на какие origin'ы content-script может инжектиться (вместе с content_scripts.matches).

Сценарий Рекомендация
Host extension'у <all_urls> уже нужен (рекордер, тулза-на-всех-сайтах, ассистент) Оставляйте <all_urls>. SDK работает как есть. Риск: Chrome Web Store review для <all_urls> идёт через ручной audit и занимает дольше; AV-вендоры (Avast/Kaspersky/etc.) активнее метят такие расширения как PUA. Это «цена» широкого инжекта — не SDK'шный риск, а вашего use-case'а.
Host extension ходит только на ваш бекенд и paywall'ит свои фичи (popup-tool, side-panel app) НЕ ставьте <all_urls>. Достаточно вашего apiOrigin: ["https://api.your-domain.com/*"]. Никакого content-script инжекта на все сайты не нужно.
Хотите гибрид — popup-tool, но иногда content-script нужен на узком списке доменов host_permissions + content_scripts.matches ограничьте до этих доменов: ["https://*.your-target.com/*", "https://api.your-domain.com/*"].

Главный сигнал для CWS/AV: чем уже host_permissions, тем меньше подозрений. <all_urls> оставляйте только если он реально нужен для UX, и будьте готовы обосновать его в CWS review (поле "Permission justification").

Demo extension'а: build modes

Для self-проверки и e2e-тестов есть demo-extension/ — reference-imple­ментация. Билдов два:

pnpm build:demo       # production build (= шаблон, который можно копировать клиентам)
pnpm build:demo:e2e   # debug build — экспонирует window.__paywall для playwright'а

build:demo НЕ кладёт window.__paywall в bundle (dead-code elimination через import.meta.env.MODE !== 'e2e'). Шаблон, который клиент копирует, остаётся чистым: любой script на странице иначе мог бы дёрнуть paywall.open() / paywall.track() и злоупотреблять чужим extension'ом.

pnpm dev:demo собирает в e2e-режиме (для удобной отладки из DevTools-консоли).