puppywebhook 1.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/.gitattributes +2 -0
- package/README.md +36 -0
- package/package.json +26 -0
- package/src/index.js +126 -0
package/.gitattributes
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# puppywebhook
|
|
2
|
+
|
|
3
|
+
[On npm @ https://www.npmjs.com/package/puppywebhook](https://www.npmjs.com/package/puppywebhook)
|
|
4
|
+
|
|
5
|
+
[And GitHub @ https://github.com/onlypuppy7/puppywebhook](https://github.com/onlypuppy7/puppywebhook)
|
|
6
|
+
|
|
7
|
+
Discord webhook wrapper/helper, ported to npm. Another useless file taken out of my projects!
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
`npm install puppywebhook`
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
```js
|
|
14
|
+
import PuppyWebhook from 'puppywebhook';
|
|
15
|
+
|
|
16
|
+
const webhook = new PuppyWebhook({
|
|
17
|
+
webhookUrl: "https://discord.com/api/webhooks/1460782220192256031/Fkibsumk3hWg4M6F2eCmDe_ylXaJlY_z3W9XeCMWbiw4r8zcYfQJg64YeIhaHT-7tpbT",
|
|
18
|
+
username: 'StateFarmBot',
|
|
19
|
+
maxMessageLength: 1800,
|
|
20
|
+
|
|
21
|
+
//logs just for testing
|
|
22
|
+
logSends: true,
|
|
23
|
+
logErrors: true
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
console.log('Queuing some test webhook messages...');
|
|
27
|
+
|
|
28
|
+
webhook.send('Bot started');
|
|
29
|
+
webhook.send('Loaded config');
|
|
30
|
+
webhook.send('Something happened');
|
|
31
|
+
|
|
32
|
+
process.on('exit', async () => {
|
|
33
|
+
console.log('Flushing webhook messages before exit...');
|
|
34
|
+
await webhook.flush();
|
|
35
|
+
});
|
|
36
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "puppywebhook",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Queued, rate safe Discord webhook logger with automatic chunking",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./src/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.js"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"discord",
|
|
12
|
+
"webhook",
|
|
13
|
+
"logger",
|
|
14
|
+
"queue",
|
|
15
|
+
"rate-limit",
|
|
16
|
+
"logging"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"test": "node src/tests/test.js"
|
|
20
|
+
},
|
|
21
|
+
"author": "onlypuppy7",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"node-fetch": "^3.3.2"
|
|
25
|
+
}
|
|
26
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import fetch from 'node-fetch';
|
|
2
|
+
|
|
3
|
+
export class PuppyWebhook {
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
this.webhookUrl = options.webhookUrl;
|
|
6
|
+
this.username = options.username ?? 'puppywebhook';
|
|
7
|
+
this.avatar = options.avatar ?? null;
|
|
8
|
+
|
|
9
|
+
this.maxMessageLength = options.maxMessageLength ?? 1900;
|
|
10
|
+
this.minDelay = options.minDelay ?? 5000;
|
|
11
|
+
this.maxDelay = options.maxDelay ?? 15000;
|
|
12
|
+
this.logSends = options.logSends ?? false;
|
|
13
|
+
this.logErrors = options.logErrors ?? true;
|
|
14
|
+
|
|
15
|
+
this.logQueue = [];
|
|
16
|
+
this.queuedChunks = [];
|
|
17
|
+
this.messagesSent = 0;
|
|
18
|
+
|
|
19
|
+
this.interval = null;
|
|
20
|
+
|
|
21
|
+
if (!this.webhookUrl) {
|
|
22
|
+
throw new Error('webhookUrl is required');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
this.start();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
send(message) {
|
|
29
|
+
if (typeof message !== 'string') {
|
|
30
|
+
message = String(message);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
this.logQueue.push(message);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
start() {
|
|
37
|
+
if (this.interval) return;
|
|
38
|
+
this.interval = setInterval(() => this._process(), this._nextDelay());
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
stop() {
|
|
42
|
+
if (!this.interval) return;
|
|
43
|
+
clearInterval(this.interval);
|
|
44
|
+
this.interval = null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
flush() {
|
|
48
|
+
return this._process(true);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async _process(force = false) {
|
|
52
|
+
while (this.logQueue.length > 0) {
|
|
53
|
+
const msg = this.logQueue.shift();
|
|
54
|
+
|
|
55
|
+
if (msg.length > this.maxMessageLength) {
|
|
56
|
+
const parts = this._split(msg);
|
|
57
|
+
this.logQueue.unshift(...parts);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const last = this.queuedChunks[0] ?? '';
|
|
62
|
+
const next = last + '\n' + msg;
|
|
63
|
+
|
|
64
|
+
if (next.length > this.maxMessageLength) {
|
|
65
|
+
this.queuedChunks.unshift(msg);
|
|
66
|
+
} else {
|
|
67
|
+
this.queuedChunks[0] = next;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (this.queuedChunks.length === 0 && !force) return;
|
|
72
|
+
|
|
73
|
+
const chunkContent = this.queuedChunks[this.queuedChunks.length - 1];
|
|
74
|
+
if (!chunkContent) return;
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const content = chunkContent.slice(0, 2000) + ` (${this.messagesSent % 1000})`
|
|
78
|
+
|
|
79
|
+
const res = await fetch(this.webhookUrl, {
|
|
80
|
+
method: 'POST',
|
|
81
|
+
headers: { 'Content-Type': 'application/json' },
|
|
82
|
+
body: JSON.stringify({
|
|
83
|
+
username: this.username,
|
|
84
|
+
avatar_url: this.avatar,
|
|
85
|
+
content: content
|
|
86
|
+
})
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
if (!res.ok) {
|
|
90
|
+
throw new Error(res.statusText);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
this.logSends && console.log('Sent webhook message:', content);
|
|
94
|
+
|
|
95
|
+
this.queuedChunks.pop();
|
|
96
|
+
this.messagesSent++;
|
|
97
|
+
} catch (err) {
|
|
98
|
+
this.logErrors && console.error('Error sending webhook:', err);
|
|
99
|
+
this.logQueue.unshift(chunkContent);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
this._reschedule();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
_split(str) {
|
|
106
|
+
const chunks = [];
|
|
107
|
+
for (let i = 0; i < str.length; i += this.maxMessageLength) {
|
|
108
|
+
chunks.push(str.slice(i, i + this.maxMessageLength));
|
|
109
|
+
}
|
|
110
|
+
return chunks;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
_nextDelay() {
|
|
114
|
+
const base = this.maxDelay - Math.min(this.queuedChunks.length, 7) * 1000;
|
|
115
|
+
const jitter = (Math.floor(Math.random() * 8) - 4) * 1000;
|
|
116
|
+
return Math.max(this.minDelay, base + jitter);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
_reschedule() {
|
|
120
|
+
if (!this.interval) return;
|
|
121
|
+
clearInterval(this.interval);
|
|
122
|
+
this.interval = setInterval(() => this._process(), this._nextDelay());
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export default PuppyWebhook;
|