lunibee 0.3.0 → 0.3.1
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/dist/builders/embed.d.ts +1 -0
- package/dist/builders/index.js +6 -2
- package/dist/builders/index.js.map +4 -4
- package/dist/core/index.js +66 -15
- package/dist/core/index.js.map +8 -8
- package/dist/index.js +2345 -199
- package/dist/index.js.map +22 -14
- package/dist/managers/index.js +2 -2
- package/dist/managers/index.js.map +3 -3
- package/dist/rest/errors.d.ts +8 -0
- package/dist/rest/index.d.ts +2 -0
- package/dist/rest/index.js +65 -14
- package/dist/rest/index.js.map +5 -5
- package/dist/rest/transport.d.ts +9 -0
- package/dist/sharding/bus.d.ts +8 -0
- package/dist/sharding/cluster.d.ts +224 -14
- package/dist/sharding/context.d.ts +41 -0
- package/dist/sharding/gateway-bot.d.ts +20 -0
- package/dist/sharding/health.d.ts +94 -0
- package/dist/sharding/host.d.ts +70 -0
- package/dist/sharding/identify.d.ts +62 -0
- package/dist/sharding/index.d.ts +56 -12
- package/dist/sharding/index.js +2255 -164
- package/dist/sharding/index.js.map +18 -10
- package/dist/sharding/protocol.d.ts +47 -0
- package/dist/sharding/remote-protocol.d.ts +100 -0
- package/dist/sharding/remote.d.ts +118 -0
- package/dist/sharding/requests.d.ts +54 -0
- package/dist/sharding/worker.d.ts +45 -0
- package/dist/structures/index.js +2 -2
- package/dist/structures/index.js.map +3 -3
- package/dist/types/gateway.d.ts +3 -0
- package/dist/types/index.js.map +1 -1
- package/dist/ws/index.d.ts +1 -1
- package/dist/ws/index.js +2 -2
- package/dist/ws/index.js.map +5 -5
- package/dist/ws/send-budget.d.ts +1 -1
- package/package.json +18 -16
package/dist/rest/errors.d.ts
CHANGED
|
@@ -26,6 +26,14 @@ export type RESTErrorKind =
|
|
|
26
26
|
* credential.
|
|
27
27
|
*/
|
|
28
28
|
export declare function redactPath(path: string): string;
|
|
29
|
+
/** Hides webhook and interaction tokens in free text. */
|
|
30
|
+
export declare function redactText(text: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* A copy of a lower-level error that is safe to attach as a `cause`: the same
|
|
33
|
+
* name and code, with tokens removed from the message and stack. Runtimes put
|
|
34
|
+
* the request URL in network error messages, and the URL holds webhook tokens.
|
|
35
|
+
*/
|
|
36
|
+
export declare function sanitizeCause(error: unknown): unknown;
|
|
29
37
|
/** Error thrown when Discord rejects a REST request. */
|
|
30
38
|
export declare class RESTError extends Error {
|
|
31
39
|
/** Failure category. */
|
package/dist/rest/index.d.ts
CHANGED
|
@@ -107,6 +107,8 @@ export declare class REST {
|
|
|
107
107
|
retries?: number;
|
|
108
108
|
retryPolicy?: RetryPolicy;
|
|
109
109
|
baseURL?: string;
|
|
110
|
+
/** Allow a cleartext `http://` base URL on a network you trust (a REST proxy). Default false. */
|
|
111
|
+
allowInsecureBaseURL?: boolean;
|
|
110
112
|
hooks?: RESTHooks;
|
|
111
113
|
store?: RateLimitStore;
|
|
112
114
|
/** Replaces the HTTP stage, e.g. with a recording transport in tests. */
|
package/dist/rest/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// packages/rest/package.json
|
|
3
3
|
var package_default = {
|
|
4
4
|
name: "@lunibee/rest",
|
|
5
|
-
version: "0.3.
|
|
5
|
+
version: "0.3.1",
|
|
6
6
|
type: "module",
|
|
7
7
|
module: "./src/index.ts",
|
|
8
8
|
types: "./src/index.ts",
|
|
@@ -85,6 +85,24 @@ function kindFromStatus(status) {
|
|
|
85
85
|
function redactPath(path) {
|
|
86
86
|
return path.replace(/^(\/webhooks\/[^/?]+\/)[^/?]+/i, "$1:token").replace(/^(\/interactions\/[^/?]+\/)[^/?]+/i, "$1:token");
|
|
87
87
|
}
|
|
88
|
+
var TOKEN_IN_TEXT = /(\/(?:webhooks|interactions)\/[^/\s?"'`]+\/)[^/\s?"'`]+/gi;
|
|
89
|
+
function redactText(text) {
|
|
90
|
+
return text.replace(TOKEN_IN_TEXT, "$1:token");
|
|
91
|
+
}
|
|
92
|
+
function sanitizeCause(error) {
|
|
93
|
+
if (!(error instanceof Error))
|
|
94
|
+
return;
|
|
95
|
+
const copy = new Error(redactText(error.message));
|
|
96
|
+
copy.name = error.name;
|
|
97
|
+
if (error.stack)
|
|
98
|
+
copy.stack = redactText(error.stack);
|
|
99
|
+
for (const key of ["code", "errno", "syscall"]) {
|
|
100
|
+
const value = error[key];
|
|
101
|
+
if (typeof value === "string" || typeof value === "number")
|
|
102
|
+
copy[key] = value;
|
|
103
|
+
}
|
|
104
|
+
return copy;
|
|
105
|
+
}
|
|
88
106
|
var HINTS = {
|
|
89
107
|
50001: "The bot cannot see this resource: check that it is in the guild and has View Channel there.",
|
|
90
108
|
50013: "The bot lacks a permission for this action, or the target role or member is at or above the bot's highest role."
|
|
@@ -120,14 +138,19 @@ async function sleep(delay, signal, path) {
|
|
|
120
138
|
if (delay <= 0)
|
|
121
139
|
return;
|
|
122
140
|
await new Promise((resolve, reject) => {
|
|
123
|
-
const
|
|
124
|
-
const abort = () => {
|
|
141
|
+
const finish = (error) => {
|
|
125
142
|
clearTimeout(timer);
|
|
126
|
-
|
|
143
|
+
signal?.removeEventListener("abort", onAbort);
|
|
144
|
+
if (error)
|
|
145
|
+
reject(error);
|
|
146
|
+
else
|
|
147
|
+
resolve();
|
|
127
148
|
};
|
|
149
|
+
const onAbort = () => finish(abortError(path, signal?.reason));
|
|
150
|
+
const timer = setTimeout(finish, delay);
|
|
128
151
|
if (signal?.aborted)
|
|
129
|
-
return
|
|
130
|
-
signal?.addEventListener("abort",
|
|
152
|
+
return onAbort();
|
|
153
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
131
154
|
});
|
|
132
155
|
}
|
|
133
156
|
async function abortable(promise, signal, path) {
|
|
@@ -135,10 +158,17 @@ async function abortable(promise, signal, path) {
|
|
|
135
158
|
return promise;
|
|
136
159
|
if (signal.aborted)
|
|
137
160
|
throw abortError(path, signal.reason);
|
|
138
|
-
return Promise
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
161
|
+
return new Promise((resolve, reject) => {
|
|
162
|
+
const onAbort = () => reject(abortError(path, signal.reason));
|
|
163
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
164
|
+
promise.then(() => {
|
|
165
|
+
signal.removeEventListener("abort", onAbort);
|
|
166
|
+
resolve();
|
|
167
|
+
}, (error) => {
|
|
168
|
+
signal.removeEventListener("abort", onAbort);
|
|
169
|
+
reject(error);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
142
172
|
}
|
|
143
173
|
|
|
144
174
|
// packages/rest/src/route.ts
|
|
@@ -312,6 +342,25 @@ class RateLimiter {
|
|
|
312
342
|
}
|
|
313
343
|
|
|
314
344
|
// packages/rest/src/transport.ts
|
|
345
|
+
var LOOPBACK = /^(?:localhost|127(?:\.\d{1,3}){3}|\[::1\])$/i;
|
|
346
|
+
function parseBaseURL(raw, allowInsecure = false) {
|
|
347
|
+
let url;
|
|
348
|
+
try {
|
|
349
|
+
url = new URL(raw);
|
|
350
|
+
} catch {
|
|
351
|
+
throw new TypeError("baseURL must be an absolute http(s) URL.");
|
|
352
|
+
}
|
|
353
|
+
if (url.protocol !== "https:" && url.protocol !== "http:")
|
|
354
|
+
throw new TypeError("baseURL must use https.");
|
|
355
|
+
if (url.username || url.password)
|
|
356
|
+
throw new TypeError("baseURL must not contain credentials.");
|
|
357
|
+
if (url.search || url.hash)
|
|
358
|
+
throw new TypeError("baseURL must not contain a query or fragment.");
|
|
359
|
+
if (url.protocol === "http:" && !allowInsecure && !LOOPBACK.test(url.hostname))
|
|
360
|
+
throw new TypeError("baseURL must use https: the bot token would travel in cleartext (allowInsecureBaseURL: true overrides this for a trusted network).");
|
|
361
|
+
return raw.replace(/\/$/, "");
|
|
362
|
+
}
|
|
363
|
+
|
|
315
364
|
class TransportError extends Error {
|
|
316
365
|
timedOut;
|
|
317
366
|
constructor(message, timedOut, cause) {
|
|
@@ -326,7 +375,7 @@ class HttpTransport {
|
|
|
326
375
|
#timeout;
|
|
327
376
|
#fetch;
|
|
328
377
|
constructor(options = {}) {
|
|
329
|
-
this.#baseURL = (options.baseURL ?? "https://discord.com/api/v10"
|
|
378
|
+
this.#baseURL = parseBaseURL(options.baseURL ?? "https://discord.com/api/v10", options.allowInsecureBaseURL);
|
|
330
379
|
this.#timeout = Math.max(1, options.timeout ?? 15000);
|
|
331
380
|
this.#fetch = options.fetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
332
381
|
}
|
|
@@ -348,13 +397,14 @@ class HttpTransport {
|
|
|
348
397
|
method: request.method,
|
|
349
398
|
headers: request.headers,
|
|
350
399
|
body: request.body,
|
|
351
|
-
signal: controller.signal
|
|
400
|
+
signal: controller.signal,
|
|
401
|
+
redirect: "error"
|
|
352
402
|
});
|
|
353
403
|
} catch (error) {
|
|
354
404
|
if (error instanceof RESTError)
|
|
355
405
|
throw error;
|
|
356
406
|
const timedOut = error instanceof DOMException && (error.name === "TimeoutError" || error.name === "AbortError");
|
|
357
|
-
throw new TransportError(timedOut ? `Discord REST request timed out after ${this.#timeout}ms` : "Discord REST request failed", timedOut, error);
|
|
407
|
+
throw new TransportError(timedOut ? `Discord REST request timed out after ${this.#timeout}ms` : "Discord REST request failed", timedOut, sanitizeCause(error));
|
|
358
408
|
} finally {
|
|
359
409
|
clearTimeout(timer);
|
|
360
410
|
request.signal?.removeEventListener("abort", onAbort);
|
|
@@ -793,6 +843,7 @@ class REST {
|
|
|
793
843
|
this.#retryPolicy = options.retryPolicy ?? createRetryPolicy(options.retries ?? 2);
|
|
794
844
|
this.#transport = options.transport ?? new HttpTransport({
|
|
795
845
|
baseURL: options.baseURL,
|
|
846
|
+
allowInsecureBaseURL: options.allowInsecureBaseURL,
|
|
796
847
|
timeout: options.timeout
|
|
797
848
|
});
|
|
798
849
|
const store = options.store ?? new MemoryRateLimitStore;
|
|
@@ -999,4 +1050,4 @@ export {
|
|
|
999
1050
|
serializeQuery
|
|
1000
1051
|
};
|
|
1001
1052
|
|
|
1002
|
-
//# debugId=
|
|
1053
|
+
//# debugId=67C38AAB1AEA94A764756E2164756E21
|