scrapebadger 0.1.9 → 0.3.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.
package/README.md CHANGED
@@ -202,6 +202,112 @@ const nearby = await client.twitter.geo.search({
202
202
  const place = await client.twitter.geo.getDetail("5a110d312052166f");
203
203
  ```
204
204
 
205
+ ### Stream Monitoring
206
+
207
+ Real-time tweet monitoring with WebSocket streaming and webhook delivery.
208
+
209
+ ```typescript
210
+ import { ScrapeBadger, WebSocketStreamError } from "scrapebadger";
211
+
212
+ const client = new ScrapeBadger({ apiKey: "your-api-key" });
213
+
214
+ // Create a monitor
215
+ const monitor = await client.twitter.stream.createMonitor({
216
+ name: "Tech Leaders",
217
+ usernames: ["elonmusk", "naval", "sama"],
218
+ pollIntervalSeconds: 10,
219
+ webhookUrl: "https://example.com/webhook",
220
+ });
221
+ console.log(`Created: ${monitor.id}, tier: ${monitor.pricing_tier}`);
222
+ console.log(`Credits/hr: ${monitor.estimated_credits_per_hour}`);
223
+
224
+ // List monitors
225
+ const { monitors, total } = await client.twitter.stream.listMonitors({ status: "active" });
226
+ console.log(`${total} active monitors`);
227
+
228
+ // Pause / resume
229
+ await client.twitter.stream.pauseMonitor(monitor.id);
230
+ await client.twitter.stream.resumeMonitor(monitor.id);
231
+
232
+ // Delete
233
+ await client.twitter.stream.deleteMonitor(monitor.id);
234
+ ```
235
+
236
+ #### EventEmitter streaming
237
+
238
+ ```typescript
239
+ const stream = client.twitter.stream.connect({
240
+ reconnect: true,
241
+ reconnectDelaySeconds: 90,
242
+ });
243
+
244
+ stream.on("connected", (e) => {
245
+ console.log("Connected, connection ID:", e.connectionId);
246
+ });
247
+
248
+ stream.on("tweet", (event) => {
249
+ console.log(`@${event.authorUsername}: ${event.tweet.text}`);
250
+ console.log(` latency: ${event.latencyMs}ms`);
251
+ });
252
+
253
+ stream.on("error", (err) => {
254
+ if (err instanceof WebSocketStreamError && err.code === 4001) {
255
+ console.error("API key rejected");
256
+ } else {
257
+ console.error("Stream error:", err.message);
258
+ }
259
+ });
260
+
261
+ stream.on("close", () => console.log("Stream closed"));
262
+
263
+ // Later: graceful disconnect
264
+ stream.close();
265
+ ```
266
+
267
+ #### AsyncIterator streaming
268
+
269
+ ```typescript
270
+ import { WebSocketStreamError } from "scrapebadger";
271
+
272
+ try {
273
+ for await (const event of client.twitter.stream.connectIter({
274
+ reconnect: true,
275
+ reconnectDelaySeconds: 90,
276
+ })) {
277
+ if (event.type === "tweet") {
278
+ console.log(`@${event.authorUsername}: ${event.latencyMs}ms latency`);
279
+ }
280
+ }
281
+ } catch (err) {
282
+ if (err instanceof WebSocketStreamError) {
283
+ console.error("Stream failed:", err.message, err.code);
284
+ }
285
+ }
286
+ ```
287
+
288
+ #### Webhook signature verification
289
+
290
+ ```typescript
291
+ import { verifyWebhookSignature } from "scrapebadger/twitter";
292
+ import express from "express";
293
+
294
+ const app = express();
295
+
296
+ app.post(
297
+ "/webhook",
298
+ express.raw({ type: "application/json" }),
299
+ (req, res) => {
300
+ const sig = req.headers["x-scrapebadger-signature"] as string;
301
+ if (!verifyWebhookSignature("my-webhook-secret", req.body, sig)) {
302
+ return res.status(401).json({ error: "Invalid signature" });
303
+ }
304
+ const event = JSON.parse(req.body.toString());
305
+ console.log("Received tweet:", event.tweet_id);
306
+ res.sendStatus(200);
307
+ }
308
+ );
309
+ ```
310
+
205
311
  ## Error Handling
206
312
 
207
313
  ```typescript
@@ -267,10 +373,26 @@ const client = new ScrapeBadger({
267
373
  - `client.twitter.communities` - Community operations
268
374
  - `client.twitter.trends` - Trend operations
269
375
  - `client.twitter.geo` - Geographic place operations
376
+ - `client.twitter.stream` - Real-time stream monitor management and WebSocket streaming
377
+
378
+ ### Stream Client Methods
379
+
380
+ - `createMonitor(params)` - Create a stream monitor
381
+ - `listMonitors(options?)` - List monitors with optional status filter
382
+ - `getMonitor(id)` - Get a monitor by ID
383
+ - `updateMonitor(id, params)` - Partially update a monitor
384
+ - `pauseMonitor(id)` - Pause an active monitor
385
+ - `resumeMonitor(id)` - Resume a paused monitor
386
+ - `deleteMonitor(id)` - Delete a monitor (irreversible)
387
+ - `listDeliveryLogs(options?)` - List tweet delivery logs
388
+ - `listBillingLogs(options?)` - List billing activity logs
389
+ - `connect(options?)` - Connect via EventEmitter (`.on("tweet", handler)`)
390
+ - `connectIter(options?)` - Connect via AsyncIterator (`for await`)
270
391
 
271
392
  ### Utilities
272
393
 
273
394
  - `collectAll(asyncIterator)` - Collect async iterator results into an array
395
+ - `verifyWebhookSignature(secret, body, header)` - Verify incoming webhook HMAC signature
274
396
 
275
397
  ### Exceptions
276
398
 
@@ -283,6 +405,7 @@ const client = new ScrapeBadger({
283
405
  - `TimeoutError` - Request timeout
284
406
  - `InsufficientCreditsError` - Out of credits
285
407
  - `AccountRestrictedError` - Account restricted
408
+ - `WebSocketStreamError` - WebSocket stream failure (auth, limit, or network)
286
409
 
287
410
  ## Requirements
288
411