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 +26 -4
- package/dist/index.d.mts +1 -0
- package/dist/index.mjs +6 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/xnotif)
|
|
4
4
|
[](https://github.com/yutakobayashidev/xnotif/actions/workflows/ci.yml)
|
|
5
|
+
[](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
|
|
92
|
-
| --------- |
|
|
93
|
-
| `cookies` | `{ auth_token: string; ct0: string }`
|
|
94
|
-
| `state` | `ClientState`
|
|
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
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)));
|