e621stream 0.0.0-stage → 0.0.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/LICENSE +21 -0
- package/README.md +38 -2
- package/dist/E621Stream.d.ts +95 -0
- package/dist/E621Stream.js +180 -0
- package/dist/E621Stream.js.map +1 -0
- package/dist/Emitter.d.ts +12 -0
- package/dist/Emitter.js +33 -0
- package/dist/Emitter.js.map +1 -0
- package/dist/changes.d.ts +30 -0
- package/dist/changes.js +2 -0
- package/dist/changes.js.map +1 -0
- package/dist/events.d.ts +54 -0
- package/dist/events.js +138 -0
- package/dist/events.js.map +1 -0
- package/dist/generated.d.ts +1204 -0
- package/dist/generated.js +4 -0
- package/dist/generated.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/package.json +46 -3
- package/tsconfig.json +32 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) undefined Donovan_DMC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,39 @@
|
|
|
1
|
-
#
|
|
1
|
+
# e621stream
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A TypeScript client for [E621Stream](https://e621.stream), a live WebSocket stream of e621 activity. It works in Node 22+, Bun, Deno and browsers, has no dependencies, and every event type is typed down to the record it carries.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install e621stream
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { E621Stream } from "e621stream";
|
|
11
|
+
|
|
12
|
+
const stream = new E621Stream({
|
|
13
|
+
auth: { username: "your_name", apiKey: "your e621 api key" },
|
|
14
|
+
subscriptions: ["post.create", { type: "post.update", filter: { tags: "fox -solo" } }, "comment.*"],
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
stream.on("post.create", (event) => {
|
|
18
|
+
console.log(event.data.post.id, event.data.post.tags.general);
|
|
19
|
+
});
|
|
20
|
+
stream.on("post.update", (event) => {
|
|
21
|
+
// only the fields that changed, tags per category
|
|
22
|
+
console.log(event.data.changes?.["tags.general"]?.added);
|
|
23
|
+
});
|
|
24
|
+
stream.on("comment.update", (event) => {
|
|
25
|
+
console.log(event.data.comment.id, event.data.changes?.body?.old, "->", event.data.changes?.body?.new);
|
|
26
|
+
});
|
|
27
|
+
stream.on("error", err => console.error(err));
|
|
28
|
+
stream.connect();
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- **Events:** `on("<event type>", ...)` for one type, typed to its data, or `on("dispatch", ...)` for everything, narrowed by checking `event.type`. See [Events](https://e621.stream/events/) for what each one is.
|
|
32
|
+
- **Reconnecting:** the connection is reopened with backoff when it drops, and resumes from the last event it got, so nothing is missed. It isn't reopened after a close retrying won't fix, like bad credentials. `reconnect: false` turns it off.
|
|
33
|
+
- **Resuming:** pass `cursor` (an event id, or a millisecond timestamp) to replay from there. `stream.cursor` is the last event received.
|
|
34
|
+
- **Changing subscriptions:** `stream.subscribe([...])`.
|
|
35
|
+
- **Private events:** like `dmail.create`, these are polled with your own credentials and have to be subscribed to by name.
|
|
36
|
+
- **Other events:** `ready`, `replayComplete`, `subscribed`, `reconnecting`, `close` and `error`.
|
|
37
|
+
- **Older Node:** pass a WebSocket implementation, like the `ws` package, as the `WebSocket` option.
|
|
38
|
+
|
|
39
|
+
Event data comes from the [e621 module](https://www.npmjs.com/package/e621)'s types, so records like `LegacyPost`, `Comment` and `ForumTopic` are exported here too. Mod action events are typed per action: checking `event.data.action` narrows `event.data.values`.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import Emitter from "./Emitter.ts";
|
|
2
|
+
import { type EventType, type PrivateEventType, type StreamEvent, type Subscription } from "./events.ts";
|
|
3
|
+
export interface Options {
|
|
4
|
+
/** your e621 username and an api key, from Account > Manage API Access */
|
|
5
|
+
auth?: {
|
|
6
|
+
apiKey: string;
|
|
7
|
+
username: string;
|
|
8
|
+
};
|
|
9
|
+
/** a name for your client, shown in the server's logs */
|
|
10
|
+
client?: string;
|
|
11
|
+
/** an event id (or a millisecond timestamp) to replay from. after that, reconnecting resumes from the last event */
|
|
12
|
+
cursor?: number | string;
|
|
13
|
+
/** reconnects with backoff when the connection drops, unless the server closed it for something retrying won't fix */
|
|
14
|
+
reconnect?: boolean;
|
|
15
|
+
subscriptions: Array<Subscription>;
|
|
16
|
+
url?: string;
|
|
17
|
+
/** for runtimes without a global WebSocket, like node before 22 (the `ws` package works) */
|
|
18
|
+
WebSocket?: typeof WebSocket;
|
|
19
|
+
}
|
|
20
|
+
export interface Ready {
|
|
21
|
+
/** when replaying, set if the cursor was older than anything still kept */
|
|
22
|
+
cursor_expired?: boolean;
|
|
23
|
+
replaying: boolean;
|
|
24
|
+
session_id: string;
|
|
25
|
+
subscriptions: Array<Subscription>;
|
|
26
|
+
user: {
|
|
27
|
+
id: number;
|
|
28
|
+
level: number;
|
|
29
|
+
level_string: string;
|
|
30
|
+
name: string;
|
|
31
|
+
} | null;
|
|
32
|
+
}
|
|
33
|
+
export interface ClientEvents {
|
|
34
|
+
close: [{
|
|
35
|
+
code: number;
|
|
36
|
+
reason: string;
|
|
37
|
+
reconnecting: boolean;
|
|
38
|
+
}];
|
|
39
|
+
/** every event, public or private */
|
|
40
|
+
dispatch: [StreamEvent];
|
|
41
|
+
error: [Error];
|
|
42
|
+
ready: [Ready];
|
|
43
|
+
reconnecting: [{
|
|
44
|
+
attempt: number;
|
|
45
|
+
delayMS: number;
|
|
46
|
+
}];
|
|
47
|
+
/** replay is done, live events follow */
|
|
48
|
+
replayComplete: [{
|
|
49
|
+
cursor: string | null;
|
|
50
|
+
events: number;
|
|
51
|
+
}];
|
|
52
|
+
subscribed: [Array<Subscription>];
|
|
53
|
+
}
|
|
54
|
+
type Listeners = ClientEvents & {
|
|
55
|
+
[K in EventType | PrivateEventType]: [StreamEvent<K>];
|
|
56
|
+
};
|
|
57
|
+
export declare class StreamError extends Error {
|
|
58
|
+
readonly code: number;
|
|
59
|
+
constructor(code: number, message: string);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* a connection to E621Stream, see https://e621.stream
|
|
63
|
+
*
|
|
64
|
+
* ```ts
|
|
65
|
+
* const stream = new E621Stream({ auth: { username, apiKey }, subscriptions: ["post.create"] });
|
|
66
|
+
* stream.on("post.create", event => console.log(event.data.post.id));
|
|
67
|
+
* stream.connect();
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare class E621Stream extends Emitter<Listeners> {
|
|
71
|
+
private attempt;
|
|
72
|
+
private closing;
|
|
73
|
+
private heartbeat;
|
|
74
|
+
private lastError;
|
|
75
|
+
private lastMessage;
|
|
76
|
+
private reconnectTimer;
|
|
77
|
+
private socket;
|
|
78
|
+
/** the newest event received, which reconnecting resumes from */
|
|
79
|
+
cursor: string | null;
|
|
80
|
+
readonly options: Options & {
|
|
81
|
+
url: string;
|
|
82
|
+
};
|
|
83
|
+
constructor(options: Options);
|
|
84
|
+
private handle;
|
|
85
|
+
private onClose;
|
|
86
|
+
private send;
|
|
87
|
+
private startHeartbeat;
|
|
88
|
+
private stopHeartbeat;
|
|
89
|
+
/** closes the connection for good */
|
|
90
|
+
close(): void;
|
|
91
|
+
connect(): this;
|
|
92
|
+
/** replaces the current subscriptions, and keeps them for reconnecting */
|
|
93
|
+
subscribe(subscriptions: Array<Subscription>): void;
|
|
94
|
+
}
|
|
95
|
+
export {};
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import Emitter from "./Emitter.js";
|
|
2
|
+
import { CloseCodes } from "./events.js";
|
|
3
|
+
export class StreamError extends Error {
|
|
4
|
+
code;
|
|
5
|
+
constructor(code, message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.name = "StreamError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
// closing for any of these again would just get the same result
|
|
12
|
+
const FATAL = new Set([
|
|
13
|
+
CloseCodes.UNKNOWN_OP,
|
|
14
|
+
CloseCodes.DECODE_ERROR,
|
|
15
|
+
CloseCodes.AUTHENTICATION_FAILED,
|
|
16
|
+
CloseCodes.ALREADY_IDENTIFIED,
|
|
17
|
+
CloseCodes.INVALID_SUBSCRIPTION,
|
|
18
|
+
CloseCodes.INVALID_CURSOR,
|
|
19
|
+
CloseCodes.AUTHENTICATION_EXPIRED,
|
|
20
|
+
]);
|
|
21
|
+
const MAX_DELAY_MS = 60_000;
|
|
22
|
+
const HEARTBEAT_MS = 30_000;
|
|
23
|
+
// the server answers heartbeats and pings, nothing for this long means the connection is gone without having closed
|
|
24
|
+
const SILENT_MS = 75_000;
|
|
25
|
+
/**
|
|
26
|
+
* a connection to E621Stream, see https://e621.stream
|
|
27
|
+
*
|
|
28
|
+
* ```ts
|
|
29
|
+
* const stream = new E621Stream({ auth: { username, apiKey }, subscriptions: ["post.create"] });
|
|
30
|
+
* stream.on("post.create", event => console.log(event.data.post.id));
|
|
31
|
+
* stream.connect();
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export class E621Stream extends Emitter {
|
|
35
|
+
attempt = 0;
|
|
36
|
+
closing = false;
|
|
37
|
+
heartbeat = null;
|
|
38
|
+
lastError = null;
|
|
39
|
+
lastMessage = 0;
|
|
40
|
+
reconnectTimer = null;
|
|
41
|
+
socket = null;
|
|
42
|
+
/** the newest event received, which reconnecting resumes from */
|
|
43
|
+
cursor;
|
|
44
|
+
options;
|
|
45
|
+
constructor(options) {
|
|
46
|
+
super();
|
|
47
|
+
this.options = { reconnect: true, url: "wss://e621.stream/ws", ...options };
|
|
48
|
+
this.cursor = options.cursor === undefined ? null : String(options.cursor);
|
|
49
|
+
}
|
|
50
|
+
handle(raw) {
|
|
51
|
+
if (typeof raw !== "string") {
|
|
52
|
+
this.emit("error", new Error("got a binary message, compression isn't supported by this client"));
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
this.lastMessage = Date.now();
|
|
56
|
+
const message = JSON.parse(raw);
|
|
57
|
+
switch (message.op) {
|
|
58
|
+
case "hello": {
|
|
59
|
+
const { auth, client, subscriptions } = this.options;
|
|
60
|
+
this.send({
|
|
61
|
+
op: "identify",
|
|
62
|
+
d: {
|
|
63
|
+
...(auth ? { auth: { username: auth.username, api_key: auth.apiKey } } : {}),
|
|
64
|
+
...(client ? { client } : {}),
|
|
65
|
+
...(this.cursor === null ? {} : { cursor: this.cursor }),
|
|
66
|
+
subscriptions,
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
case "ready": {
|
|
72
|
+
this.attempt = 0;
|
|
73
|
+
this.emit("ready", message.d);
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
case "dispatch": {
|
|
77
|
+
const event = { id: message.id, type: message.type, time: message.time, data: message.data, ...(message.private ? { private: true } : {}) };
|
|
78
|
+
// private events aren't in the stream, so they can't be resumed from
|
|
79
|
+
if (!event.private)
|
|
80
|
+
this.cursor = event.id;
|
|
81
|
+
this.emit("dispatch", event);
|
|
82
|
+
// typescript can't tie each type in the union to its own listener, it's the same event either way
|
|
83
|
+
this.emitUnchecked(event.type, event);
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
case "replay_complete": {
|
|
87
|
+
this.emit("replayComplete", message.d);
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
case "subscribed": {
|
|
91
|
+
this.emit("subscribed", message.d.subscriptions);
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
case "error": {
|
|
95
|
+
const { code, message: text } = message.d;
|
|
96
|
+
this.lastError = new StreamError(code, text);
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
onClose(code, reason) {
|
|
102
|
+
this.stopHeartbeat();
|
|
103
|
+
this.socket = null;
|
|
104
|
+
const error = this.lastError;
|
|
105
|
+
this.lastError = null;
|
|
106
|
+
const reconnecting = !this.closing && this.options.reconnect !== false && !FATAL.has(code);
|
|
107
|
+
if (error)
|
|
108
|
+
this.emit("error", error);
|
|
109
|
+
this.emit("close", { code, reason: error?.message ?? reason, reconnecting });
|
|
110
|
+
if (!reconnecting)
|
|
111
|
+
return;
|
|
112
|
+
this.attempt++;
|
|
113
|
+
// a server that's rate limiting this connection wants a longer break
|
|
114
|
+
const base = code === CloseCodes.RATE_LIMITED ? 30_000 : 1000;
|
|
115
|
+
const delayMS = Math.min(MAX_DELAY_MS, base * 2 ** (this.attempt - 1)) * (0.75 + Math.random() * 0.5);
|
|
116
|
+
this.emit("reconnecting", { attempt: this.attempt, delayMS: Math.round(delayMS) });
|
|
117
|
+
this.reconnectTimer = setTimeout(() => {
|
|
118
|
+
this.reconnectTimer = null;
|
|
119
|
+
this.connect();
|
|
120
|
+
}, delayMS);
|
|
121
|
+
}
|
|
122
|
+
send(payload) {
|
|
123
|
+
if (this.socket?.readyState === 1)
|
|
124
|
+
this.socket.send(JSON.stringify(payload));
|
|
125
|
+
}
|
|
126
|
+
startHeartbeat() {
|
|
127
|
+
this.lastMessage = Date.now();
|
|
128
|
+
this.heartbeat = setInterval(() => {
|
|
129
|
+
if (Date.now() - this.lastMessage > SILENT_MS) {
|
|
130
|
+
// a client-side close code, nothing the server would send
|
|
131
|
+
this.socket?.close(4999, "no response from the server");
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
this.send({ op: "heartbeat" });
|
|
135
|
+
}, HEARTBEAT_MS);
|
|
136
|
+
}
|
|
137
|
+
stopHeartbeat() {
|
|
138
|
+
if (this.heartbeat)
|
|
139
|
+
clearInterval(this.heartbeat);
|
|
140
|
+
this.heartbeat = null;
|
|
141
|
+
}
|
|
142
|
+
/** closes the connection for good */
|
|
143
|
+
close() {
|
|
144
|
+
this.closing = true;
|
|
145
|
+
if (this.reconnectTimer)
|
|
146
|
+
clearTimeout(this.reconnectTimer);
|
|
147
|
+
this.reconnectTimer = null;
|
|
148
|
+
this.socket?.close(1000, "closed by client");
|
|
149
|
+
}
|
|
150
|
+
connect() {
|
|
151
|
+
if (this.socket)
|
|
152
|
+
return this;
|
|
153
|
+
this.closing = false;
|
|
154
|
+
// the dom types say it's always there, node before 22 doesn't have it
|
|
155
|
+
const global = globalThis.WebSocket;
|
|
156
|
+
const Socket = this.options.WebSocket ?? global;
|
|
157
|
+
if (!Socket)
|
|
158
|
+
throw new Error("there's no global WebSocket here, pass one as the WebSocket option");
|
|
159
|
+
const socket = this.socket = new Socket(this.options.url);
|
|
160
|
+
socket.addEventListener("open", () => { this.startHeartbeat(); });
|
|
161
|
+
socket.addEventListener("message", (event) => {
|
|
162
|
+
try {
|
|
163
|
+
this.handle(event.data);
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
this.emit("error", err instanceof Error ? err : new Error(String(err)));
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
socket.addEventListener("close", (event) => { this.onClose(event.code, event.reason); });
|
|
170
|
+
// the close event that follows has the details
|
|
171
|
+
socket.addEventListener("error", () => null);
|
|
172
|
+
return this;
|
|
173
|
+
}
|
|
174
|
+
/** replaces the current subscriptions, and keeps them for reconnecting */
|
|
175
|
+
subscribe(subscriptions) {
|
|
176
|
+
this.options.subscriptions = subscriptions;
|
|
177
|
+
this.send({ op: "subscribe", d: { subscriptions } });
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=E621Stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E621Stream.js","sourceRoot":"","sources":["../lib/E621Stream.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type Listener<Args extends Array<unknown>> = (...args: Args) => void;
|
|
2
|
+
export default class Emitter<Events extends {
|
|
3
|
+
[K in keyof Events]: Array<unknown>;
|
|
4
|
+
}> {
|
|
5
|
+
private listeners;
|
|
6
|
+
protected emit<K extends keyof Events>(event: K, ...args: Events[K]): void;
|
|
7
|
+
/** for an event name only known at runtime, whose listeners' arguments can't be checked */
|
|
8
|
+
protected emitUnchecked(event: keyof Events, ...args: Array<unknown>): void;
|
|
9
|
+
off<K extends keyof Events>(event: K, listener: NoInfer<Listener<Events[K]>>): this;
|
|
10
|
+
on<K extends keyof Events>(event: K, listener: NoInfer<Listener<Events[K]>>): this;
|
|
11
|
+
once<K extends keyof Events>(event: K, listener: NoInfer<Listener<Events[K]>>): this;
|
|
12
|
+
}
|
package/dist/Emitter.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// a minimal typed event emitter, so the client has no dependencies and works anywhere
|
|
2
|
+
export default class Emitter {
|
|
3
|
+
// listeners of every event share one map, so they're stored without their argument types
|
|
4
|
+
listeners = new Map();
|
|
5
|
+
emit(event, ...args) {
|
|
6
|
+
for (const listener of this.listeners.get(event) ?? [])
|
|
7
|
+
listener(...args);
|
|
8
|
+
}
|
|
9
|
+
/** for an event name only known at runtime, whose listeners' arguments can't be checked */
|
|
10
|
+
emitUnchecked(event, ...args) {
|
|
11
|
+
for (const listener of this.listeners.get(event) ?? [])
|
|
12
|
+
listener(...args);
|
|
13
|
+
}
|
|
14
|
+
off(event, listener) {
|
|
15
|
+
this.listeners.get(event)?.delete(listener);
|
|
16
|
+
return this;
|
|
17
|
+
}
|
|
18
|
+
on(event, listener) {
|
|
19
|
+
let set = this.listeners.get(event);
|
|
20
|
+
if (!set)
|
|
21
|
+
this.listeners.set(event, set = new Set());
|
|
22
|
+
set.add(listener);
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
once(event, listener) {
|
|
26
|
+
const wrapped = (...args) => {
|
|
27
|
+
this.off(event, wrapped);
|
|
28
|
+
listener(...args);
|
|
29
|
+
};
|
|
30
|
+
return this.on(event, wrapped);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=Emitter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Emitter.js","sourceRoot":"","sources":["../lib/Emitter.ts"],"names":[],"mappings":"AAAA,sFAAsF;AAItF,MAAM,CAAC,OAAO,OAAO,OAAO;IACxB,yFAAyF;IACjF,SAAS,GAAG,IAAI,GAAG,EAA8B,CAAC;IAEhD,IAAI,CAAyB,KAAQ,EAAE,GAAG,IAAe;QAC/D,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE;YAAG,QAAgC,CAAC,GAAG,IAAI,CAAC,CAAC;IACvG,CAAC;IAED,2FAA2F;IACjF,aAAa,CAAC,KAAmB,EAAE,GAAG,IAAoB;QAChE,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE;YAAG,QAAqC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC5G,CAAC;IAED,GAAG,CAAyB,KAAQ,EAAE,QAAsC;QACxE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,EAAE,CAAyB,KAAQ,EAAE,QAAsC;QACvE,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG;YAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC;QACrD,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAClB,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,IAAI,CAAyB,KAAQ,EAAE,QAAsC;QACzE,MAAM,OAAO,GAAwB,CAAC,GAAG,IAAI,EAAE,EAAE;YAC7C,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YACzB,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC;QACtB,CAAC,CAAC;QACF,OAAO,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACnC,CAAC;CACJ"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { LegacyPost } from "./generated.ts";
|
|
2
|
+
/** a field's value before and after */
|
|
3
|
+
export interface ValueChange<T> {
|
|
4
|
+
new: T;
|
|
5
|
+
old: T;
|
|
6
|
+
}
|
|
7
|
+
/** what was added to and removed from a list */
|
|
8
|
+
export interface SetChange<T> {
|
|
9
|
+
added: Array<T>;
|
|
10
|
+
removed: Array<T>;
|
|
11
|
+
}
|
|
12
|
+
/** what changed on a record, only the fields that did */
|
|
13
|
+
export type Changes<R, Field extends keyof R> = Partial<{
|
|
14
|
+
[K in Field]: ValueChange<R[K]>;
|
|
15
|
+
}>;
|
|
16
|
+
export type TagCategoryName = "artist" | "character" | "contributor" | "copyright" | "general" | "invalid" | "lore" | "meta" | "species";
|
|
17
|
+
export type PostFlagName = Extract<keyof LegacyPost["flags"], string>;
|
|
18
|
+
/** what changed on a post, only the fields that did. tags are per category, so a category change shows up as a move */
|
|
19
|
+
export type PostChanges = Partial<Record<`tags.${TagCategoryName}`, SetChange<string>> & Record<`flags.${PostFlagName}`, ValueChange<boolean>> & {
|
|
20
|
+
approver_id: ValueChange<number | null>;
|
|
21
|
+
children: SetChange<number>;
|
|
22
|
+
description: ValueChange<string>;
|
|
23
|
+
has_notes: ValueChange<boolean>;
|
|
24
|
+
locked_tags: SetChange<string>;
|
|
25
|
+
md5: ValueChange<string>;
|
|
26
|
+
parent_id: ValueChange<number | null>;
|
|
27
|
+
pools: SetChange<number>;
|
|
28
|
+
rating: ValueChange<LegacyPost["rating"]>;
|
|
29
|
+
sources: SetChange<string>;
|
|
30
|
+
}>;
|
package/dist/changes.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"changes.js","sourceRoot":"","sources":["../lib/changes.ts"],"names":[],"mappings":""}
|
package/dist/events.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { EventDataMap } from "./generated.ts";
|
|
2
|
+
export declare const EVENT_TYPES: readonly ["artist.create", "artist.delete", "artist.update", "artist_url.create", "artist_version.create", "avoid_posting.create", "avoid_posting.delete", "avoid_posting.destroy", "avoid_posting.undelete", "avoid_posting.update", "avoid_posting_version.create", "ban.create", "ban.delete", "ban.update", "blip.create", "bulk_update_request.create", "bulk_update_request.update", "comment.create", "comment.delete", "comment.hide", "comment.unhide", "comment.update", "forum_post.create", "forum_post.delete", "forum_post.hide", "forum_post.unhide", "forum_post.update", "forum_topic.create", "forum_topic.delete", "forum_topic.hide", "forum_topic.unhide", "forum_topic.update", "help_page.create", "help_page.update", "mod_action.create", "news_update.create", "news_update.update", "note.create", "note.update", "note_version.create", "pool.add_posts", "pool.create", "pool.delete", "pool.remove_posts", "pool.update", "pool_version.create", "post.create", "post.update", "post_approval.create", "post_event.create", "post_flag.create", "post_flag.update", "post_replacement.create", "post_set.add_posts", "post_set.create", "post_set.delete", "post_set.remove_posts", "post_set.update", "post_version.create", "post_version.hide", "post_version.unhide", "tag.create", "tag.delete", "tag.update", "tag_alias.create", "tag_alias.update", "tag_implication.create", "tag_implication.update", "tag_type_version.create", "takedown.create", "takedown.delete", "takedown.update", "upload_karma_event.create", "user.create", "user.delete", "user.update", "user_feedback.create", "user_feedback.delete", "user_feedback.destroy", "user_feedback.undelete", "user_feedback.update", "wiki_page.create", "wiki_page.delete", "wiki_page.update", "wiki_page_version.create"];
|
|
3
|
+
export type EventType = typeof EVENT_TYPES[number];
|
|
4
|
+
/** polled with your own credentials and only sent to you, they have to be subscribed to by name */
|
|
5
|
+
export declare const PRIVATE_EVENT_TYPES: readonly ["dmail.create"];
|
|
6
|
+
export type PrivateEventType = typeof PRIVATE_EVENT_TYPES[number];
|
|
7
|
+
/** events whose data is the mod action they come from */
|
|
8
|
+
export declare const MOD_ACTION_EVENT_TYPES: readonly ["artist.delete", "avoid_posting.delete", "avoid_posting.destroy", "avoid_posting.undelete", "ban.delete", "ban.update", "comment.delete", "comment.hide", "comment.unhide", "forum_post.delete", "forum_post.hide", "forum_post.unhide", "forum_topic.delete", "forum_topic.hide", "forum_topic.unhide", "pool.delete", "post_set.delete", "post_version.hide", "post_version.unhide", "tag.delete", "takedown.delete", "user.delete", "user.update", "user_feedback.delete", "user_feedback.destroy", "user_feedback.undelete", "user_feedback.update", "wiki_page.delete"];
|
|
9
|
+
/** updates whose data is the version record they come from */
|
|
10
|
+
export declare const VERSION_EVENT_TYPES: readonly ["artist.update", "avoid_posting.update", "note.update", "pool.update", "tag.update", "wiki_page.update"];
|
|
11
|
+
export type ModActionEventType = typeof MOD_ACTION_EVENT_TYPES[number];
|
|
12
|
+
export type VersionEventType = typeof VERSION_EVENT_TYPES[number];
|
|
13
|
+
/** what an event type's `data` is, see https://e621.stream/events/ */
|
|
14
|
+
export type EventData<T extends EventType | PrivateEventType> = EventDataMap[T];
|
|
15
|
+
/** one event from the stream, narrowed to its type's data by checking `type` */
|
|
16
|
+
export type StreamEvent<T extends EventType | PrivateEventType = EventType | PrivateEventType> = T extends EventType | PrivateEventType ? {
|
|
17
|
+
data: EventData<T>;
|
|
18
|
+
/** the event's cursor, pass it as `cursor` to resume after it. private events have no cursor */
|
|
19
|
+
id: string;
|
|
20
|
+
/** only for private events, which are polled with your own credentials and never stored */
|
|
21
|
+
private?: true;
|
|
22
|
+
/** when it happened on e621 */
|
|
23
|
+
time: string;
|
|
24
|
+
type: T;
|
|
25
|
+
} : never;
|
|
26
|
+
export interface Filter {
|
|
27
|
+
actions?: Array<string>;
|
|
28
|
+
pool_ids?: Array<number>;
|
|
29
|
+
post_ids?: Array<number>;
|
|
30
|
+
set_ids?: Array<number>;
|
|
31
|
+
/** e621 style tag query, supports `tag`, `-tag`, `~tag` and `rating:<s|q|e>` */
|
|
32
|
+
tags?: string;
|
|
33
|
+
topic_ids?: Array<number>;
|
|
34
|
+
user_ids?: Array<number>;
|
|
35
|
+
}
|
|
36
|
+
/** an event type, `<resource>.*`, `*`, or one of those with a filter */
|
|
37
|
+
export type Subscription = string | {
|
|
38
|
+
filter?: Filter;
|
|
39
|
+
type: string;
|
|
40
|
+
};
|
|
41
|
+
export declare const CloseCodes: {
|
|
42
|
+
readonly UNKNOWN_ERROR: 4000;
|
|
43
|
+
readonly UNKNOWN_OP: 4001;
|
|
44
|
+
readonly DECODE_ERROR: 4002;
|
|
45
|
+
readonly NOT_IDENTIFIED: 4003;
|
|
46
|
+
readonly AUTHENTICATION_FAILED: 4004;
|
|
47
|
+
readonly ALREADY_IDENTIFIED: 4005;
|
|
48
|
+
readonly INVALID_SUBSCRIPTION: 4006;
|
|
49
|
+
readonly INVALID_CURSOR: 4007;
|
|
50
|
+
readonly RATE_LIMITED: 4008;
|
|
51
|
+
readonly SLOW_CONSUMER: 4009;
|
|
52
|
+
readonly TOO_MANY_CONNECTIONS: 4010;
|
|
53
|
+
readonly AUTHENTICATION_EXPIRED: 4011;
|
|
54
|
+
};
|
package/dist/events.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// kept identical to the server's src/events.ts, the repository's tests check it
|
|
2
|
+
export const EVENT_TYPES = [
|
|
3
|
+
"artist.create",
|
|
4
|
+
"artist.delete",
|
|
5
|
+
"artist.update",
|
|
6
|
+
"artist_url.create",
|
|
7
|
+
"artist_version.create",
|
|
8
|
+
"avoid_posting.create",
|
|
9
|
+
"avoid_posting.delete",
|
|
10
|
+
"avoid_posting.destroy",
|
|
11
|
+
"avoid_posting.undelete",
|
|
12
|
+
"avoid_posting.update",
|
|
13
|
+
"avoid_posting_version.create",
|
|
14
|
+
"ban.create",
|
|
15
|
+
"ban.delete",
|
|
16
|
+
"ban.update",
|
|
17
|
+
"blip.create",
|
|
18
|
+
"bulk_update_request.create",
|
|
19
|
+
"bulk_update_request.update",
|
|
20
|
+
"comment.create",
|
|
21
|
+
"comment.delete",
|
|
22
|
+
"comment.hide",
|
|
23
|
+
"comment.unhide",
|
|
24
|
+
"comment.update",
|
|
25
|
+
"forum_post.create",
|
|
26
|
+
"forum_post.delete",
|
|
27
|
+
"forum_post.hide",
|
|
28
|
+
"forum_post.unhide",
|
|
29
|
+
"forum_post.update",
|
|
30
|
+
"forum_topic.create",
|
|
31
|
+
"forum_topic.delete",
|
|
32
|
+
"forum_topic.hide",
|
|
33
|
+
"forum_topic.unhide",
|
|
34
|
+
"forum_topic.update",
|
|
35
|
+
"help_page.create",
|
|
36
|
+
"help_page.update",
|
|
37
|
+
"mod_action.create",
|
|
38
|
+
"news_update.create",
|
|
39
|
+
"news_update.update",
|
|
40
|
+
"note.create",
|
|
41
|
+
"note.update",
|
|
42
|
+
"note_version.create",
|
|
43
|
+
"pool.add_posts",
|
|
44
|
+
"pool.create",
|
|
45
|
+
"pool.delete",
|
|
46
|
+
"pool.remove_posts",
|
|
47
|
+
"pool.update",
|
|
48
|
+
"pool_version.create",
|
|
49
|
+
"post.create",
|
|
50
|
+
"post.update",
|
|
51
|
+
"post_approval.create",
|
|
52
|
+
"post_event.create",
|
|
53
|
+
"post_flag.create",
|
|
54
|
+
"post_flag.update",
|
|
55
|
+
"post_replacement.create",
|
|
56
|
+
"post_set.add_posts",
|
|
57
|
+
"post_set.create",
|
|
58
|
+
"post_set.delete",
|
|
59
|
+
"post_set.remove_posts",
|
|
60
|
+
"post_set.update",
|
|
61
|
+
"post_version.create",
|
|
62
|
+
"post_version.hide",
|
|
63
|
+
"post_version.unhide",
|
|
64
|
+
"tag.create",
|
|
65
|
+
"tag.delete",
|
|
66
|
+
"tag.update",
|
|
67
|
+
"tag_alias.create",
|
|
68
|
+
"tag_alias.update",
|
|
69
|
+
"tag_implication.create",
|
|
70
|
+
"tag_implication.update",
|
|
71
|
+
"tag_type_version.create",
|
|
72
|
+
"takedown.create",
|
|
73
|
+
"takedown.delete",
|
|
74
|
+
"takedown.update",
|
|
75
|
+
"upload_karma_event.create",
|
|
76
|
+
"user.create",
|
|
77
|
+
"user.delete",
|
|
78
|
+
"user.update",
|
|
79
|
+
"user_feedback.create",
|
|
80
|
+
"user_feedback.delete",
|
|
81
|
+
"user_feedback.destroy",
|
|
82
|
+
"user_feedback.undelete",
|
|
83
|
+
"user_feedback.update",
|
|
84
|
+
"wiki_page.create",
|
|
85
|
+
"wiki_page.delete",
|
|
86
|
+
"wiki_page.update",
|
|
87
|
+
"wiki_page_version.create",
|
|
88
|
+
];
|
|
89
|
+
/** polled with your own credentials and only sent to you, they have to be subscribed to by name */
|
|
90
|
+
export const PRIVATE_EVENT_TYPES = ["dmail.create"];
|
|
91
|
+
/** events whose data is the mod action they come from */
|
|
92
|
+
export const MOD_ACTION_EVENT_TYPES = [
|
|
93
|
+
"artist.delete",
|
|
94
|
+
"avoid_posting.delete",
|
|
95
|
+
"avoid_posting.destroy",
|
|
96
|
+
"avoid_posting.undelete",
|
|
97
|
+
"ban.delete",
|
|
98
|
+
"ban.update",
|
|
99
|
+
"comment.delete",
|
|
100
|
+
"comment.hide",
|
|
101
|
+
"comment.unhide",
|
|
102
|
+
"forum_post.delete",
|
|
103
|
+
"forum_post.hide",
|
|
104
|
+
"forum_post.unhide",
|
|
105
|
+
"forum_topic.delete",
|
|
106
|
+
"forum_topic.hide",
|
|
107
|
+
"forum_topic.unhide",
|
|
108
|
+
"pool.delete",
|
|
109
|
+
"post_set.delete",
|
|
110
|
+
"post_version.hide",
|
|
111
|
+
"post_version.unhide",
|
|
112
|
+
"tag.delete",
|
|
113
|
+
"takedown.delete",
|
|
114
|
+
"user.delete",
|
|
115
|
+
"user.update",
|
|
116
|
+
"user_feedback.delete",
|
|
117
|
+
"user_feedback.destroy",
|
|
118
|
+
"user_feedback.undelete",
|
|
119
|
+
"user_feedback.update",
|
|
120
|
+
"wiki_page.delete",
|
|
121
|
+
];
|
|
122
|
+
/** updates whose data is the version record they come from */
|
|
123
|
+
export const VERSION_EVENT_TYPES = ["artist.update", "avoid_posting.update", "note.update", "pool.update", "tag.update", "wiki_page.update"];
|
|
124
|
+
export const CloseCodes = {
|
|
125
|
+
UNKNOWN_ERROR: 4000,
|
|
126
|
+
UNKNOWN_OP: 4001,
|
|
127
|
+
DECODE_ERROR: 4002,
|
|
128
|
+
NOT_IDENTIFIED: 4003,
|
|
129
|
+
AUTHENTICATION_FAILED: 4004,
|
|
130
|
+
ALREADY_IDENTIFIED: 4005,
|
|
131
|
+
INVALID_SUBSCRIPTION: 4006,
|
|
132
|
+
INVALID_CURSOR: 4007,
|
|
133
|
+
RATE_LIMITED: 4008,
|
|
134
|
+
SLOW_CONSUMER: 4009,
|
|
135
|
+
TOO_MANY_CONNECTIONS: 4010,
|
|
136
|
+
AUTHENTICATION_EXPIRED: 4011,
|
|
137
|
+
};
|
|
138
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../lib/events.ts"],"names":[],"mappings":"AAEA,gFAAgF;AAEhF,MAAM,CAAC,MAAM,WAAW,GAAG;IACvB,eAAe;IACf,eAAe;IACf,eAAe;IACf,mBAAmB;IACnB,uBAAuB;IACvB,sBAAsB;IACtB,sBAAsB;IACtB,uBAAuB;IACvB,wBAAwB;IACxB,sBAAsB;IACtB,8BAA8B;IAC9B,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,aAAa;IACb,4BAA4B;IAC5B,4BAA4B;IAC5B,gBAAgB;IAChB,gBAAgB;IAChB,cAAc;IACd,gBAAgB;IAChB,gBAAgB;IAChB,mBAAmB;IACnB,mBAAmB;IACnB,iBAAiB;IACjB,mBAAmB;IACnB,mBAAmB;IACnB,oBAAoB;IACpB,oBAAoB;IACpB,kBAAkB;IAClB,oBAAoB;IACpB,oBAAoB;IACpB,kBAAkB;IAClB,kBAAkB;IAClB,mBAAmB;IACnB,oBAAoB;IACpB,oBAAoB;IACpB,aAAa;IACb,aAAa;IACb,qBAAqB;IACrB,gBAAgB;IAChB,aAAa;IACb,aAAa;IACb,mBAAmB;IACnB,aAAa;IACb,qBAAqB;IACrB,aAAa;IACb,aAAa;IACb,sBAAsB;IACtB,mBAAmB;IACnB,kBAAkB;IAClB,kBAAkB;IAClB,yBAAyB;IACzB,oBAAoB;IACpB,iBAAiB;IACjB,iBAAiB;IACjB,uBAAuB;IACvB,iBAAiB;IACjB,qBAAqB;IACrB,mBAAmB;IACnB,qBAAqB;IACrB,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,kBAAkB;IAClB,kBAAkB;IAClB,wBAAwB;IACxB,wBAAwB;IACxB,yBAAyB;IACzB,iBAAiB;IACjB,iBAAiB;IACjB,iBAAiB;IACjB,2BAA2B;IAC3B,aAAa;IACb,aAAa;IACb,aAAa;IACb,sBAAsB;IACtB,sBAAsB;IACtB,uBAAuB;IACvB,wBAAwB;IACxB,sBAAsB;IACtB,kBAAkB;IAClB,kBAAkB;IAClB,kBAAkB;IAClB,0BAA0B;CACpB,CAAC;AAIX,mGAAmG;AAEnG,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,cAAc,CAAU,CAAC;AAI7D,yDAAyD;AAEzD,MAAM,CAAC,MAAM,sBAAsB,GAAG;IAClC,eAAe;IACf,sBAAsB;IACtB,uBAAuB;IACvB,wBAAwB;IACxB,YAAY;IACZ,YAAY;IACZ,gBAAgB;IAChB,cAAc;IACd,gBAAgB;IAChB,mBAAmB;IACnB,iBAAiB;IACjB,mBAAmB;IACnB,oBAAoB;IACpB,kBAAkB;IAClB,oBAAoB;IACpB,aAAa;IACb,iBAAiB;IACjB,mBAAmB;IACnB,qBAAqB;IACrB,YAAY;IACZ,iBAAiB;IACjB,aAAa;IACb,aAAa;IACb,sBAAsB;IACtB,uBAAuB;IACvB,wBAAwB;IACxB,sBAAsB;IACtB,kBAAkB;CACZ,CAAC;AAEX,8DAA8D;AAE9D,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,eAAe,EAAE,sBAAsB,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,kBAAkB,CAAU,CAAC;AAkCtJ,MAAM,CAAC,MAAM,UAAU,GAAG;IACtB,aAAa,EAAE,IAAI;IACnB,UAAU,EAAE,IAAI;IAChB,YAAY,EAAE,IAAI;IAClB,cAAc,EAAE,IAAI;IACpB,qBAAqB,EAAE,IAAI;IAC3B,kBAAkB,EAAE,IAAI;IACxB,oBAAoB,EAAE,IAAI;IAC1B,cAAc,EAAE,IAAI;IACpB,YAAY,EAAE,IAAI;IAClB,aAAa,EAAE,IAAI;IACnB,oBAAoB,EAAE,IAAI;IAC1B,sBAAsB,EAAE,IAAI;CACtB,CAAC"}
|