xnotif 0.2.0-beta.1 → 0.2.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
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/xnotif)](https://www.npmjs.com/package/xnotif)
4
4
  [![CI](https://github.com/yutakobayashidev/xnotif/actions/workflows/ci.yml/badge.svg)](https://github.com/yutakobayashidev/xnotif/actions/workflows/ci.yml)
5
+ [![DeepWiki](https://img.shields.io/badge/DeepWiki-yutakobayashidev%2Fxnotif-blue.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAyCAYAAAAnWDnqAAAAAXNSR0IArs4c6QAAA05JREFUaEPtmUtyEzEQhtWTQyQLHNak2AB7ZnyXZMEjXMGeK/AIi+QuHrMnbChYY7MIh8g01fJoopFb0uhhEqqcbWTp06/uv1saEDv4O3n3dV60RfP947Mm9/SQc0ICFQgzfc4CYZoTPAswgSJCCUJUnAAoRHOAUOcATwbmVLWdGoH//PB8mnKqScAhsD0kYP3j/Yt5LPQe2KvcXmGvRHcDnpxfL2zOYJ1mFwrryWTz0advv1Ut4CJgf5uhDuDj5eUcAUoahrdY/56ebRWeraTjMt/00Sh3UDtjgHtQNHwcRGOC98BJEAEymycmYcWwOprTgcB6VZ5JK5TAJ+fXGLBm3FDAmn6oPPjR4rKCAoJCal2eAiQp2x0vxTPB3ALO2CRkwmDy5WohzBDwSEFKRwPbknEggCPB/imwrycgxX2NzoMCHhPkDwqYMr9tRcP5qNrMZHkVnOjRMWwLCcr8ohBVb1OMjxLwGCvjTikrsBOiA6fNyCrm8V1rP93iVPpwaE+gO0SsWmPiXB+jikdf6SizrT5qKasx5j8ABbHpFTx+vFXp9EnYQmLx02h1QTTrl6eDqxLnGjporxl3NL3agEvXdT0WmEost648sQOYAeJS9Q7bfUVoMGnjo4AZdUMQku50McDcMWcBPvr0SzbTAFDfvJqwLzgxwATnCgnp4wDl6Aa+Ax283gghmj+vj7feE2KBBRMW3FzOpLOADl0Isb5587h/U4gGvkt5v60Z1VLG8BhYjbzRwyQZemwAd6cCR5/XFWLYZRIMpX39AR0tjaGGiGzLVyhse5C9RKC6ai42ppWPKiBagOvaYk8lO7DajerabOZP46Lby5wKjw1HCRx7p9sVMOWGzb/vA1hwiWc6jm3MvQDTogQkiqIhJV0nBQBTU+3okKCFDy9WwferkHjtxib7t3xIUQtHxnIwtx4mpg26/HfwVNVDb4oI9RHmx5WGelRVlrtiw43zboCLaxv46AZeB3IlTkwouebTr1y2NjSpHz68WNFjHvupy3q8TFn3Hos2IAk4Ju5dCo8B3wP7VPr/FGaKiG+T+v+TQqIrOqMTL1VdWV1DdmcbO8KXBz6esmYWYKPwDL5b5FA1a0hwapHiom0r/cKaoqr+27/XcrS5UwSMbQAAAABJRU5ErkJggg==)](https://deepwiki.com/yutakobayashidev/xnotif)
5
6
 
6
7
  Receive Twitter/X notifications in real-time. No API key, no scraping — just Web Push.
7
8
 
@@ -27,6 +28,13 @@ npm install xnotif
27
28
 
28
29
  > Requires Node.js >= 22.0.0
29
30
 
31
+ ## Why xnotif
32
+
33
+ - **Cookie exposure can be minimized** - Cookies are mainly used for one registration call to `POST /1.1/notifications/settings/login.json`. After registration, notifications are received through Mozilla Autopush WebSocket, so you are not continuously calling internal Twitter endpoints with cookies.
34
+ - **Lower ban-risk profile than polling/scraping** - xnotif avoids headless-browser automation and high-frequency private API polling. The runtime traffic pattern is mostly one registration plus push-stream consumption.
35
+ - **Avoid unnecessary re-registration** - If you persist `ClientState` from the `connected` event, restart with `state`, and the endpoint is unchanged, xnotif skips the registration call.
36
+ - **Simple operations** - No API key provisioning, no webhook server, and no request-signing stack. A single Node.js process can receive and process notifications.
37
+
30
38
  ## Notification Payload
31
39
 
32
40
  Each `notification` event delivers a `TwitterNotification` object:
@@ -88,10 +96,24 @@ await client.start();
88
96
 
89
97
  ### `createClient(options)`
90
98
 
91
- | Option | Type | Required | Description |
92
- | --------- | ------------------------------------- | -------- | ---------------------- |
93
- | `cookies` | `{ auth_token: string; ct0: string }` | Yes | Session cookies |
94
- | `state` | `ClientState` | No | Restore previous state |
99
+ | Option | Type | Required | Description |
100
+ | --------- | ------------------------------------------------ | -------- | --------------------------------- |
101
+ | `cookies` | `{ auth_token: string; ct0: string }` | Yes | Session cookies |
102
+ | `state` | `ClientState` | No | Restore previous state |
103
+ | `filter` | `(notification: TwitterNotification) => boolean` | No | Predicate to filter notifications |
104
+
105
+ #### Filtering Notifications
106
+
107
+ Pass a `filter` function to receive only the notifications you care about:
108
+
109
+ ```typescript
110
+ const client = createClient({
111
+ cookies: { auth_token: "...", ct0: "..." },
112
+ filter: (n) => n.data?.type === "tweet",
113
+ });
114
+ ```
115
+
116
+ The predicate receives the decrypted `TwitterNotification` object. Return `true` to emit the notification, `false` to discard it silently. If the filter throws an exception, the notification is discarded and an `error` event is emitted.
95
117
 
96
118
  ### Events
97
119
 
package/dist/index.d.mts CHANGED
@@ -48,6 +48,7 @@ interface NotificationClientOptions {
48
48
  [key: string]: string;
49
49
  };
50
50
  state?: ClientState;
51
+ filter?: (notification: TwitterNotification) => boolean;
51
52
  }
52
53
  //#endregion
53
54
  //#region src/client.d.ts
package/dist/index.mjs CHANGED
@@ -385,6 +385,12 @@ var NotificationClient = class extends EventEmitter {
385
385
  const payload = base64urlToBuffer(msg.data);
386
386
  const json = await decryptor.decrypt(msg.headers.crypto_key, msg.headers.encryption, payload);
387
387
  const notification = JSON.parse(json);
388
+ if (this.options.filter) try {
389
+ if (!this.options.filter(notification)) return;
390
+ } catch (filterErr) {
391
+ this.emit("error", filterErr instanceof Error ? filterErr : new Error(String(filterErr)));
392
+ return;
393
+ }
388
394
  this.emit("notification", notification);
389
395
  } catch (err) {
390
396
  this.emit("error", err instanceof Error ? err : new Error(String(err)));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xnotif",
3
- "version": "0.2.0-beta.1",
3
+ "version": "0.2.0",
4
4
  "description": "Receive Twitter/X push notifications programmatically via Mozilla Autopush",
5
5
  "keywords": [
6
6
  "autopush",