@zap.stream/api
v0.1.0
Published
zap.stream API client — live streaming & account management for Nostr
Downloads
77
Maintainers
Readme
@zap.stream/api
TypeScript API client for zap.stream — live streaming & account management for Nostr.
Zero Nostr-library dependencies. Bring your own signer.
Install
bun add @zap.stream/apiUsage
Setup
Create a Signer — the only crypto interface the library needs. Any Nostr library works:
import { NostrStreamProvider, type Signer } from "@zap.stream/api";
const signer: Signer = {
getPubKey: () => myPublicKey, // hex pubkey string
sign: async (event) => myNostrLib.signEvent(event), // returns event with id & sig
};
const provider = new NostrStreamProvider("zap.stream", "https://api-core.zap.stream/api/v1", signer);Getting started — stream key & balance
The main flow: check your balance, get your stream key, top up if needed.
// 1. Check account info
const account = await provider.info();
console.log(`Balance: ${account.balance} sats`);
// Endpoints contain the stream key you push to via RTMP
for (const ep of account.endpoints) {
console.log(`Endpoint: ${ep.name}`);
console.log(` URL: ${ep.url}`);
console.log(` Stream key: ${ep.key}`);
console.log(` Cost: ${ep.cost.rate} sats/${ep.cost.unit}`);
}
// 2. Top up if balance is low
if (account.balance < 1000) {
const invoice = await provider.topup(10000); // 10k sats
// Hand this invoice to the user's wallet
console.log(`Pay this invoice: ${invoice.pr}`);
}Withdrawing
const result = await provider.withdraw(bolt11Invoice);
console.log(`Fee: ${result.fee} sats`);
console.log(`Preimage: ${result.preimage}`);Balance history
const history = await provider.history(0, 20);
for (const item of history.items) {
console.log(`${new Date(item.created * 1000).toISOString()}: ${item.amount} sats`);
}Accepting terms of service
New accounts need to accept TOS before streaming:
const account = await provider.info();
if (account.tos && !account.tos.accepted) {
console.log(`TOS available at: ${account.tos.link}`);
await provider.acceptTos();
}Updating stream details
await provider.updateStream({
title: "Building stuff live",
summary: "Nostr dev stream",
tags: ["coding", "nostr"],
image: "https://example.com/thumbnail.jpg",
});
// Or update from a Nostr live event
import { extractStreamInfo } from "@zap.stream/api";
await provider.updateStreamFromEvent(myLiveEvent, extractStreamInfo);Real-time metrics (WebSocket)
provider.subscribeToMetrics(streamId, (metrics) => {
console.log(`Viewers: ${metrics.data?.viewers}`);
const stats = metrics.data?.endpoint_stats;
if (stats) {
for (const ep of Object.values(stats)) {
console.log(`${ep.name}: ${ep.bitrate} bps`);
}
}
});
provider.unsubscribeFromMetrics(streamId);
provider.closeWebSocket();Wallet integration (NWC)
await provider.configureNwc("nostr+wallet://…");
await provider.removeNwc();Stream forwarding
await provider.addForward("my-relay", "wss://relay.example.com");
await provider.removeForward(forwardId);Clips
const clip = await provider.prepareClip(streamId);
const result = await provider.createClip(streamId, clip.id, start, length);Notifications (Web Push)
const { publicKey } = await provider.getNotificationsInfo();
await provider.subscribeNotifications({ endpoint, key, auth, scope });Game database
import { GameDatabase } from "@zap.stream/api";
const db = new GameDatabase();
const games = await db.searchGames("minecraft", 10);
const game = await db.getGame("igdb:1234");Clock sync
import { timeSync } from "@zap.stream/api";
await timeSync.syncClock(); // call once at startup
console.log(timeSync.offset); // ms offset from serverThe Signer interface
The only crypto dependency. Two methods:
interface Signer {
getPubKey(): string | Promise<string>;
sign(event: NostrEvent): Promise<NostrEvent>;
}Adapting @snort/system
import { EventPublisher } from "@snort/system";
function adaptPublisher(pub: EventPublisher): Signer {
return {
getPubKey: () => pub.pubKey,
sign: async (event) => {
return await pub.generic(eb => {
let builder = eb.kind(event.kind).content(event.content).createdAt(event.created_at);
for (const tag of event.tags) {
builder = builder.tag(tag);
}
return builder;
});
},
};
}Dependencies
@scure/base— base64 encoding for NIP-98 auth tokens
No Nostr library, no framework, no bundler plugin required.
License
MIT
