@ovencord/util 1.1.7 → 1.1.8
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/package.json +1 -1
- package/src/AsyncEventEmitter.ts +200 -197
- package/src/AsyncQueue.ts +23 -23
- package/src/RawFile.ts +0 -1
- package/src/Snowflake.ts +9 -1
- package/src/functions/runtime.ts +0 -2
- package/src/functions/userAgentAppendix.ts +4 -6
- package/src/index.ts +8 -8
- package/src/shims.d.ts +3 -3
package/package.json
CHANGED
package/src/AsyncEventEmitter.ts
CHANGED
|
@@ -3,201 +3,204 @@ import { AsyncQueue } from './AsyncQueue.js';
|
|
|
3
3
|
export type EventMap = Record<string | symbol, any[]>;
|
|
4
4
|
|
|
5
5
|
export class AsyncEventEmitter<Events extends Record<keyof Events, any[]> = any> {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
6
|
+
private _listeners = new Map<keyof Events | string | symbol, Set<Function>>();
|
|
7
|
+
private _maxListeners = 10;
|
|
8
|
+
|
|
9
|
+
public on<K extends keyof Events>(event: K, listener: (...args: Events[K]) => void | Promise<void>): this;
|
|
10
|
+
public on<K extends string | symbol>(event: K, listener: (...args: any[]) => void | Promise<void>): this;
|
|
11
|
+
public on(event: string | symbol, listener: Function): this {
|
|
12
|
+
if (!this._listeners.has(event)) {
|
|
13
|
+
this._listeners.set(event, new Set());
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const listeners = this._listeners.get(event)!;
|
|
17
|
+
listeners.add(listener);
|
|
18
|
+
|
|
19
|
+
if (listeners.size > this._maxListeners) {
|
|
20
|
+
console.warn(
|
|
21
|
+
`Possible AsyncEventEmitter memory leak detected. ` +
|
|
22
|
+
`${listeners.size} ${String(event)} listeners added. ` +
|
|
23
|
+
`Use emitter.setMaxListeners() to increase limit`,
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public addListener<K extends keyof Events>(event: K, listener: (...args: Events[K]) => void | Promise<void>): this;
|
|
31
|
+
public addListener<K extends string | symbol>(event: K, listener: (...args: any[]) => void | Promise<void>): this;
|
|
32
|
+
public addListener(event: string | symbol, listener: Function): this {
|
|
33
|
+
return this.on(event, listener as any);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public once<K extends keyof Events>(event: K, listener: (...args: Events[K]) => void | Promise<void>): this;
|
|
37
|
+
public once<K extends string | symbol>(event: K, listener: (...args: any[]) => void | Promise<void>): this;
|
|
38
|
+
public once(event: string | symbol, listener: Function): this {
|
|
39
|
+
const wrapper = async (...args: any[]) => {
|
|
40
|
+
this.off(event, wrapper);
|
|
41
|
+
await listener(...args);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
Object.defineProperty(wrapper, '_originalListener', {
|
|
45
|
+
value: listener,
|
|
46
|
+
writable: false,
|
|
47
|
+
enumerable: false,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
return this.on(event, wrapper);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public off<K extends keyof Events>(event: K, listener: (...args: Events[K]) => void | Promise<void>): this;
|
|
54
|
+
public off<K extends string | symbol>(event: K, listener: (...args: any[]) => void | Promise<void>): this;
|
|
55
|
+
public off(event: string | symbol, listener: Function): this {
|
|
56
|
+
const listeners = this._listeners.get(event);
|
|
57
|
+
if (!listeners) return this;
|
|
58
|
+
|
|
59
|
+
for (const fn of listeners) {
|
|
60
|
+
if (fn === listener || (fn as any)._originalListener === listener) {
|
|
61
|
+
listeners.delete(fn);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (listeners.size === 0) {
|
|
66
|
+
this._listeners.delete(event);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return this;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public removeListener<K extends keyof Events>(event: K, listener: (...args: Events[K]) => void | Promise<void>): this;
|
|
73
|
+
public removeListener<K extends string | symbol>(event: K, listener: (...args: any[]) => void | Promise<void>): this;
|
|
74
|
+
public removeListener(event: string | symbol, listener: Function): this {
|
|
75
|
+
return this.off(event, listener as any);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public async emit<K extends keyof Events>(event: K, ...args: Events[K]): Promise<boolean>;
|
|
79
|
+
public async emit<K extends string | symbol>(event: K, ...args: any[]): Promise<boolean>;
|
|
80
|
+
public async emit(event: string | symbol, ...args: any[]): Promise<boolean> {
|
|
81
|
+
const listeners = this._listeners.get(event);
|
|
82
|
+
if (!listeners?.size) return false;
|
|
83
|
+
|
|
84
|
+
// We copy the listeners to ensure that if a listener is removed during execution,
|
|
85
|
+
// the loop still iterates over the snapshot of listeners at the time of emission.
|
|
86
|
+
// However, for strict sequential execution where one might remove another,
|
|
87
|
+
// iterating over the live Set or a copy is a design choice.
|
|
88
|
+
// Discord.js usually handles this by copying or iterating safe.
|
|
89
|
+
// The user's snippet iterates directly over the listeners collection from .get().
|
|
90
|
+
// If we use 'for of' on a Set, it handles deletions gracefully (the deleted item won't be visited if not reached yet),
|
|
91
|
+
// but additions might be visited.
|
|
92
|
+
// For now, adhering to user's "for (const listener of listeners)" pattern.
|
|
93
|
+
|
|
94
|
+
// NOTE: Iterating over the Set directly allows listeners to remove themselves safely.
|
|
95
|
+
for (const listener of listeners) {
|
|
96
|
+
try {
|
|
97
|
+
await listener(...args);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
if (event === 'error') {
|
|
100
|
+
console.error('Error in error handler:', error);
|
|
101
|
+
} else if (this.listenerCount('error') > 0) {
|
|
102
|
+
await this.emit('error', error);
|
|
103
|
+
} else {
|
|
104
|
+
console.error(`Unhandled error in ${String(event)} event:`, error);
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
public removeAllListeners(event?: keyof Events | string | symbol): this {
|
|
114
|
+
if (event !== undefined) {
|
|
115
|
+
this._listeners.delete(event);
|
|
116
|
+
} else {
|
|
117
|
+
this._listeners.clear();
|
|
118
|
+
}
|
|
119
|
+
return this;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public setMaxListeners(n: number): this {
|
|
123
|
+
this._maxListeners = n;
|
|
124
|
+
return this;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
public getMaxListeners(): number {
|
|
128
|
+
return this._maxListeners;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
public listenerCount(event: keyof Events | string | symbol): number {
|
|
132
|
+
return this._listeners.get(event)?.size ?? 0;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public eventNames(): Array<keyof Events | string | symbol> {
|
|
136
|
+
return Array.from(this._listeners.keys());
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
public rawListeners(event: keyof Events | string | symbol): Function[] {
|
|
140
|
+
return Array.from(this._listeners.get(event) ?? []);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
public waitFor<K extends keyof Events>(event: K, timeout?: number): Promise<Events[K]>;
|
|
144
|
+
public waitFor(event: string | symbol, timeout?: number): Promise<any[]> {
|
|
145
|
+
return new Promise((resolve, reject) => {
|
|
146
|
+
let timeoutId: Timer | undefined;
|
|
147
|
+
|
|
148
|
+
const listener = (...args: any[]) => {
|
|
149
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
150
|
+
resolve(args);
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
this.once(event, listener);
|
|
154
|
+
|
|
155
|
+
if (timeout) {
|
|
156
|
+
timeoutId = setTimeout(() => {
|
|
157
|
+
this.off(event, listener);
|
|
158
|
+
reject(new Error(`Timeout waiting for ${String(event)}`));
|
|
159
|
+
}, timeout);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
public static async *on<
|
|
165
|
+
T extends AsyncEventEmitter<any>,
|
|
166
|
+
K extends keyof (T extends AsyncEventEmitter<infer U> ? U : never),
|
|
167
|
+
>(
|
|
168
|
+
emitter: T,
|
|
169
|
+
eventName: K,
|
|
170
|
+
options?: { signal?: AbortSignal },
|
|
171
|
+
): AsyncIterableIterator<(T extends AsyncEventEmitter<infer U> ? U : never)[K]> {
|
|
172
|
+
const signal = options?.signal;
|
|
173
|
+
if (signal?.aborted) throw new Error('AbortError');
|
|
174
|
+
|
|
175
|
+
const queue = new AsyncQueue();
|
|
176
|
+
const items: any[][] = [];
|
|
177
|
+
|
|
178
|
+
const listener = (...args: any[]) => {
|
|
179
|
+
items.push(args);
|
|
180
|
+
queue.shift();
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const abortHandler = () => {
|
|
184
|
+
emitter.off(eventName as any, listener);
|
|
185
|
+
queue.shift();
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
emitter.on(eventName as any, listener);
|
|
189
|
+
signal?.addEventListener('abort', abortHandler, { once: true });
|
|
190
|
+
|
|
191
|
+
try {
|
|
192
|
+
while (true) {
|
|
193
|
+
if (signal?.aborted && items.length === 0) break;
|
|
194
|
+
if (items.length === 0) {
|
|
195
|
+
await queue.wait(options);
|
|
196
|
+
}
|
|
197
|
+
if (signal?.aborted && items.length === 0) break;
|
|
198
|
+
|
|
199
|
+
yield items.shift()! as any;
|
|
200
|
+
}
|
|
201
|
+
} finally {
|
|
202
|
+
emitter.off(eventName as any, listener);
|
|
203
|
+
signal?.removeEventListener('abort', abortHandler);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
203
206
|
}
|
package/src/AsyncQueue.ts
CHANGED
|
@@ -17,7 +17,7 @@ export class AsyncQueue {
|
|
|
17
17
|
* @param options.signal - An optional abort signal
|
|
18
18
|
*/
|
|
19
19
|
public wait(options?: { signal?: AbortSignal }): Promise<void> {
|
|
20
|
-
const next = this.#promises.length ? this.#promises.at(-1)
|
|
20
|
+
const next = this.#promises.length ? this.#promises.at(-1)?.promise : Promise.resolve();
|
|
21
21
|
|
|
22
22
|
let resolve!: () => void;
|
|
23
23
|
const promise = new Promise<void>((res) => {
|
|
@@ -26,32 +26,32 @@ export class AsyncQueue {
|
|
|
26
26
|
|
|
27
27
|
this.#promises.push({ promise, resolve });
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
// If no signal, just return the promise we wait on
|
|
30
|
+
if (!options?.signal) {
|
|
31
|
+
return next;
|
|
32
|
+
}
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
return new Promise((res, rej) => {
|
|
35
|
+
if (options.signal?.aborted) {
|
|
36
|
+
// Bridge immediately: when next resolves, we resolve our token
|
|
37
|
+
next.then(() => resolve());
|
|
38
|
+
rej(new Error('AbortError')); // TODO: Use DOMException or standard AbortError if available
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
const abortHandler = () => {
|
|
43
|
+
// Bridge: when next resolves, we resolve our token
|
|
44
|
+
next.then(() => resolve());
|
|
45
|
+
rej(new Error('AbortError'));
|
|
46
|
+
};
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
options.signal?.addEventListener('abort', abortHandler, { once: true });
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
next.then(() => {
|
|
51
|
+
options.signal?.removeEventListener('abort', abortHandler);
|
|
52
|
+
res();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
/**
|
package/src/RawFile.ts
CHANGED
package/src/Snowflake.ts
CHANGED
|
@@ -181,7 +181,15 @@ export class Snowflake {
|
|
|
181
181
|
const typeA = typeof a;
|
|
182
182
|
if (typeA === typeof b) {
|
|
183
183
|
if (typeA === 'string') {
|
|
184
|
-
return a === b
|
|
184
|
+
return a === b
|
|
185
|
+
? 0
|
|
186
|
+
: (a as string).length < (b as string).length
|
|
187
|
+
? -1
|
|
188
|
+
: (a as string).length > (b as string).length
|
|
189
|
+
? 1
|
|
190
|
+
: a < b
|
|
191
|
+
? -1
|
|
192
|
+
: 1;
|
|
185
193
|
}
|
|
186
194
|
|
|
187
195
|
return a === b ? 0 : (a as bigint) < (b as bigint) ? -1 : 1;
|
package/src/functions/runtime.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Resolves the user agent appendix string for the current environment.
|
|
5
3
|
*/
|
|
@@ -8,24 +6,24 @@ export function getUserAgentAppendix(): string {
|
|
|
8
6
|
if (typeof (globalThis as any).EdgeRuntime !== 'undefined') {
|
|
9
7
|
return 'Vercel-Edge-Functions';
|
|
10
8
|
}
|
|
11
|
-
|
|
9
|
+
|
|
12
10
|
// Cloudflare Workers
|
|
13
11
|
if (typeof (globalThis as any).R2 !== 'undefined' && typeof (globalThis as any).WebSocketPair !== 'undefined') {
|
|
14
12
|
// https://developers.cloudflare.com/workers/runtime-apis/web-standards/#navigatoruseragent
|
|
15
13
|
return 'Cloudflare-Workers';
|
|
16
14
|
}
|
|
17
|
-
|
|
15
|
+
|
|
18
16
|
// https://docs.netlify.com/edge-functions/api/#netlify-global-object
|
|
19
17
|
if (typeof (globalThis as any).Netlify !== 'undefined') {
|
|
20
18
|
return 'Netlify-Edge-Functions';
|
|
21
19
|
}
|
|
22
|
-
|
|
20
|
+
|
|
23
21
|
// Most (if not all) edge environments will have `process` defined. Within a web browser we'll extract it using `navigator.userAgent`.
|
|
24
22
|
if (typeof (globalThis as any).process !== 'object') {
|
|
25
23
|
if (typeof (globalThis as any).navigator === 'object') {
|
|
26
24
|
return (globalThis as any).navigator.userAgent;
|
|
27
25
|
}
|
|
28
|
-
|
|
26
|
+
|
|
29
27
|
return 'UnknownEnvironment';
|
|
30
28
|
}
|
|
31
29
|
|
package/src/index.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
export type * from './types.js';
|
|
2
|
-
export { DiscordSnowflake, Snowflake as SnowflakeClass } from './Snowflake.js';
|
|
3
|
-
export type { DeconstructedSnowflake, SnowflakeGenerateOptions } from './Snowflake.js';
|
|
4
|
-
export * from './functions/index.js';
|
|
5
|
-
export * from './encodables.js';
|
|
6
|
-
export type * from './RawFile.js';
|
|
7
|
-
export * from './Equatable.js';
|
|
8
|
-
export * from './gatewayRateLimitError.js';
|
|
9
1
|
export * from './AsyncEventEmitter.js';
|
|
10
2
|
export * from './AsyncQueue.js';
|
|
3
|
+
export * from './Equatable.js';
|
|
4
|
+
export * from './encodables.js';
|
|
5
|
+
export * from './functions/index.js';
|
|
6
|
+
export * from './gatewayRateLimitError.js';
|
|
7
|
+
export type * from './RawFile.js';
|
|
8
|
+
export type { DeconstructedSnowflake, SnowflakeGenerateOptions } from './Snowflake.js';
|
|
9
|
+
export { DiscordSnowflake, Snowflake as SnowflakeClass } from './Snowflake.js';
|
|
10
|
+
export type * from './types.js';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* The {@link https://github.com/ovencord/ovencord/blob/main/packages/util#readme | @ovencord/util} version
|
package/src/shims.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Type Shims for Bun Native Environment
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* This file provides type declarations to eliminate conflicts between
|
|
5
5
|
* @types/node and @types/bun, allowing clean TypeScript compilation
|
|
6
6
|
* in a pure Bun environment.
|
|
@@ -47,9 +47,9 @@ declare global {
|
|
|
47
47
|
platform: string;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
interface Timeout extends
|
|
50
|
+
interface Timeout extends number {}
|
|
51
51
|
}
|
|
52
|
-
|
|
52
|
+
|
|
53
53
|
// Global declarations
|
|
54
54
|
var process: NodeJS.Process;
|
|
55
55
|
var __dirname: string;
|