e621stream 0.0.0 → 0.0.2
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 +19 -12
- package/dist/E621Stream.d.ts +12 -14
- package/dist/E621Stream.js +19 -21
- package/dist/E621Stream.js.map +1 -1
- package/dist/Emitter.d.ts +0 -1
- package/dist/Emitter.js +0 -3
- package/dist/Emitter.js.map +1 -1
- package/dist/changes.d.ts +36 -4
- package/dist/events.d.ts +9 -12
- package/dist/events.js +21 -6
- package/dist/events.js.map +1 -1
- package/dist/generated.d.ts +23 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# e621stream
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A client for [E621Stream](https://e621.stream). Works in node 22+, bun, deno & browsers, has no dependencies, and every event is typed down to the record it has.
|
|
4
4
|
|
|
5
|
-
```
|
|
6
|
-
npm
|
|
5
|
+
```sh
|
|
6
|
+
npm i e621stream
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
```ts
|
|
@@ -18,7 +18,7 @@ stream.on("post.create", (event) => {
|
|
|
18
18
|
console.log(event.data.post.id, event.data.post.tags.general);
|
|
19
19
|
});
|
|
20
20
|
stream.on("post.update", (event) => {
|
|
21
|
-
// only
|
|
21
|
+
// only what changed, tags are per category
|
|
22
22
|
console.log(event.data.changes?.["tags.general"]?.added);
|
|
23
23
|
});
|
|
24
24
|
stream.on("comment.update", (event) => {
|
|
@@ -28,12 +28,19 @@ stream.on("error", err => console.error(err));
|
|
|
28
28
|
stream.connect();
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
|
|
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.
|
|
31
|
+
Listen for an event type with `on("post.create", ...)`, or everything with `on("dispatch", ...)` (check `event.type` to narrow it). The others are `ready`, `replayComplete`, `subscribed`, `reconnecting`, `close` and `error`. See [Events](https://e621.stream/events/) for what each event is.
|
|
38
32
|
|
|
39
|
-
|
|
33
|
+
#### Options
|
|
34
|
+
| Option | Type | Default | Description |
|
|
35
|
+
|:---:|:---:|:---:|:---:|
|
|
36
|
+
| `subscriptions` | Array | | what to subscribe to, `stream.subscribe([...])` changes it later |
|
|
37
|
+
| `auth` | Object | None | `{ username, apiKey }` |
|
|
38
|
+
| `cursor` | String \| Number | None | an event id or ms timestamp to replay from, `stream.cursor` is the last event you got |
|
|
39
|
+
| `reconnect` | Boolean | `true` | reconnect when the connection drops (not after things like bad credentials) |
|
|
40
|
+
| `client` | String | None | shown in the server's logs |
|
|
41
|
+
| `url` | String | `wss://e621.stream/ws` | |
|
|
42
|
+
| `WebSocket` | WebSocket | global | for older node, the `ws` package works |
|
|
43
|
+
|
|
44
|
+
Private events like `dmail.create` have to be subscribed to by name.
|
|
45
|
+
|
|
46
|
+
Records like `LegacyPost`, `Comment` and `ForumTopic` come from the [e621 module](https://www.npmjs.com/package/e621)'s types, and are exported here too. Mod action events are typed per action, so checking `event.data.action` narrows `event.data.values`.
|
package/dist/E621Stream.d.ts
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import Emitter from "./Emitter.ts";
|
|
2
2
|
import { type EventType, type PrivateEventType, type StreamEvent, type Subscription } from "./events.ts";
|
|
3
3
|
export interface Options {
|
|
4
|
-
/**
|
|
4
|
+
/** Your e621 username & api key. */
|
|
5
5
|
auth?: {
|
|
6
6
|
apiKey: string;
|
|
7
7
|
username: string;
|
|
8
8
|
};
|
|
9
|
-
/**
|
|
9
|
+
/** Shown in the server's logs. */
|
|
10
10
|
client?: string;
|
|
11
|
-
/**
|
|
11
|
+
/** An event id or millisecond timestamp to replay from. */
|
|
12
12
|
cursor?: number | string;
|
|
13
|
-
/**
|
|
13
|
+
/** Reconnect when the connection drops. */
|
|
14
14
|
reconnect?: boolean;
|
|
15
15
|
subscriptions: Array<Subscription>;
|
|
16
16
|
url?: string;
|
|
17
|
-
/**
|
|
17
|
+
/** For runtimes without a global WebSocket (node < 22), the `ws` package works. */
|
|
18
18
|
WebSocket?: typeof WebSocket;
|
|
19
19
|
}
|
|
20
20
|
export interface Ready {
|
|
21
|
-
/**
|
|
21
|
+
/** If the cursor was older than anything still kept. */
|
|
22
22
|
cursor_expired?: boolean;
|
|
23
23
|
replaying: boolean;
|
|
24
24
|
session_id: string;
|
|
@@ -36,7 +36,7 @@ export interface ClientEvents {
|
|
|
36
36
|
reason: string;
|
|
37
37
|
reconnecting: boolean;
|
|
38
38
|
}];
|
|
39
|
-
/**
|
|
39
|
+
/** Every event, public or private. */
|
|
40
40
|
dispatch: [StreamEvent];
|
|
41
41
|
error: [Error];
|
|
42
42
|
ready: [Ready];
|
|
@@ -44,7 +44,6 @@ export interface ClientEvents {
|
|
|
44
44
|
attempt: number;
|
|
45
45
|
delayMS: number;
|
|
46
46
|
}];
|
|
47
|
-
/** replay is done, live events follow */
|
|
48
47
|
replayComplete: [{
|
|
49
48
|
cursor: string | null;
|
|
50
49
|
events: number;
|
|
@@ -59,8 +58,8 @@ export declare class StreamError extends Error {
|
|
|
59
58
|
constructor(code: number, message: string);
|
|
60
59
|
}
|
|
61
60
|
/**
|
|
62
|
-
*
|
|
63
|
-
*
|
|
61
|
+
* A connection to E621Stream, see https://e621.stream
|
|
62
|
+
* @example
|
|
64
63
|
* ```ts
|
|
65
64
|
* const stream = new E621Stream({ auth: { username, apiKey }, subscriptions: ["post.create"] });
|
|
66
65
|
* stream.on("post.create", event => console.log(event.data.post.id));
|
|
@@ -72,10 +71,9 @@ export declare class E621Stream extends Emitter<Listeners> {
|
|
|
72
71
|
private closing;
|
|
73
72
|
private heartbeat;
|
|
74
73
|
private lastError;
|
|
75
|
-
private
|
|
74
|
+
private lastHeartbeatAck;
|
|
76
75
|
private reconnectTimer;
|
|
77
76
|
private socket;
|
|
78
|
-
/** the newest event received, which reconnecting resumes from */
|
|
79
77
|
cursor: string | null;
|
|
80
78
|
readonly options: Options & {
|
|
81
79
|
url: string;
|
|
@@ -86,10 +84,10 @@ export declare class E621Stream extends Emitter<Listeners> {
|
|
|
86
84
|
private send;
|
|
87
85
|
private startHeartbeat;
|
|
88
86
|
private stopHeartbeat;
|
|
89
|
-
/**
|
|
87
|
+
/** Close the connection. */
|
|
90
88
|
close(): void;
|
|
91
89
|
connect(): this;
|
|
92
|
-
/**
|
|
90
|
+
/** Replace the current subscriptions. */
|
|
93
91
|
subscribe(subscriptions: Array<Subscription>): void;
|
|
94
92
|
}
|
|
95
93
|
export {};
|
package/dist/E621Stream.js
CHANGED
|
@@ -8,7 +8,6 @@ export class StreamError extends Error {
|
|
|
8
8
|
this.name = "StreamError";
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
|
-
// closing for any of these again would just get the same result
|
|
12
11
|
const FATAL = new Set([
|
|
13
12
|
CloseCodes.UNKNOWN_OP,
|
|
14
13
|
CloseCodes.DECODE_ERROR,
|
|
@@ -17,14 +16,14 @@ const FATAL = new Set([
|
|
|
17
16
|
CloseCodes.INVALID_SUBSCRIPTION,
|
|
18
17
|
CloseCodes.INVALID_CURSOR,
|
|
19
18
|
CloseCodes.AUTHENTICATION_EXPIRED,
|
|
19
|
+
CloseCodes.DISCONNECTED,
|
|
20
|
+
CloseCodes.BANNED,
|
|
20
21
|
]);
|
|
21
22
|
const MAX_DELAY_MS = 60_000;
|
|
22
23
|
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
24
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
* A connection to E621Stream, see https://e621.stream
|
|
26
|
+
* @example
|
|
28
27
|
* ```ts
|
|
29
28
|
* const stream = new E621Stream({ auth: { username, apiKey }, subscriptions: ["post.create"] });
|
|
30
29
|
* stream.on("post.create", event => console.log(event.data.post.id));
|
|
@@ -36,10 +35,9 @@ export class E621Stream extends Emitter {
|
|
|
36
35
|
closing = false;
|
|
37
36
|
heartbeat = null;
|
|
38
37
|
lastError = null;
|
|
39
|
-
|
|
38
|
+
lastHeartbeatAck = true;
|
|
40
39
|
reconnectTimer = null;
|
|
41
40
|
socket = null;
|
|
42
|
-
/** the newest event received, which reconnecting resumes from */
|
|
43
41
|
cursor;
|
|
44
42
|
options;
|
|
45
43
|
constructor(options) {
|
|
@@ -49,10 +47,9 @@ export class E621Stream extends Emitter {
|
|
|
49
47
|
}
|
|
50
48
|
handle(raw) {
|
|
51
49
|
if (typeof raw !== "string") {
|
|
52
|
-
this.emit("error", new Error("
|
|
50
|
+
this.emit("error", new Error("compression isn't supported"));
|
|
53
51
|
return;
|
|
54
52
|
}
|
|
55
|
-
this.lastMessage = Date.now();
|
|
56
53
|
const message = JSON.parse(raw);
|
|
57
54
|
switch (message.op) {
|
|
58
55
|
case "hello": {
|
|
@@ -75,11 +72,10 @@ export class E621Stream extends Emitter {
|
|
|
75
72
|
}
|
|
76
73
|
case "dispatch": {
|
|
77
74
|
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
75
|
if (!event.private)
|
|
80
76
|
this.cursor = event.id;
|
|
81
77
|
this.emit("dispatch", event);
|
|
82
|
-
// typescript can't
|
|
78
|
+
// typescript can't narrow this
|
|
83
79
|
this.emitUnchecked(event.type, event);
|
|
84
80
|
break;
|
|
85
81
|
}
|
|
@@ -91,6 +87,10 @@ export class E621Stream extends Emitter {
|
|
|
91
87
|
this.emit("subscribed", message.d.subscriptions);
|
|
92
88
|
break;
|
|
93
89
|
}
|
|
90
|
+
case "heartbeat_ack": {
|
|
91
|
+
this.lastHeartbeatAck = true;
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
94
|
case "error": {
|
|
95
95
|
const { code, message: text } = message.d;
|
|
96
96
|
this.lastError = new StreamError(code, text);
|
|
@@ -110,7 +110,6 @@ export class E621Stream extends Emitter {
|
|
|
110
110
|
if (!reconnecting)
|
|
111
111
|
return;
|
|
112
112
|
this.attempt++;
|
|
113
|
-
// a server that's rate limiting this connection wants a longer break
|
|
114
113
|
const base = code === CloseCodes.RATE_LIMITED ? 30_000 : 1000;
|
|
115
114
|
const delayMS = Math.min(MAX_DELAY_MS, base * 2 ** (this.attempt - 1)) * (0.75 + Math.random() * 0.5);
|
|
116
115
|
this.emit("reconnecting", { attempt: this.attempt, delayMS: Math.round(delayMS) });
|
|
@@ -124,13 +123,13 @@ export class E621Stream extends Emitter {
|
|
|
124
123
|
this.socket.send(JSON.stringify(payload));
|
|
125
124
|
}
|
|
126
125
|
startHeartbeat() {
|
|
127
|
-
this.
|
|
126
|
+
this.lastHeartbeatAck = true;
|
|
128
127
|
this.heartbeat = setInterval(() => {
|
|
129
|
-
if (
|
|
130
|
-
|
|
131
|
-
this.socket?.close(4999, "no response from the server");
|
|
128
|
+
if (!this.lastHeartbeatAck) {
|
|
129
|
+
this.socket?.close(4999, "heartbeat not acknowledged");
|
|
132
130
|
return;
|
|
133
131
|
}
|
|
132
|
+
this.lastHeartbeatAck = false;
|
|
134
133
|
this.send({ op: "heartbeat" });
|
|
135
134
|
}, HEARTBEAT_MS);
|
|
136
135
|
}
|
|
@@ -139,7 +138,7 @@ export class E621Stream extends Emitter {
|
|
|
139
138
|
clearInterval(this.heartbeat);
|
|
140
139
|
this.heartbeat = null;
|
|
141
140
|
}
|
|
142
|
-
/**
|
|
141
|
+
/** Close the connection. */
|
|
143
142
|
close() {
|
|
144
143
|
this.closing = true;
|
|
145
144
|
if (this.reconnectTimer)
|
|
@@ -151,11 +150,11 @@ export class E621Stream extends Emitter {
|
|
|
151
150
|
if (this.socket)
|
|
152
151
|
return this;
|
|
153
152
|
this.closing = false;
|
|
154
|
-
//
|
|
153
|
+
// not present before node 22
|
|
155
154
|
const global = globalThis.WebSocket;
|
|
156
155
|
const Socket = this.options.WebSocket ?? global;
|
|
157
156
|
if (!Socket)
|
|
158
|
-
throw new Error("
|
|
157
|
+
throw new Error("no WebSocket available, pass one with the WebSocket option");
|
|
159
158
|
const socket = this.socket = new Socket(this.options.url);
|
|
160
159
|
socket.addEventListener("open", () => { this.startHeartbeat(); });
|
|
161
160
|
socket.addEventListener("message", (event) => {
|
|
@@ -167,11 +166,10 @@ export class E621Stream extends Emitter {
|
|
|
167
166
|
}
|
|
168
167
|
});
|
|
169
168
|
socket.addEventListener("close", (event) => { this.onClose(event.code, event.reason); });
|
|
170
|
-
// the close event that follows has the details
|
|
171
169
|
socket.addEventListener("error", () => null);
|
|
172
170
|
return this;
|
|
173
171
|
}
|
|
174
|
-
/**
|
|
172
|
+
/** Replace the current subscriptions. */
|
|
175
173
|
subscribe(subscriptions) {
|
|
176
174
|
this.options.subscriptions = subscriptions;
|
|
177
175
|
this.send({ op: "subscribe", d: { subscriptions } });
|
package/dist/E621Stream.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"E621Stream.js","sourceRoot":"","sources":["../lib/E621Stream.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,UAAU,EAA8E,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"E621Stream.js","sourceRoot":"","sources":["../lib/E621Stream.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,UAAU,EAA8E,MAAM,aAAa,CAAC;AAuCrH,MAAM,OAAO,WAAY,SAAQ,KAAK;IACb;IAArB,YAAqB,IAAY,EAAE,OAAe;QAC9C,KAAK,CAAC,OAAO,CAAC,CAAC;QADE,SAAI,GAAJ,IAAI,CAAQ;QAE7B,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC9B,CAAC;CACJ;AAED,MAAM,KAAK,GAAG,IAAI,GAAG,CAAS;IAC1B,UAAU,CAAC,UAAU;IACrB,UAAU,CAAC,YAAY;IACvB,UAAU,CAAC,qBAAqB;IAChC,UAAU,CAAC,kBAAkB;IAC7B,UAAU,CAAC,oBAAoB;IAC/B,UAAU,CAAC,cAAc;IACzB,UAAU,CAAC,sBAAsB;IACjC,UAAU,CAAC,YAAY;IACvB,UAAU,CAAC,MAAM;CACpB,CAAC,CAAC;AACH,MAAM,YAAY,GAAG,MAAM,CAAC;AAC5B,MAAM,YAAY,GAAG,MAAM,CAAC;AAE5B;;;;;;;;GAQG;AACH,MAAM,OAAO,UAAW,SAAQ,OAAkB;IACtC,OAAO,GAAG,CAAC,CAAC;IACZ,OAAO,GAAG,KAAK,CAAC;IAChB,SAAS,GAA0C,IAAI,CAAC;IACxD,SAAS,GAAuB,IAAI,CAAC;IACrC,gBAAgB,GAAG,IAAI,CAAC;IACxB,cAAc,GAAyC,IAAI,CAAC;IAC5D,MAAM,GAAqB,IAAI,CAAC;IACxC,MAAM,CAAgB;IACb,OAAO,CAA4B;IAE5C,YAAY,OAAgB;QACxB,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,OAAO,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,sBAAsB,EAAE,GAAG,OAAO,EAAE,CAAC;QAC5E,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/E,CAAC;IAEO,MAAM,CAAC,GAAY;QACvB,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;YAC1B,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC,CAAC;YAC7D,OAAO;QACX,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA2G,CAAC;QAC1I,QAAQ,OAAO,CAAC,EAAE,EAAE,CAAC;YACjB,KAAK,OAAO,CAAC,CAAC,CAAC;gBACX,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;gBACrD,IAAI,CAAC,IAAI,CAAC;oBACN,EAAE,EAAE,UAAU;oBACd,CAAC,EAAE;wBACC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;wBAC5E,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;wBAC7B,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;wBACxD,aAAa;qBAChB;iBACJ,CAAC,CAAC;gBACH,MAAM;YACV,CAAC;YACD,KAAK,OAAO,CAAC,CAAC,CAAC;gBACX,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;gBACjB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAU,CAAC,CAAC;gBACvC,MAAM;YACV,CAAC;YACD,KAAK,UAAU,CAAC,CAAC,CAAC;gBACd,MAAM,KAAK,GAAG,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAiB,CAAC;gBAC3J,IAAI,CAAC,KAAK,CAAC,OAAO;oBAAE,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,EAAE,CAAC;gBAC3C,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;gBAC7B,+BAA+B;gBAC/B,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;gBACtC,MAAM;YACV,CAAC;YACD,KAAK,iBAAiB,CAAC,CAAC,CAAC;gBACrB,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAA8C,CAAC,CAAC;gBACpF,MAAM;YACV,CAAC;YACD,KAAK,YAAY,CAAC,CAAC,CAAC;gBAChB,IAAI,CAAC,IAAI,CAAC,YAAY,EAAG,OAAO,CAAC,CAA4C,CAAC,aAAa,CAAC,CAAC;gBAC7F,MAAM;YACV,CAAC;YACD,KAAK,eAAe,CAAC,CAAC,CAAC;gBACnB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;gBAC7B,MAAM;YACV,CAAC;YACD,KAAK,OAAO,CAAC,CAAC,CAAC;gBACX,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,CAAsC,CAAC;gBAC/E,IAAI,CAAC,SAAS,GAAG,IAAI,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBAC7C,MAAM;YACV,CAAC;QACL,CAAC;IACL,CAAC;IAEO,OAAO,CAAC,IAAY,EAAE,MAAc;QACxC,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC;QAC7B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,MAAM,YAAY,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,KAAK,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC3F,IAAI,KAAK;YAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,IAAI,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;QAC7E,IAAI,CAAC,YAAY;YAAE,OAAO;QAC1B,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,MAAM,IAAI,GAAG,IAAI,KAAK,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;QAC9D,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC;QACtG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACnF,IAAI,CAAC,cAAc,GAAG,UAAU,CAAC,GAAG,EAAE;YAClC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;YAC3B,IAAI,CAAC,OAAO,EAAE,CAAC;QACnB,CAAC,EAAE,OAAO,CAAC,CAAC;IAChB,CAAC;IAEO,IAAI,CAAC,OAAe;QACxB,IAAI,IAAI,CAAC,MAAM,EAAE,UAAU,KAAK,CAAC;YAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IACjF,CAAC;IAEO,cAAc;QAClB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC7B,IAAI,CAAC,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE;YAC9B,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACzB,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,EAAE,4BAA4B,CAAC,CAAC;gBACvD,OAAO;YACX,CAAC;YACD,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC;QACnC,CAAC,EAAE,YAAY,CAAC,CAAC;IACrB,CAAC;IAEO,aAAa;QACjB,IAAI,IAAI,CAAC,SAAS;YAAE,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IAC1B,CAAC;IAED,4BAA4B;IAC5B,KAAK;QACD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,IAAI,CAAC,cAAc;YAAE,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC3D,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC3B,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;IACjD,CAAC;IAED,OAAO;QACH,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QAC7B,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,6BAA6B;QAC7B,MAAM,MAAM,GAAI,UAA4D,CAAC,SAAS,CAAC;QACvF,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC;QAChD,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;QAC3F,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC1D,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAClE,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,KAAmB,EAAE,EAAE;YACvD,IAAI,CAAC;gBACD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC5B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACX,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC5E,CAAC;QACL,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,KAAiB,EAAE,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACrG,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QAC7C,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,yCAAyC;IACzC,SAAS,CAAC,aAAkC;QACxC,IAAI,CAAC,OAAO,CAAC,aAAa,GAAG,aAAa,CAAC;QAC3C,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC;IACzD,CAAC;CACJ"}
|
package/dist/Emitter.d.ts
CHANGED
|
@@ -4,7 +4,6 @@ export default class Emitter<Events extends {
|
|
|
4
4
|
}> {
|
|
5
5
|
private listeners;
|
|
6
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
7
|
protected emitUnchecked(event: keyof Events, ...args: Array<unknown>): void;
|
|
9
8
|
off<K extends keyof Events>(event: K, listener: NoInfer<Listener<Events[K]>>): this;
|
|
10
9
|
on<K extends keyof Events>(event: K, listener: NoInfer<Listener<Events[K]>>): this;
|
package/dist/Emitter.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
// a minimal typed event emitter, so the client has no dependencies and works anywhere
|
|
2
1
|
export default class Emitter {
|
|
3
|
-
// listeners of every event share one map, so they're stored without their argument types
|
|
4
2
|
listeners = new Map();
|
|
5
3
|
emit(event, ...args) {
|
|
6
4
|
for (const listener of this.listeners.get(event) ?? [])
|
|
7
5
|
listener(...args);
|
|
8
6
|
}
|
|
9
|
-
/** for an event name only known at runtime, whose listeners' arguments can't be checked */
|
|
10
7
|
emitUnchecked(event, ...args) {
|
|
11
8
|
for (const listener of this.listeners.get(event) ?? [])
|
|
12
9
|
listener(...args);
|
package/dist/Emitter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Emitter.js","sourceRoot":"","sources":["../lib/Emitter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Emitter.js","sourceRoot":"","sources":["../lib/Emitter.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,OAAO,OAAO;IAChB,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;IAES,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"}
|
package/dist/changes.d.ts
CHANGED
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
import type { LegacyPost } from "./generated.ts";
|
|
2
|
-
/**
|
|
2
|
+
/** A field's old and new value. */
|
|
3
3
|
export interface ValueChange<T> {
|
|
4
4
|
new: T;
|
|
5
5
|
old: T;
|
|
6
6
|
}
|
|
7
|
-
/** what was added to and removed from a list */
|
|
8
7
|
export interface SetChange<T> {
|
|
9
8
|
added: Array<T>;
|
|
10
9
|
removed: Array<T>;
|
|
11
10
|
}
|
|
12
|
-
/** what changed on a record, only the fields that did */
|
|
13
11
|
export type Changes<R, Field extends keyof R> = Partial<{
|
|
14
12
|
[K in Field]: ValueChange<R[K]>;
|
|
15
13
|
}>;
|
|
16
14
|
export type TagCategoryName = "artist" | "character" | "contributor" | "copyright" | "general" | "invalid" | "lore" | "meta" | "species";
|
|
17
15
|
export type PostFlagName = Extract<keyof LegacyPost["flags"], string>;
|
|
18
|
-
/**
|
|
16
|
+
/** Tags are split by category, so moving a tag between categories shows up as a remove & add. */
|
|
19
17
|
export type PostChanges = Partial<Record<`tags.${TagCategoryName}`, SetChange<string>> & Record<`flags.${PostFlagName}`, ValueChange<boolean>> & {
|
|
20
18
|
approver_id: ValueChange<number | null>;
|
|
21
19
|
children: SetChange<number>;
|
|
@@ -28,3 +26,37 @@ export type PostChanges = Partial<Record<`tags.${TagCategoryName}`, SetChange<st
|
|
|
28
26
|
rating: ValueChange<LegacyPost["rating"]>;
|
|
29
27
|
sources: SetChange<string>;
|
|
30
28
|
}>;
|
|
29
|
+
/** What was last known of a post, only `id` is guaranteed. */
|
|
30
|
+
export type PostSnapshot = Partial<{
|
|
31
|
+
approver_id: number | null;
|
|
32
|
+
change_seq: number;
|
|
33
|
+
children: Array<number>;
|
|
34
|
+
description: string;
|
|
35
|
+
flags: LegacyPost["flags"];
|
|
36
|
+
has_notes: boolean;
|
|
37
|
+
locked_tags: Array<string>;
|
|
38
|
+
md5: string;
|
|
39
|
+
parent_id: number | null;
|
|
40
|
+
pools: Array<number>;
|
|
41
|
+
rating: LegacyPost["rating"];
|
|
42
|
+
sources: Array<string>;
|
|
43
|
+
tags: Partial<Record<TagCategoryName, Array<string>>>;
|
|
44
|
+
} & Omit<PostStats, "changes" | "post_id">> & {
|
|
45
|
+
id: number;
|
|
46
|
+
};
|
|
47
|
+
export interface PostScore {
|
|
48
|
+
down: number;
|
|
49
|
+
total: number;
|
|
50
|
+
up: number;
|
|
51
|
+
}
|
|
52
|
+
export interface PostStats {
|
|
53
|
+
changes: Partial<{
|
|
54
|
+
comment_count: ValueChange<number>;
|
|
55
|
+
fav_count: ValueChange<number>;
|
|
56
|
+
score: ValueChange<PostScore>;
|
|
57
|
+
}>;
|
|
58
|
+
comment_count: number;
|
|
59
|
+
fav_count: number;
|
|
60
|
+
post_id: number;
|
|
61
|
+
score: PostScore;
|
|
62
|
+
}
|
package/dist/events.d.ts
CHANGED
|
@@ -1,25 +1,21 @@
|
|
|
1
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"];
|
|
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.destroy", "post.stats", "post.update", "post_approval.create", "post_event.create", "post_flag.create", "post_flag.update", "post_replacement.create", "post_replacement.destroy", "post_replacement.update", "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
3
|
export type EventType = typeof EVENT_TYPES[number];
|
|
4
|
-
/**
|
|
5
|
-
export declare const PRIVATE_EVENT_TYPES: readonly ["dmail.create"];
|
|
4
|
+
/** Polled with your own credentials, these need to be subscribed to by name. */
|
|
5
|
+
export declare const PRIVATE_EVENT_TYPES: readonly ["dmail.create", "private_post_set.add_posts", "private_post_set.remove_posts"];
|
|
6
6
|
export type PrivateEventType = typeof PRIVATE_EVENT_TYPES[number];
|
|
7
|
-
/** events whose data is the mod action they come from */
|
|
8
7
|
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
8
|
export declare const VERSION_EVENT_TYPES: readonly ["artist.update", "avoid_posting.update", "note.update", "pool.update", "tag.update", "wiki_page.update"];
|
|
11
9
|
export type ModActionEventType = typeof MOD_ACTION_EVENT_TYPES[number];
|
|
12
10
|
export type VersionEventType = typeof VERSION_EVENT_TYPES[number];
|
|
13
|
-
/**
|
|
11
|
+
/** The data for each event type, see https://e621.stream/events/ */
|
|
14
12
|
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
13
|
export type StreamEvent<T extends EventType | PrivateEventType = EventType | PrivateEventType> = T extends EventType | PrivateEventType ? {
|
|
17
14
|
data: EventData<T>;
|
|
18
|
-
/**
|
|
15
|
+
/** Pass this as `cursor` to resume after this event. Private events don't have one. */
|
|
19
16
|
id: string;
|
|
20
|
-
/** only for private events, which are polled with your own credentials and never stored */
|
|
21
17
|
private?: true;
|
|
22
|
-
/**
|
|
18
|
+
/** When it happened on e621. */
|
|
23
19
|
time: string;
|
|
24
20
|
type: T;
|
|
25
21
|
} : never;
|
|
@@ -28,12 +24,11 @@ export interface Filter {
|
|
|
28
24
|
pool_ids?: Array<number>;
|
|
29
25
|
post_ids?: Array<number>;
|
|
30
26
|
set_ids?: Array<number>;
|
|
31
|
-
/** e621 style tag query,
|
|
27
|
+
/** An e621 style tag query, supporting `tag`, `-tag`, `~tag` and `rating:`. */
|
|
32
28
|
tags?: string;
|
|
33
29
|
topic_ids?: Array<number>;
|
|
34
30
|
user_ids?: Array<number>;
|
|
35
31
|
}
|
|
36
|
-
/** an event type, `<resource>.*`, `*`, or one of those with a filter */
|
|
37
32
|
export type Subscription = string | {
|
|
38
33
|
filter?: Filter;
|
|
39
34
|
type: string;
|
|
@@ -51,4 +46,6 @@ export declare const CloseCodes: {
|
|
|
51
46
|
readonly SLOW_CONSUMER: 4009;
|
|
52
47
|
readonly TOO_MANY_CONNECTIONS: 4010;
|
|
53
48
|
readonly AUTHENTICATION_EXPIRED: 4011;
|
|
49
|
+
readonly DISCONNECTED: 4012;
|
|
50
|
+
readonly BANNED: 4013;
|
|
54
51
|
};
|
package/dist/events.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// keep in sync with src/events.ts
|
|
2
2
|
export const EVENT_TYPES = [
|
|
3
3
|
"artist.create",
|
|
4
4
|
"artist.delete",
|
|
@@ -47,12 +47,16 @@ export const EVENT_TYPES = [
|
|
|
47
47
|
"pool.update",
|
|
48
48
|
"pool_version.create",
|
|
49
49
|
"post.create",
|
|
50
|
+
"post.destroy",
|
|
51
|
+
"post.stats",
|
|
50
52
|
"post.update",
|
|
51
53
|
"post_approval.create",
|
|
52
54
|
"post_event.create",
|
|
53
55
|
"post_flag.create",
|
|
54
56
|
"post_flag.update",
|
|
55
57
|
"post_replacement.create",
|
|
58
|
+
"post_replacement.destroy",
|
|
59
|
+
"post_replacement.update",
|
|
56
60
|
"post_set.add_posts",
|
|
57
61
|
"post_set.create",
|
|
58
62
|
"post_set.delete",
|
|
@@ -86,9 +90,12 @@ export const EVENT_TYPES = [
|
|
|
86
90
|
"wiki_page.update",
|
|
87
91
|
"wiki_page_version.create",
|
|
88
92
|
];
|
|
89
|
-
/**
|
|
90
|
-
export const PRIVATE_EVENT_TYPES = [
|
|
91
|
-
|
|
93
|
+
/** Polled with your own credentials, these need to be subscribed to by name. */
|
|
94
|
+
export const PRIVATE_EVENT_TYPES = [
|
|
95
|
+
"dmail.create",
|
|
96
|
+
"private_post_set.add_posts",
|
|
97
|
+
"private_post_set.remove_posts",
|
|
98
|
+
];
|
|
92
99
|
export const MOD_ACTION_EVENT_TYPES = [
|
|
93
100
|
"artist.delete",
|
|
94
101
|
"avoid_posting.delete",
|
|
@@ -119,8 +126,14 @@ export const MOD_ACTION_EVENT_TYPES = [
|
|
|
119
126
|
"user_feedback.update",
|
|
120
127
|
"wiki_page.delete",
|
|
121
128
|
];
|
|
122
|
-
|
|
123
|
-
|
|
129
|
+
export const VERSION_EVENT_TYPES = [
|
|
130
|
+
"artist.update",
|
|
131
|
+
"avoid_posting.update",
|
|
132
|
+
"note.update",
|
|
133
|
+
"pool.update",
|
|
134
|
+
"tag.update",
|
|
135
|
+
"wiki_page.update",
|
|
136
|
+
];
|
|
124
137
|
export const CloseCodes = {
|
|
125
138
|
UNKNOWN_ERROR: 4000,
|
|
126
139
|
UNKNOWN_OP: 4001,
|
|
@@ -134,5 +147,7 @@ export const CloseCodes = {
|
|
|
134
147
|
SLOW_CONSUMER: 4009,
|
|
135
148
|
TOO_MANY_CONNECTIONS: 4010,
|
|
136
149
|
AUTHENTICATION_EXPIRED: 4011,
|
|
150
|
+
DISCONNECTED: 4012,
|
|
151
|
+
BANNED: 4013,
|
|
137
152
|
};
|
|
138
153
|
//# sourceMappingURL=events.js.map
|
package/dist/events.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sourceRoot":"","sources":["../lib/events.ts"],"names":[],"mappings":"AAEA,
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../lib/events.ts"],"names":[],"mappings":"AAEA,kCAAkC;AAElC,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,cAAc;IACd,YAAY;IACZ,aAAa;IACb,sBAAsB;IACtB,mBAAmB;IACnB,kBAAkB;IAClB,kBAAkB;IAClB,yBAAyB;IACzB,0BAA0B;IAC1B,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,gFAAgF;AAEhF,MAAM,CAAC,MAAM,mBAAmB,GAAG;IAC/B,cAAc;IACd,4BAA4B;IAC5B,+BAA+B;CACzB,CAAC;AAIX,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,MAAM,CAAC,MAAM,mBAAmB,GAAG;IAC/B,eAAe;IACf,sBAAsB;IACtB,aAAa;IACb,aAAa;IACb,YAAY;IACZ,kBAAkB;CACZ,CAAC;AA+BX,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;IAC5B,YAAY,EAAE,IAAI;IAClB,MAAM,EAAE,IAAI;CACN,CAAC"}
|
package/dist/generated.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Changes, PostChanges } from "./changes.ts";
|
|
1
|
+
import type { Changes, PostChanges, PostSnapshot, PostStats } from "./changes.ts";
|
|
2
2
|
export type PoolCategory = 'collection' | 'series';
|
|
3
3
|
export type PostEventAction = 'deleted' | 'undeleted' | 'approved' | 'unapproved' | 'flag_created' | 'flag_removed' | 'favorites_moved' | 'favorites_received' | 'rating_locked' | 'rating_unlocked' | 'status_locked' | 'status_unlocked' | 'note_locked' | 'note_unlocked' | 'comment_locked' | 'comment_unlocked' | 'replacement_accepted' | 'replacement_rejected' | 'replacement_promoted' | 'replacement_deleted' | 'expunged' | 'changed_bg_color' | 'replacement_penalty_changed' | 'owner_changed' | 'replacement_moved';
|
|
4
4
|
export type PostReplacementStatus = 'promoted' | 'approved' | 'rejected' | 'pending' | 'original';
|
|
@@ -1084,21 +1084,21 @@ export interface ModActionValues {
|
|
|
1084
1084
|
};
|
|
1085
1085
|
}
|
|
1086
1086
|
export type ModActionName = keyof ModActionValues;
|
|
1087
|
-
/**
|
|
1087
|
+
/** Checking `action` narrows `values`. */
|
|
1088
1088
|
export type ModAction<A extends ModActionName = ModActionName> = A extends ModActionName ? {
|
|
1089
1089
|
action: A;
|
|
1090
1090
|
created_at: string;
|
|
1091
1091
|
creator_id: number;
|
|
1092
1092
|
id: number;
|
|
1093
1093
|
updated_at: string;
|
|
1094
|
-
/**
|
|
1094
|
+
/** What the action applies to. */
|
|
1095
1095
|
values: ModActionValues[A];
|
|
1096
1096
|
} : never;
|
|
1097
|
-
/**
|
|
1097
|
+
/** `changes` is null when the previous state isn't known. */
|
|
1098
1098
|
export type Update<Resource extends string, R, Field extends keyof R & string> = Record<Resource, R> & {
|
|
1099
1099
|
changes: Changes<R, Field> | null;
|
|
1100
1100
|
};
|
|
1101
|
-
/**
|
|
1101
|
+
/** The `data` each event type is sent with. */
|
|
1102
1102
|
export interface EventDataMap {
|
|
1103
1103
|
"artist.create": Artist;
|
|
1104
1104
|
"artist.delete": ModAction<"artist_delete">;
|
|
@@ -1155,6 +1155,11 @@ export interface EventDataMap {
|
|
|
1155
1155
|
"post.create": {
|
|
1156
1156
|
post: LegacyPost;
|
|
1157
1157
|
};
|
|
1158
|
+
"post.destroy": {
|
|
1159
|
+
post: PostSnapshot;
|
|
1160
|
+
post_event: PostEvent;
|
|
1161
|
+
};
|
|
1162
|
+
"post.stats": PostStats;
|
|
1158
1163
|
"post.update": {
|
|
1159
1164
|
changes: PostChanges | null;
|
|
1160
1165
|
post: LegacyPost;
|
|
@@ -1164,6 +1169,11 @@ export interface EventDataMap {
|
|
|
1164
1169
|
"post_flag.create": PostFlag;
|
|
1165
1170
|
"post_flag.update": Update<"post_flag", PostFlag, "is_resolved">;
|
|
1166
1171
|
"post_replacement.create": PostReplacement;
|
|
1172
|
+
"post_replacement.destroy": {
|
|
1173
|
+
post_event: PostEvent;
|
|
1174
|
+
post_replacement: Pick<PostReplacement, "id" | "status" | "approver_id" | "reason" | "post_id">;
|
|
1175
|
+
};
|
|
1176
|
+
"post_replacement.update": Update<"post_replacement", PostReplacement, "status" | "approver_id" | "reason" | "post_id">;
|
|
1167
1177
|
"post_set.add_posts": Record<"post_set", PostSet> & {
|
|
1168
1178
|
post_ids: Array<number>;
|
|
1169
1179
|
};
|
|
@@ -1201,4 +1211,12 @@ export interface EventDataMap {
|
|
|
1201
1211
|
"wiki_page.update": WikiPageVersion;
|
|
1202
1212
|
"wiki_page_version.create": WikiPageVersion;
|
|
1203
1213
|
"dmail.create": DMail;
|
|
1214
|
+
"private_post_set.add_posts": {
|
|
1215
|
+
post_ids: Array<number>;
|
|
1216
|
+
post_set: PostSet;
|
|
1217
|
+
};
|
|
1218
|
+
"private_post_set.remove_posts": {
|
|
1219
|
+
post_ids: Array<number>;
|
|
1220
|
+
post_set: PostSet;
|
|
1221
|
+
};
|
|
1204
1222
|
}
|