lunibee 0.2.2 → 0.2.4
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/LICENSE +21 -21
- package/README.md +225 -225
- package/dist/builders/attachment.d.ts +10 -2
- package/dist/builders/commands.d.ts +161 -101
- package/dist/builders/components.d.ts +54 -75
- package/dist/builders/embed.d.ts +68 -35
- package/dist/builders/index.d.ts +1 -1
- package/dist/builders/index.js +108 -133
- package/dist/builders/index.js.map +8 -8
- package/dist/collection/cache.d.ts +13 -6
- package/dist/collection/index.d.ts +90 -17
- package/dist/collection/index.js +442 -266
- package/dist/collection/index.js.map +4 -4
- package/dist/core/index.d.ts +9 -0
- package/dist/core/index.js +791 -436
- package/dist/core/index.js.map +47 -47
- package/dist/core/permissions.d.ts +9 -5
- package/dist/formatters/index.js +9 -5
- package/dist/formatters/index.js.map +3 -3
- package/dist/handlers/index.js +5 -10
- package/dist/handlers/index.js.map +3 -3
- package/dist/index.js +1010 -679
- package/dist/index.js.map +66 -65
- package/dist/managers/base.d.ts +26 -14
- package/dist/managers/emoji.d.ts +7 -1
- package/dist/managers/guild-resources.d.ts +11 -3
- package/dist/managers/guild.d.ts +13 -5
- package/dist/managers/index.d.ts +28 -14
- package/dist/managers/index.js +580 -340
- package/dist/managers/index.js.map +26 -26
- package/dist/managers/member.d.ts +5 -3
- package/dist/managers/message.d.ts +7 -3
- package/dist/managers/role.d.ts +13 -1
- package/dist/rest/error-codes.d.ts +48 -0
- package/dist/rest/errors.d.ts +14 -6
- package/dist/rest/index.d.ts +25 -12
- package/dist/rest/index.js +105 -18
- package/dist/rest/index.js.map +15 -14
- package/dist/rest/redis.d.ts +1 -1
- package/dist/rest/route.d.ts +8 -4
- package/dist/rest/routes.d.ts +102 -46
- package/dist/rest/transport.d.ts +10 -5
- package/dist/rest/webhook.d.ts +9 -5
- package/dist/sharding/bus.d.ts +34 -17
- package/dist/sharding/index.d.ts +34 -17
- package/dist/sharding/index.js +68 -36
- package/dist/sharding/index.js.map +17 -17
- package/dist/structures/base.d.ts +28 -10
- package/dist/structures/channels.d.ts +28 -14
- package/dist/structures/index.d.ts +6 -6
- package/dist/structures/index.js +81 -99
- package/dist/structures/index.js.map +19 -18
- package/dist/structures/interactions.d.ts +98 -50
- package/dist/structures/resources.d.ts +90 -46
- package/dist/types/gateway.d.ts +1 -1
- package/dist/types/index.d.ts +43 -18
- package/dist/types/index.js +20 -22
- package/dist/types/index.js.map +4 -4
- package/dist/utils/index.js.map +2 -2
- package/dist/voice/index.d.ts +12 -4
- package/dist/voice/index.js +17 -20
- package/dist/voice/index.js.map +3 -3
- package/dist/ws/decoder.d.ts +6 -2
- package/dist/ws/index.d.ts +25 -13
- package/dist/ws/index.js +63 -31
- package/dist/ws/index.js.map +14 -14
- package/dist/ws/protocol.d.ts +10 -2
- package/dist/ws/session.d.ts +14 -4
- package/dist/ws/state.d.ts +22 -11
- package/package.json +16 -15
|
@@ -2,6 +2,8 @@ import { REST } from "@lunibee/rest";
|
|
|
2
2
|
import { GuildMember, type ResourceContext } from "@lunibee/structures";
|
|
3
3
|
import { ResourceManager } from "./base.js";
|
|
4
4
|
export interface MemberEditOptions {
|
|
5
|
+
/** Audit-log reason. */
|
|
6
|
+
reason?: string;
|
|
5
7
|
nick?: string | null;
|
|
6
8
|
roles?: string[];
|
|
7
9
|
mute?: boolean;
|
|
@@ -23,9 +25,9 @@ export declare class GuildMemberManager extends ResourceManager<string, GuildMem
|
|
|
23
25
|
kick(userId: string, reason?: string): Promise<void>;
|
|
24
26
|
/** Bans a user from the guild. */
|
|
25
27
|
ban(userId: string, options?: BanOptions): Promise<void>;
|
|
26
|
-
/** Unbans a user from the guild. */
|
|
27
|
-
unban(userId: string): Promise<void>;
|
|
28
|
-
/** Edits a guild member (nickname, roles, timeout, mute, deaf). @param reason
|
|
28
|
+
/** Unbans a user from the guild. @param reason Audit-log reason. */
|
|
29
|
+
unban(userId: string, reason?: string): Promise<void>;
|
|
30
|
+
/** Edits a guild member (nickname, roles, timeout, mute, deaf). Put the audit-log reason in `options.reason`. @param reason Deprecated: use `options.reason`. Removed in 0.3.0. */
|
|
29
31
|
edit(userId: string, options: MemberEditOptions, reason?: string): Promise<GuildMember>;
|
|
30
32
|
/** Adds a role to a member. @param reason Audit-log reason. */
|
|
31
33
|
addRole(userId: string, roleId: string, reason?: string): Promise<void>;
|
|
@@ -7,7 +7,8 @@ export interface MessageCacheOptions {
|
|
|
7
7
|
/** Sliding TTL in ms. Omit for no expiry. */
|
|
8
8
|
ttl?: number;
|
|
9
9
|
}
|
|
10
|
-
import { REST } from "@lunibee/rest";
|
|
10
|
+
import { REST, type RESTFileAttachment } from "@lunibee/rest";
|
|
11
|
+
import type { AllowedMentions } from "@lunibee/types";
|
|
11
12
|
import { Message, type ResourceContext } from "@lunibee/structures";
|
|
12
13
|
/** A file to upload with a message. */
|
|
13
14
|
export interface MessageFile {
|
|
@@ -26,12 +27,15 @@ export type MessageEditOptions = MessageCreateOptions;
|
|
|
26
27
|
* data as UTF-8. `allowedMentions` is the client's default, applied only when
|
|
27
28
|
* the payload has no `allowed_mentions` of its own.
|
|
28
29
|
*/
|
|
29
|
-
export declare function toRequest(options: MessageCreateOptions, allowedMentions?:
|
|
30
|
+
export declare function toRequest(options: MessageCreateOptions, allowedMentions?: AllowedMentions): Omit<MessageCreateOptions, "files"> | {
|
|
31
|
+
body: Omit<MessageCreateOptions, "files">;
|
|
32
|
+
files: RESTFileAttachment[];
|
|
33
|
+
};
|
|
30
34
|
export declare class MessageManager {
|
|
31
35
|
#private;
|
|
32
36
|
/** Cached messages; always empty unless a message cache is configured. */
|
|
33
37
|
readonly cache: Collection<string, Message>;
|
|
34
|
-
constructor(rest: REST, context: ResourceContext, channelId: string, cache?: MessageCacheOptions, allowedMentions?:
|
|
38
|
+
constructor(rest: REST, context: ResourceContext, channelId: string, cache?: MessageCacheOptions, allowedMentions?: AllowedMentions);
|
|
35
39
|
resolve(messageId: string): Promise<Message>;
|
|
36
40
|
send(options: MessageCreateOptions): Promise<Message>;
|
|
37
41
|
fetch(messageId: string): Promise<Message>;
|
package/dist/managers/role.d.ts
CHANGED
|
@@ -29,6 +29,18 @@ export declare class RoleManager extends ResourceManager<string, Role> {
|
|
|
29
29
|
create(options: RoleCreateOptions): Promise<Role>;
|
|
30
30
|
/** Edits an existing role. */
|
|
31
31
|
edit(roleId: string, options: RoleEditOptions): Promise<Role>;
|
|
32
|
-
/** Deletes a role
|
|
32
|
+
/** Deletes a role. @param reason Audit-log reason. */
|
|
33
|
+
remove(roleId: string, reason?: string): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Moves roles in the hierarchy. Discord shifts the other roles around them.
|
|
36
|
+
* @param positions Each role's ID and its new position.
|
|
37
|
+
* @param reason Audit-log reason.
|
|
38
|
+
* @returns Every role in the guild, in their new order.
|
|
39
|
+
*/
|
|
40
|
+
setPositions(positions: readonly {
|
|
41
|
+
id: string;
|
|
42
|
+
position: number;
|
|
43
|
+
}[], reason?: string): Promise<Role[]>;
|
|
44
|
+
/** @deprecated Use {@link RoleManager.remove}, which also takes an audit-log reason. Removed in 0.3.0. */
|
|
33
45
|
deleteRole(roleId: string): Promise<void>;
|
|
34
46
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discord JSON error codes that bots commonly handle, by name, for comparing
|
|
3
|
+
* with `RESTError.code`: `if (error.code === RESTErrorCode.UnknownMessage) …`.
|
|
4
|
+
*
|
|
5
|
+
* Values are from Discord's "JSON Error Codes" table
|
|
6
|
+
* (discord/discord-api-docs, developers/topics/opcodes-and-status-codes.mdx,
|
|
7
|
+
* checked at commit 86f0a46). Any other code is still available as a number
|
|
8
|
+
* on `RESTError.code`.
|
|
9
|
+
*/
|
|
10
|
+
export declare const RESTErrorCode: {
|
|
11
|
+
readonly UnknownAccount: 10001;
|
|
12
|
+
readonly UnknownChannel: 10003;
|
|
13
|
+
readonly UnknownGuild: 10004;
|
|
14
|
+
readonly UnknownInvite: 10006;
|
|
15
|
+
readonly UnknownMember: 10007;
|
|
16
|
+
readonly UnknownMessage: 10008;
|
|
17
|
+
readonly UnknownPermissionOverwrite: 10009;
|
|
18
|
+
readonly UnknownRole: 10011;
|
|
19
|
+
readonly UnknownUser: 10013;
|
|
20
|
+
readonly UnknownEmoji: 10014;
|
|
21
|
+
readonly UnknownWebhook: 10015;
|
|
22
|
+
readonly UnknownBan: 10026;
|
|
23
|
+
readonly UnknownSticker: 10060;
|
|
24
|
+
readonly UnknownInteraction: 10062;
|
|
25
|
+
readonly UnknownScheduledEvent: 10070;
|
|
26
|
+
readonly BotsCannotUseEndpoint: 20001;
|
|
27
|
+
readonly MaxGuilds: 30001;
|
|
28
|
+
readonly MaxPins: 30003;
|
|
29
|
+
readonly MaxRoles: 30005;
|
|
30
|
+
readonly MaxWebhooks: 30007;
|
|
31
|
+
readonly MaxEmojis: 30008;
|
|
32
|
+
readonly MaxReactions: 30010;
|
|
33
|
+
readonly MaxChannels: 30013;
|
|
34
|
+
readonly InteractionAlreadyAcknowledged: 40060;
|
|
35
|
+
readonly MissingAccess: 50001;
|
|
36
|
+
readonly CannotExecuteInDM: 50003;
|
|
37
|
+
readonly CannotEditOthersMessage: 50005;
|
|
38
|
+
readonly CannotSendEmptyMessage: 50006;
|
|
39
|
+
readonly CannotSendMessagesToUser: 50007;
|
|
40
|
+
readonly MissingPermissions: 50013;
|
|
41
|
+
readonly InvalidToken: 50014;
|
|
42
|
+
readonly MessageTooOldToBulkDelete: 50034;
|
|
43
|
+
readonly InvalidFormBody: 50035;
|
|
44
|
+
readonly ThreadArchived: 50083;
|
|
45
|
+
readonly CannotReplyWithoutReadHistory: 160002;
|
|
46
|
+
};
|
|
47
|
+
/** One {@link RESTErrorCode} value, usable as a type. */
|
|
48
|
+
export type RESTErrorCode = (typeof RESTErrorCode)[keyof typeof RESTErrorCode];
|
package/dist/rest/errors.d.ts
CHANGED
|
@@ -28,12 +28,20 @@ export type RESTErrorKind =
|
|
|
28
28
|
export declare function redactPath(path: string): string;
|
|
29
29
|
/** Error thrown when Discord rejects a REST request. */
|
|
30
30
|
export declare class RESTError extends Error {
|
|
31
|
-
/** Failure category. */
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
|
|
31
|
+
/** Failure category. */
|
|
32
|
+
readonly kind: RESTErrorKind;
|
|
33
|
+
/** HTTP status returned by Discord. */
|
|
34
|
+
readonly status: number;
|
|
35
|
+
/** Discord API error code, when provided. */
|
|
36
|
+
readonly code?: number;
|
|
37
|
+
/** Raw Discord validation/error payload. */
|
|
38
|
+
readonly errors?: unknown;
|
|
39
|
+
/** HTTP method used for the failed request. */
|
|
40
|
+
readonly method?: string;
|
|
41
|
+
/** API path used for the failed request. */
|
|
42
|
+
readonly path?: string;
|
|
43
|
+
/** What to check next, for errors with a common cause (missing access or permissions). */
|
|
44
|
+
readonly hint?: string;
|
|
37
45
|
/** Creates a REST error with request context. @param message Error message. @param status HTTP status. @param code Discord error code. @param errors Raw error payload. @param options Request context and cause. */
|
|
38
46
|
constructor(message: string, status: number, code?: number, errors?: unknown, options?: {
|
|
39
47
|
method?: string;
|
package/dist/rest/index.d.ts
CHANGED
|
@@ -16,11 +16,16 @@ export interface RESTFileAttachment {
|
|
|
16
16
|
* `reason`, `auth`) additively without changing that positional default.
|
|
17
17
|
*/
|
|
18
18
|
export interface RESTRequestOptions {
|
|
19
|
-
/** Abort signal used to cancel the request and any queued wait. */
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
|
|
23
|
-
/**
|
|
19
|
+
/** Abort signal used to cancel the request and any queued wait. */
|
|
20
|
+
signal?: AbortSignal;
|
|
21
|
+
/** Query-string appended to the path (`URLSearchParams`, a record, or a raw string). */
|
|
22
|
+
query?: RESTQuery;
|
|
23
|
+
/** Extra request headers merged in (library headers such as `Authorization` win). */
|
|
24
|
+
headers?: Record<string, string>;
|
|
25
|
+
/** Audit-log reason, sent as the `X-Audit-Log-Reason` header. */
|
|
26
|
+
reason?: string;
|
|
27
|
+
/** Set `false` to omit the `Authorization` header for this request. Defaults to `true`. */
|
|
28
|
+
auth?: boolean;
|
|
24
29
|
}
|
|
25
30
|
/**
|
|
26
31
|
* Discord.js-familiar request payload. Superset of {@link RESTRequestOptions} that also
|
|
@@ -28,8 +33,10 @@ export interface RESTRequestOptions {
|
|
|
28
33
|
* additive `method(path, { body })` overloads without breaking the positional signature.
|
|
29
34
|
*/
|
|
30
35
|
export interface RequestData extends RESTRequestOptions {
|
|
31
|
-
/** Request body. Encoded as JSON unless `files` are present (then multipart). */
|
|
32
|
-
|
|
36
|
+
/** Request body. Encoded as JSON unless `files` are present (then multipart). */
|
|
37
|
+
body?: unknown;
|
|
38
|
+
/** File attachments; presence upgrades the request to `multipart/form-data`. */
|
|
39
|
+
files?: RESTFileAttachment[];
|
|
33
40
|
}
|
|
34
41
|
/** Context passed to `RESTHooks.onRequest`. */
|
|
35
42
|
export interface RESTRequestContext {
|
|
@@ -81,9 +88,12 @@ export interface RESTHooks {
|
|
|
81
88
|
}
|
|
82
89
|
/** Configures which REST failures may be retried. */
|
|
83
90
|
export interface RetryPolicy {
|
|
84
|
-
/** Maximum retry attempts. */
|
|
85
|
-
|
|
86
|
-
/**
|
|
91
|
+
/** Maximum retry attempts. */
|
|
92
|
+
maxRetries: number;
|
|
93
|
+
/** Determines whether a request may be retried. @param method HTTP method. @param status HTTP status, or zero for transport errors. @returns True when retrying is safe under the policy. */
|
|
94
|
+
shouldRetry(method: string, status: number): boolean;
|
|
95
|
+
/** Calculates delay before the next attempt. @param attempt Zero-based retry number. @param retryAfter Server-provided delay, when available. @returns Delay in milliseconds. */
|
|
96
|
+
getDelay(attempt: number, retryAfter?: number): number;
|
|
87
97
|
}
|
|
88
98
|
/** Creates the default conservative REST retry policy. @param maxRetries Maximum retries. @returns Retry policy that retries rate limits and idempotent transient failures. @throws {TypeError} If maxRetries is negative or not finite. */
|
|
89
99
|
export declare function createRetryPolicy(maxRetries?: number): RetryPolicy;
|
|
@@ -126,7 +136,8 @@ export declare class REST {
|
|
|
126
136
|
* @throws {RESTError} If Discord or transport rejects the request.
|
|
127
137
|
*/
|
|
128
138
|
request<T>(method: string, path: string, body?: unknown, options?: RequestData): Promise<T>;
|
|
129
|
-
/** Sends a GET request. @param path API path. @param options Request options (`query`, `headers`, `signal`, …). @returns Decoded response. @throws {RESTError} When the request fails. */
|
|
139
|
+
/** Sends a GET request. @param path API path. @param options Request options (`query`, `headers`, `signal`, …). @returns Decoded response. @throws {RESTError} When the request fails. */
|
|
140
|
+
get<T>(path: string, options?: RequestData): Promise<T>;
|
|
130
141
|
/** Sends a POST request. Accepts a raw body (`post(path, body)`) or a Discord.js-familiar `post(path, { body })`. @param path API path. @param body Optional JSON body, or a `RequestData` wrapper. @param options Request options. @returns Decoded response. @throws {RESTError} When the request fails. */
|
|
131
142
|
post<T>(path: string, options: RequestData): Promise<T>;
|
|
132
143
|
post<T>(path: string, body?: unknown, options?: RequestData): Promise<T>;
|
|
@@ -136,7 +147,8 @@ export declare class REST {
|
|
|
136
147
|
/** Sends a PUT request. Accepts a raw body (`put(path, body)`) or a Discord.js-familiar `put(path, { body })`. @param path API path. @param body Optional JSON body, or a `RequestData` wrapper. @param options Request options. @returns Decoded response. @throws {RESTError} When the request fails. */
|
|
137
148
|
put<T>(path: string, options: RequestData): Promise<T>;
|
|
138
149
|
put<T>(path: string, body?: unknown, options?: RequestData): Promise<T>;
|
|
139
|
-
/** Sends a DELETE request. @param path API path. @param options Request options (`reason`, `headers`, `signal`, …). @returns Decoded response. @throws {RESTError} When the request fails. */
|
|
150
|
+
/** Sends a DELETE request. @param path API path. @param options Request options (`reason`, `headers`, `signal`, …). @returns Decoded response. @throws {RESTError} When the request fails. */
|
|
151
|
+
delete<T>(path: string, options?: RequestData): Promise<T>;
|
|
140
152
|
/**
|
|
141
153
|
* Sends a multipart/form-data POST request for file uploads.
|
|
142
154
|
* Attaches a JSON payload as `payload_json` and files as additional fields.
|
|
@@ -161,6 +173,7 @@ export declare class REST {
|
|
|
161
173
|
}
|
|
162
174
|
export { Routes } from "./routes.js";
|
|
163
175
|
export { RESTError, abortError, redactPath, type RESTErrorKind, } from "./errors.js";
|
|
176
|
+
export { RESTErrorCode } from "./error-codes.js";
|
|
164
177
|
export { createRouteKey, normalizeRoutePath, majorParameter, scopeBucket, serializeQuery, type RouteKey, type RESTQuery, } from "./route.js";
|
|
165
178
|
export { RequestScheduler } from "./scheduler.js";
|
|
166
179
|
export { RateLimiter } from "./limiter.js";
|
package/dist/rest/index.js
CHANGED
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
// packages/rest/package.json
|
|
3
3
|
var package_default = {
|
|
4
4
|
name: "@lunibee/rest",
|
|
5
|
-
version: "0.2.
|
|
5
|
+
version: "0.2.4",
|
|
6
6
|
type: "module",
|
|
7
7
|
module: "./src/index.ts",
|
|
8
8
|
types: "./src/index.ts",
|
|
9
9
|
exports: {
|
|
10
10
|
".": "./src/index.ts"
|
|
11
|
+
},
|
|
12
|
+
dependencies: {
|
|
13
|
+
"@lunibee/types": "workspace:*"
|
|
11
14
|
}
|
|
12
15
|
};
|
|
13
16
|
|
|
@@ -80,8 +83,12 @@ function kindFromStatus(status) {
|
|
|
80
83
|
return "client";
|
|
81
84
|
}
|
|
82
85
|
function redactPath(path) {
|
|
83
|
-
return path.replace(/^(\/webhooks\/[^/?]+\/)[^/?]
|
|
86
|
+
return path.replace(/^(\/webhooks\/[^/?]+\/)[^/?]+/i, "$1:token").replace(/^(\/interactions\/[^/?]+\/)[^/?]+/i, "$1:token");
|
|
84
87
|
}
|
|
88
|
+
var HINTS = {
|
|
89
|
+
50001: "The bot cannot see this resource: check that it is in the guild and has View Channel there.",
|
|
90
|
+
50013: "The bot lacks a permission for this action, or the target role or member is at or above the bot's highest role."
|
|
91
|
+
};
|
|
85
92
|
|
|
86
93
|
class RESTError extends Error {
|
|
87
94
|
kind;
|
|
@@ -90,12 +97,14 @@ class RESTError extends Error {
|
|
|
90
97
|
errors;
|
|
91
98
|
method;
|
|
92
99
|
path;
|
|
100
|
+
hint;
|
|
93
101
|
constructor(message, status, code, errors, options = {}) {
|
|
94
102
|
super(message, options.cause === undefined ? undefined : { cause: options.cause });
|
|
95
103
|
this.name = "RESTError";
|
|
96
104
|
this.status = status;
|
|
97
105
|
this.kind = options.kind ?? kindFromStatus(status);
|
|
98
106
|
this.code = code;
|
|
107
|
+
this.hint = code === undefined ? undefined : HINTS[code];
|
|
99
108
|
this.errors = errors;
|
|
100
109
|
this.method = options.method;
|
|
101
110
|
this.path = options.path === undefined ? undefined : redactPath(options.path);
|
|
@@ -133,19 +142,23 @@ async function abortable(promise, signal, path) {
|
|
|
133
142
|
}
|
|
134
143
|
|
|
135
144
|
// packages/rest/src/route.ts
|
|
145
|
+
import { createHash } from "crypto";
|
|
136
146
|
function normalizeRoutePath(path) {
|
|
137
147
|
const queryIndex = path.indexOf("?");
|
|
138
148
|
const routePath = queryIndex === -1 ? path : path.slice(0, queryIndex);
|
|
139
|
-
return routePath.replace(/\/\d+(?=\/|$)/g, "/:id");
|
|
149
|
+
return redactPath(routePath).replace(/\/\d+(?=\/|$)/g, "/:id");
|
|
140
150
|
}
|
|
141
151
|
function majorParameter(path) {
|
|
142
|
-
const match = /^\/(channels|guilds|webhooks)\/(\d+)(?:\/([^/?]+))
|
|
152
|
+
const match = /^\/(channels|guilds|webhooks)\/(\d+)(?:\/([^/?]+))?/i.exec(path);
|
|
143
153
|
if (!match)
|
|
144
154
|
return "@none";
|
|
145
|
-
if (match[1] === "webhooks" && match[3] !== undefined)
|
|
146
|
-
return `${match[2]}:${match[3]}`;
|
|
155
|
+
if (match[1].toLowerCase() === "webhooks" && match[3] !== undefined)
|
|
156
|
+
return `${match[2]}:${tokenDigest(match[3])}`;
|
|
147
157
|
return match[2];
|
|
148
158
|
}
|
|
159
|
+
function tokenDigest(token) {
|
|
160
|
+
return createHash("sha256").update(token).digest("hex").slice(0, 16);
|
|
161
|
+
}
|
|
149
162
|
function scopeBucket(hashOrRoute, major) {
|
|
150
163
|
return `${hashOrRoute}|${major}`;
|
|
151
164
|
}
|
|
@@ -387,6 +400,9 @@ var Routes = {
|
|
|
387
400
|
user: () => "/users/@me",
|
|
388
401
|
userById: (userId) => `/users/${snowflake(userId, "User ID")}`,
|
|
389
402
|
guild: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}`,
|
|
403
|
+
currentUserGuild: (guildId) => `/users/@me/guilds/${snowflake(guildId, "Guild ID")}`,
|
|
404
|
+
sticker: (stickerId) => `/stickers/${snowflake(stickerId, "Sticker ID")}`,
|
|
405
|
+
messageReactionUser: (channelId, messageId, emoji, userId) => `${Routes.messageReactions(channelId, messageId, emoji)}/${snowflake(userId, "User ID")}`,
|
|
390
406
|
guildPreview: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/preview`,
|
|
391
407
|
guildActiveThreads: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/threads/active`,
|
|
392
408
|
guildWebhooks: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/webhooks`,
|
|
@@ -404,6 +420,8 @@ var Routes = {
|
|
|
404
420
|
crosspostMessage: (channelId, messageId) => `${Routes.message(channelId, messageId)}/crosspost`,
|
|
405
421
|
messageReactions: (channelId, messageId, emoji) => `${Routes.message(channelId, messageId)}/reactions/${encodeURIComponent(emoji)}`,
|
|
406
422
|
messageReactionsAll: (channelId, messageId) => `${Routes.message(channelId, messageId)}/reactions`,
|
|
423
|
+
channelMessagesPins: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/messages/pins`,
|
|
424
|
+
channelMessagesPin: (channelId, messageId) => `/channels/${snowflake(channelId, "Channel ID")}/messages/pins/${snowflake(messageId, "Message ID")}`,
|
|
407
425
|
channelPins: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/pins`,
|
|
408
426
|
channelPin: (channelId, messageId) => `/channels/${snowflake(channelId, "Channel ID")}/pins/${snowflake(messageId, "Message ID")}`,
|
|
409
427
|
messageThread: (channelId, messageId) => `${Routes.message(channelId, messageId)}/threads`,
|
|
@@ -462,6 +480,44 @@ function snowflake(value, field) {
|
|
|
462
480
|
throw new TypeError(`${field} must be a valid Discord snowflake.`);
|
|
463
481
|
return value;
|
|
464
482
|
}
|
|
483
|
+
// packages/rest/src/error-codes.ts
|
|
484
|
+
var RESTErrorCode = {
|
|
485
|
+
UnknownAccount: 10001,
|
|
486
|
+
UnknownChannel: 10003,
|
|
487
|
+
UnknownGuild: 10004,
|
|
488
|
+
UnknownInvite: 10006,
|
|
489
|
+
UnknownMember: 10007,
|
|
490
|
+
UnknownMessage: 10008,
|
|
491
|
+
UnknownPermissionOverwrite: 10009,
|
|
492
|
+
UnknownRole: 10011,
|
|
493
|
+
UnknownUser: 10013,
|
|
494
|
+
UnknownEmoji: 10014,
|
|
495
|
+
UnknownWebhook: 10015,
|
|
496
|
+
UnknownBan: 10026,
|
|
497
|
+
UnknownSticker: 10060,
|
|
498
|
+
UnknownInteraction: 10062,
|
|
499
|
+
UnknownScheduledEvent: 10070,
|
|
500
|
+
BotsCannotUseEndpoint: 20001,
|
|
501
|
+
MaxGuilds: 30001,
|
|
502
|
+
MaxPins: 30003,
|
|
503
|
+
MaxRoles: 30005,
|
|
504
|
+
MaxWebhooks: 30007,
|
|
505
|
+
MaxEmojis: 30008,
|
|
506
|
+
MaxReactions: 30010,
|
|
507
|
+
MaxChannels: 30013,
|
|
508
|
+
InteractionAlreadyAcknowledged: 40060,
|
|
509
|
+
MissingAccess: 50001,
|
|
510
|
+
CannotExecuteInDM: 50003,
|
|
511
|
+
CannotEditOthersMessage: 50005,
|
|
512
|
+
CannotSendEmptyMessage: 50006,
|
|
513
|
+
CannotSendMessagesToUser: 50007,
|
|
514
|
+
MissingPermissions: 50013,
|
|
515
|
+
InvalidToken: 50014,
|
|
516
|
+
MessageTooOldToBulkDelete: 50034,
|
|
517
|
+
InvalidFormBody: 50035,
|
|
518
|
+
ThreadArchived: 50083,
|
|
519
|
+
CannotReplyWithoutReadHistory: 160002
|
|
520
|
+
};
|
|
465
521
|
// packages/rest/src/redis.ts
|
|
466
522
|
var RESERVE_SCRIPT = `
|
|
467
523
|
local raw = redis.call('GET', KEYS[1])
|
|
@@ -608,7 +664,7 @@ class WebhookClient {
|
|
|
608
664
|
#rest;
|
|
609
665
|
constructor(options, restOptions) {
|
|
610
666
|
if (options.url) {
|
|
611
|
-
const match = options.url.match(
|
|
667
|
+
const match = options.url.match(/^https:\/\/(?:(?:ptb|canary)\.)?discord(?:app)?\.com\/api(?:\/v\d+)?\/webhooks\/(\d{1,20})\/([A-Za-z0-9_-]+)\/?(?:[?#].*)?$/);
|
|
612
668
|
if (!match)
|
|
613
669
|
throw new Error("Invalid Discord webhook URL format.");
|
|
614
670
|
this.id = match[1];
|
|
@@ -623,13 +679,20 @@ class WebhookClient {
|
|
|
623
679
|
}
|
|
624
680
|
async send(options) {
|
|
625
681
|
const payload = typeof options === "string" ? { content: options } : options;
|
|
626
|
-
const { thread_id, ...body } = payload;
|
|
627
|
-
const
|
|
682
|
+
const { thread_id, files, ...body } = payload;
|
|
683
|
+
const params = new URLSearchParams({ wait: "true" });
|
|
684
|
+
if (thread_id)
|
|
685
|
+
params.set("thread_id", String(thread_id));
|
|
686
|
+
const query = `?${params}`;
|
|
628
687
|
const formattedEmbeds = body.embeds?.map((e) => ("toJSON" in e) ? e.toJSON() : e);
|
|
629
|
-
|
|
688
|
+
const formattedComponents = body.components?.map((c) => ("toJSON" in c) ? c.toJSON() : c);
|
|
689
|
+
const path = `${Routes.webhook(this.id, this.token)}${query}`;
|
|
690
|
+
const json = {
|
|
630
691
|
...body,
|
|
631
|
-
embeds: formattedEmbeds
|
|
632
|
-
|
|
692
|
+
embeds: formattedEmbeds,
|
|
693
|
+
components: formattedComponents
|
|
694
|
+
};
|
|
695
|
+
return files?.length ? this.#rest.postWithFiles(path, json, files) : this.#rest.post(path, json);
|
|
633
696
|
}
|
|
634
697
|
async editMessage(messageId, options) {
|
|
635
698
|
const payload = typeof options === "string" ? { content: options } : options;
|
|
@@ -643,7 +706,23 @@ class WebhookClient {
|
|
|
643
706
|
// packages/rest/src/index.ts
|
|
644
707
|
var LIBRARY_VERSION = package_default.version;
|
|
645
708
|
var LIBRARY_URL = "https://github.com/Ekretos/lunibee";
|
|
646
|
-
var USER_AGENT = `DiscordBot (${LIBRARY_URL}, ${
|
|
709
|
+
var USER_AGENT = `DiscordBot (${LIBRARY_URL}, ${LIBRARY_VERSION})`;
|
|
710
|
+
function assertSafePath(path) {
|
|
711
|
+
const end = path.search(/[?#]/);
|
|
712
|
+
const pathname = end === -1 ? path : path.slice(0, end);
|
|
713
|
+
if (pathname.includes("\\"))
|
|
714
|
+
throw new TypeError("REST paths must not contain backslashes.");
|
|
715
|
+
for (const segment of pathname.split("/")) {
|
|
716
|
+
let decoded;
|
|
717
|
+
try {
|
|
718
|
+
decoded = decodeURIComponent(segment);
|
|
719
|
+
} catch {
|
|
720
|
+
throw new TypeError("REST path has malformed percent-encoding.");
|
|
721
|
+
}
|
|
722
|
+
if (decoded === "." || decoded === "..")
|
|
723
|
+
throw new TypeError("REST paths must not contain '.' or '..' segments.");
|
|
724
|
+
}
|
|
725
|
+
}
|
|
647
726
|
var REQUEST_DATA_KEYS = new Set([
|
|
648
727
|
"body",
|
|
649
728
|
"files",
|
|
@@ -728,6 +807,7 @@ class REST {
|
|
|
728
807
|
throw new TypeError("REST method is required.");
|
|
729
808
|
if (!path.startsWith("/"))
|
|
730
809
|
throw new TypeError("REST paths must start with '/'.");
|
|
810
|
+
assertSafePath(path);
|
|
731
811
|
const route = createRouteKey(method, path);
|
|
732
812
|
const files = options.files;
|
|
733
813
|
if (files && files.length > 0 && !(body instanceof FormData))
|
|
@@ -815,13 +895,19 @@ class REST {
|
|
|
815
895
|
#headers(body, options) {
|
|
816
896
|
const isFormData = typeof FormData !== "undefined" && body instanceof FormData;
|
|
817
897
|
const headers = { ...options.headers };
|
|
898
|
+
const set = (name, value) => {
|
|
899
|
+
for (const key of Object.keys(headers))
|
|
900
|
+
if (key.toLowerCase() === name.toLowerCase())
|
|
901
|
+
delete headers[key];
|
|
902
|
+
headers[name] = value;
|
|
903
|
+
};
|
|
818
904
|
if (options.auth !== false && this.#token)
|
|
819
|
-
|
|
820
|
-
|
|
905
|
+
set("Authorization", `Bot ${this.#token}`);
|
|
906
|
+
set("User-Agent", USER_AGENT);
|
|
821
907
|
if (options.reason !== undefined)
|
|
822
|
-
|
|
908
|
+
set("X-Audit-Log-Reason", encodeURIComponent(options.reason));
|
|
823
909
|
if (!isFormData)
|
|
824
|
-
|
|
910
|
+
set("Content-Type", "application/json");
|
|
825
911
|
return headers;
|
|
826
912
|
}
|
|
827
913
|
#encodeBody(body) {
|
|
@@ -882,6 +968,7 @@ export {
|
|
|
882
968
|
MemoryRateLimitStore,
|
|
883
969
|
REST,
|
|
884
970
|
RESTError,
|
|
971
|
+
RESTErrorCode,
|
|
885
972
|
RateLimiter,
|
|
886
973
|
RedisRateLimitStore,
|
|
887
974
|
RequestScheduler,
|
|
@@ -899,4 +986,4 @@ export {
|
|
|
899
986
|
serializeQuery
|
|
900
987
|
};
|
|
901
988
|
|
|
902
|
-
//# debugId=
|
|
989
|
+
//# debugId=51D994350F46554C64756E2164756E21
|