@litepush/sdk
v0.2.1
Published
Web Push SDK for LitePush — a side-effect-free browser client and a typed server REST client. Drop-in web push for indie devs.
Maintainers
Readme
@litepush/sdk
Web Push SDK for LitePush — drop-in Web Push for indie devs.
Three ways to use it, one package:
<script>tag — the zero-build drop-in, served fromhttps://litepush.dev/sdk.js.- Browser client (
@litepush/sdk) — an importable, side-effect-freeLitePushClientfor bundler / framework apps. - Server client (
@litepush/sdk/server) — a typed REST client for sending broadcasts and managing groups / subscribers from your backend.
npm install @litepush/sdk1. Drop-in <script> tag (no build step)
Two files, three lines. That's the whole pitch.
<!-- 1. Load the SDK -->
<script src="https://litepush.dev/sdk.js"
data-project="prj_YOUR_PROJECT_ID"
data-vapid-key="YOUR_VAPID_PUBLIC_KEY"
async
></script>
<!-- 2. Subscribe the current visitor when ready -->
<script>
(window.litepushQ = window.litepushQ || []).push((lp) => {
document.getElementById('enable-notifs').addEventListener('click', async () => {
const result = await lp.subscribe({ userId: 'user_42' });
if (result) console.log('subscribed!', result.id);
});
});
</script>Plus: copy litepush-sw.js into the site's public/ folder so the browser can
register it at <origin>/litepush-sw.js.
window.litepush surface: subscribe({ userId? }) → { id } | null,
unsubscribe() → boolean, isSubscribed() → boolean,
canSubscribe() → boolean (sync), version.
2. Browser client (bundlers / frameworks)
Same capabilities, but importable and side-effect-free — constructing a client
does not touch window or read the DOM, so it's safe under SSR.
import { LitePushClient, canSubscribe } from "@litepush/sdk";
const lp = new LitePushClient({
projectId: "prj_YOUR_PROJECT_ID",
vapidKey: "YOUR_VAPID_PUBLIC_KEY",
});
if (canSubscribe()) {
// Must be called from a user gesture (click / tap).
const result = await lp.subscribe({ userId: "user_42" });
if (result) console.log("subscribed!", result.id);
}| Method | Purpose |
|---|---|
| new LitePushClient({ projectId, vapidKey, apiBase?, swPath? }) | Construct a client. No side effects. |
| lp.subscribe({ userId? }) | Request permission, create subscription, register. Returns { id } \| null. |
| lp.unsubscribe() | Remove the current browser's subscription. Returns boolean. |
| lp.isSubscribed() | Whether this browser currently has an active subscription. |
| lp.canSubscribe() | Whether the browser supports Web Push. Synchronous. |
| lp.version | SDK version string. |
You still need the service worker. Like the
<script>tag, the browser client registers a service worker on your origin — installing the npm package does not provide it, because a service worker must be served same-origin with your site (it can't be imported fromnode_modulesor loaded cross-origin). Hostlitepush-sw.jsat your origin root so it's reachable at<origin>/litepush-sw.js(theLitePushClientdefault; override withswPath). Grab the file from https://litepush.dev/litepush-sw.js or your project's dashboard, and serve it from yourpublic/folder.
3. Server client (@litepush/sdk/server)
A typed wrapper over the Bearer-authed REST API. Zero dependencies — uses the
global fetch (Node 18+, Bun, Deno, Cloudflare Workers). Server-side only —
never embed your API key in client code.
import { LitePush, LitePushApiError } from "@litepush/sdk/server";
const litepush = new LitePush(process.env.LITEPUSH_API_KEY!);
try {
const { broadcast_id } = await litepush.broadcasts.create({
target: { type: "all" },
notification: {
title: "New post on the blog",
body: "We just shipped Web Push support.",
url: "https://myblog.com/posts/web-push",
},
});
console.log("queued", broadcast_id);
} catch (err) {
if (err instanceof LitePushApiError) {
// err.code is stable (e.g. "monthly_push_limit_reached"); branch on it.
console.error(err.code, err.status, err.message);
}
}| Method | REST endpoint |
|---|---|
| litepush.me() | GET /v1/me |
| litepush.broadcasts.create(params) | POST /v1/send |
| litepush.broadcasts.get(id) | GET /v1/broadcasts/:id |
| litepush.broadcasts.list({ limit?, offset? }) | GET /v1/broadcasts |
| litepush.broadcasts.cancel(id) | DELETE /v1/broadcasts/:id |
| litepush.groups.list() | GET /v1/groups |
| litepush.groups.create({ name, description? }) | POST /v1/groups |
| litepush.groups.update(id, { name?, description? }) | PATCH /v1/groups/:id |
| litepush.groups.delete(id) | DELETE /v1/groups/:id |
| litepush.groups.addSubscribers(id, ids) | POST /v1/groups/:id/subscribers |
| litepush.groups.removeSubscriber(id, sid) | DELETE /v1/groups/:id/subscribers/:sid |
| litepush.subscribers.deleteByEndpoint(endpoint) | DELETE /v1/subscribers/by-endpoint |
| litepush.subscribers.deleteByExternalId(eid) | DELETE /v1/subscribers/by-external-id/:eid |
| litepush.subscribers.exportCsv() | GET /v1/subscribers/export (returns CSV text) |
Config: new LitePush("lpk_live_…") or
new LitePush({ apiKey, baseUrl?, fetch? }). Pass a fetch implementation on
Node < 18.
Full REST reference: https://litepush.dev/docs/api/concepts.
Development
bun run build # clean → stamp version → IIFE (sdk.js) + worker → ESM + .d.ts
bun run dev # rebuild sdk.js on change
bun run typecheck # tsc --noEmit (browser/server) + tsc -p tsconfig.sw.json (worker)
bun run test # vitest (helpers + server client)bun run build produces, into dist/:
stamp-version.ts— writessrc/version.tsfrompackage.json, so every output reports one version.vite build— bundlessrc/iife.tsintodist/sdk.js(IIFE, ES2022, minified) — the public<script>asset hosted athttps://litepush.dev/sdk.js.vite build -c vite.sw.config.ts— bundlessrc/sw.tsintodist/litepush-sw.js— the classic service worker, served athttps://litepush.dev/litepush-sw.js, which customers copy into their ownpublic/folder.tsc -p tsconfig.build.json— the ESM library +.d.tsintodist/esm/(dist/esm/index.js/dist/esm/server.js).tsc -p tsconfig.cjs.json— the CommonJS build intodist/cjs/(with its ownpackage.jsonmarking it commonjs) forrequire()consumers.
The IIFE assets (sdk.js, litepush-sw.js) stay at the dist root; the ESM and
CJS libraries live in dist/esm/ and dist/cjs/.
The package is dual ESM/CJS (the exports map serves import and require),
side-effect-free / tree-shakable (only sdk.js + litepush-sw.js are marked as
having side effects), and relative imports carry .js extensions so it resolves
under Node's native ESM, not just bundlers. The service worker is typed against
the WebWorker lib (src/sw.ts + tsconfig.sw.json), separate from the
DOM-typed browser code.
License
Apache-2.0 © LitePush
