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 ADDED
@@ -0,0 +1,2 @@
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
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;