lunibee 0.2.3 → 0.3.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/README.md +3 -3
- package/dist/builders/attachment.d.ts +8 -4
- package/dist/builders/commands.d.ts +122 -149
- package/dist/builders/components.d.ts +10 -150
- package/dist/builders/embed.d.ts +66 -37
- package/dist/builders/index.d.ts +0 -4
- package/dist/builders/index.js +112 -221
- package/dist/builders/index.js.map +10 -9
- package/dist/collection/cache.d.ts +15 -6
- package/dist/collection/index.d.ts +92 -17
- package/dist/collection/index.js +471 -279
- package/dist/collection/index.js.map +4 -4
- package/dist/core/api.d.ts +130 -0
- package/dist/core/channel-create.d.ts +72 -0
- package/dist/core/commands.d.ts +232 -0
- package/dist/core/events.d.ts +24 -7
- package/dist/core/handles.d.ts +157 -0
- package/dist/core/index.d.ts +68 -4
- package/dist/core/index.js +2639 -493
- package/dist/core/index.js.map +47 -37
- package/dist/core/permissions.d.ts +7 -7
- 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.d.ts +2 -2
- package/dist/index.js +9527 -7809
- package/dist/index.js.map +63 -53
- package/dist/managers/advanced.d.ts +29 -1
- package/dist/managers/base.d.ts +22 -14
- package/dist/managers/emoji.d.ts +0 -2
- package/dist/managers/guild-resources.d.ts +13 -5
- package/dist/managers/guild.d.ts +40 -4
- package/dist/managers/index.d.ts +21 -13
- package/dist/managers/index.js +969 -386
- package/dist/managers/index.js.map +30 -25
- package/dist/managers/member.d.ts +9 -2
- package/dist/managers/message.d.ts +10 -15
- package/dist/managers/role.d.ts +18 -10
- package/dist/managers/thread.d.ts +68 -0
- package/dist/managers/user.d.ts +18 -0
- package/dist/rest/errors.d.ts +14 -7
- package/dist/rest/index.d.ts +24 -12
- package/dist/rest/index.js +70 -20
- package/dist/rest/index.js.map +9 -9
- package/dist/rest/redis.d.ts +1 -1
- package/dist/rest/route.d.ts +8 -4
- package/dist/rest/routes.d.ts +122 -48
- package/dist/rest/transport.d.ts +10 -5
- package/dist/rest/webhook.d.ts +9 -5
- package/dist/sharding/bus.d.ts +47 -19
- package/dist/sharding/cluster.d.ts +11 -0
- package/dist/sharding/gateway-bot.d.ts +18 -0
- package/dist/sharding/index.d.ts +64 -25
- package/dist/sharding/index.js +439 -124
- package/dist/sharding/index.js.map +19 -14
- package/dist/sharding/supervisor.d.ts +32 -0
- package/dist/sharding/transport.d.ts +45 -0
- package/dist/structures/audit-log.d.ts +99 -2
- package/dist/structures/base.d.ts +40 -23
- package/dist/structures/channels.d.ts +45 -14
- package/dist/structures/index.d.ts +8 -12
- package/dist/structures/index.js +280 -132
- package/dist/structures/index.js.map +21 -15
- package/dist/structures/interactions.d.ts +91 -63
- package/dist/structures/resources.d.ts +99 -52
- package/dist/structures/sticker.d.ts +33 -0
- package/dist/types/channel-kind.d.ts +26 -0
- package/dist/types/gateway.d.ts +24 -12
- package/dist/types/index.d.ts +115 -113
- package/dist/types/index.js +53 -48
- package/dist/types/index.js.map +6 -5
- package/dist/voice/index.d.ts +12 -4
- package/dist/voice/index.js +14 -18
- package/dist/voice/index.js.map +3 -3
- package/dist/ws/decoder.d.ts +6 -2
- package/dist/ws/dispatcher.d.ts +19 -0
- package/dist/ws/index.d.ts +61 -15
- package/dist/ws/index.js +194 -77
- package/dist/ws/index.js.map +13 -11
- package/dist/ws/protocol.d.ts +10 -2
- package/dist/ws/reconnect.d.ts +10 -0
- package/dist/ws/send-budget.d.ts +6 -2
- package/dist/ws/session.d.ts +14 -4
- package/dist/ws/state.d.ts +22 -11
- package/package.json +20 -16
|
@@ -21,14 +21,21 @@ export declare class GuildMemberManager extends ResourceManager<string, GuildMem
|
|
|
21
21
|
readonly guildId: string;
|
|
22
22
|
/** @param context Gives fetched members their actions (`member.kick()`...). */
|
|
23
23
|
constructor(guildId: string, rest: REST, context?: () => ResourceContext | undefined);
|
|
24
|
+
/** Finds members whose username or nickname starts with `query` (up to `limit`, 1-1000, default 1). */
|
|
25
|
+
search(query: string, limit?: number): Promise<GuildMember[]>;
|
|
26
|
+
/** Changes the bot's own nickname in this guild (`null` clears it). */
|
|
27
|
+
editMe(options: {
|
|
28
|
+
nick?: string | null;
|
|
29
|
+
reason?: string;
|
|
30
|
+
}): Promise<GuildMember>;
|
|
24
31
|
/** Kicks a member from the guild. @param reason Audit-log reason. */
|
|
25
32
|
kick(userId: string, reason?: string): Promise<void>;
|
|
26
33
|
/** Bans a user from the guild. */
|
|
27
34
|
ban(userId: string, options?: BanOptions): Promise<void>;
|
|
28
35
|
/** Unbans a user from the guild. @param reason Audit-log reason. */
|
|
29
36
|
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
|
|
31
|
-
edit(userId: string, options: MemberEditOptions
|
|
37
|
+
/** Edits a guild member (nickname, roles, timeout, mute, deaf). Put the audit-log reason in `options.reason`.*/
|
|
38
|
+
edit(userId: string, options: MemberEditOptions): Promise<GuildMember>;
|
|
32
39
|
/** Adds a role to a member. @param reason Audit-log reason. */
|
|
33
40
|
addRole(userId: string, roleId: string, reason?: string): Promise<void>;
|
|
34
41
|
/** Removes a role from a member. @param reason Audit-log reason. */
|
|
@@ -7,31 +7,26 @@ 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, MessageCreateOptions, MessageEditOptions, MessageFile } from "@lunibee/types";
|
|
11
12
|
import { Message, type ResourceContext } from "@lunibee/structures";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
data: Blob | Uint8Array | ArrayBuffer | string;
|
|
16
|
-
contentType?: string;
|
|
17
|
-
}
|
|
18
|
-
export type MessageCreateOptions = Record<string, unknown> & {
|
|
19
|
-
content?: string;
|
|
20
|
-
/** Files to upload; the message is sent as multipart. */
|
|
21
|
-
files?: MessageFile[];
|
|
22
|
-
};
|
|
23
|
-
export type MessageEditOptions = MessageCreateOptions;
|
|
13
|
+
export type { MessageCreateOptions, MessageEditOptions, MessageFile };
|
|
14
|
+
/** Turns message files into REST uploads, encoding string data as UTF-8. */
|
|
15
|
+
export declare function toAttachments(files: readonly MessageFile[]): RESTFileAttachment[];
|
|
24
16
|
/**
|
|
25
17
|
* Splits `files` out of a message payload into a REST upload, encoding string
|
|
26
18
|
* data as UTF-8. `allowedMentions` is the client's default, applied only when
|
|
27
19
|
* the payload has no `allowed_mentions` of its own.
|
|
28
20
|
*/
|
|
29
|
-
export declare function toRequest(options: MessageCreateOptions, allowedMentions?:
|
|
21
|
+
export declare function toRequest(options: MessageCreateOptions, allowedMentions?: AllowedMentions): Omit<MessageCreateOptions, "files"> | {
|
|
22
|
+
body: Omit<MessageCreateOptions, "files">;
|
|
23
|
+
files: RESTFileAttachment[];
|
|
24
|
+
};
|
|
30
25
|
export declare class MessageManager {
|
|
31
26
|
#private;
|
|
32
27
|
/** Cached messages; always empty unless a message cache is configured. */
|
|
33
28
|
readonly cache: Collection<string, Message>;
|
|
34
|
-
constructor(rest: REST, context: ResourceContext, channelId: string, cache?: MessageCacheOptions, allowedMentions?:
|
|
29
|
+
constructor(rest: REST, context: ResourceContext, channelId: string, cache?: MessageCacheOptions, allowedMentions?: AllowedMentions);
|
|
35
30
|
resolve(messageId: string): Promise<Message>;
|
|
36
31
|
send(options: MessageCreateOptions): Promise<Message>;
|
|
37
32
|
fetch(messageId: string): Promise<Message>;
|
package/dist/managers/role.d.ts
CHANGED
|
@@ -1,22 +1,31 @@
|
|
|
1
1
|
import { REST } from "@lunibee/rest";
|
|
2
2
|
import { Role } from "@lunibee/structures";
|
|
3
3
|
import { ResourceManager } from "./base.js";
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
/** Role fields shared by create and edit. */
|
|
5
|
+
interface RoleStyleOptions {
|
|
6
6
|
permissions?: bigint | number | string;
|
|
7
|
+
/** A solid colour as a 24-bit integer. Use `colors` for a gradient. */
|
|
7
8
|
color?: number;
|
|
9
|
+
/** Primary, secondary and tertiary colours: two make a gradient, three the holographic style. */
|
|
10
|
+
colors?: {
|
|
11
|
+
primary: number;
|
|
12
|
+
secondary?: number | null;
|
|
13
|
+
tertiary?: number | null;
|
|
14
|
+
};
|
|
8
15
|
hoist?: boolean;
|
|
9
16
|
mentionable?: boolean;
|
|
17
|
+
/** The role's icon as a data URI (needs the guild's role-icons boost level), or `null` to remove it. */
|
|
18
|
+
icon?: string | null;
|
|
19
|
+
/** A unicode emoji as the role icon, or `null` to remove it. */
|
|
20
|
+
unicodeEmoji?: string | null;
|
|
10
21
|
reason?: string;
|
|
11
22
|
}
|
|
12
|
-
export interface
|
|
23
|
+
export interface RoleCreateOptions extends RoleStyleOptions {
|
|
24
|
+
name: string;
|
|
25
|
+
}
|
|
26
|
+
export interface RoleEditOptions extends RoleStyleOptions {
|
|
13
27
|
name?: string;
|
|
14
|
-
permissions?: bigint | number | string;
|
|
15
|
-
color?: number;
|
|
16
|
-
hoist?: boolean;
|
|
17
|
-
mentionable?: boolean;
|
|
18
28
|
position?: number;
|
|
19
|
-
reason?: string;
|
|
20
29
|
}
|
|
21
30
|
/** Manages Discord guild roles. */
|
|
22
31
|
export declare class RoleManager extends ResourceManager<string, Role> {
|
|
@@ -41,6 +50,5 @@ export declare class RoleManager extends ResourceManager<string, Role> {
|
|
|
41
50
|
id: string;
|
|
42
51
|
position: number;
|
|
43
52
|
}[], reason?: string): Promise<Role[]>;
|
|
44
|
-
/** @deprecated Use {@link RoleManager.remove}, which also takes an audit-log reason. Removed in 0.3.0. */
|
|
45
|
-
deleteRole(roleId: string): Promise<void>;
|
|
46
53
|
}
|
|
54
|
+
export {};
|
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
import { REST } from "@lunibee/rest";
|
|
2
2
|
import { Channel, type ResourceContext } from "@lunibee/structures";
|
|
3
|
+
import type { APIGuildMember, APIThreadMember, MessageCreateOptions } from "@lunibee/types";
|
|
4
|
+
/** Options shared by every way of starting a thread. */
|
|
5
|
+
export interface ThreadCreateOptions {
|
|
6
|
+
name: string;
|
|
7
|
+
/** Minutes of inactivity before it archives: 60, 1440, 4320 or 10080. */
|
|
8
|
+
autoArchiveDuration?: 60 | 1440 | 4320 | 10080;
|
|
9
|
+
/** Seconds a member must wait between messages (0-21600). */
|
|
10
|
+
rateLimitPerUser?: number;
|
|
11
|
+
reason?: string;
|
|
12
|
+
}
|
|
13
|
+
/** What a thread member lookup may ask Discord to include. */
|
|
14
|
+
export interface ThreadMemberQuery {
|
|
15
|
+
/** Include each member's guild member object. */
|
|
16
|
+
withMember?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/** Which archived threads to list. */
|
|
19
|
+
export type ArchivedThreadScope = "public" | "private" | "joined-private";
|
|
20
|
+
/** One page of archived threads. */
|
|
21
|
+
export interface ArchivedThreads {
|
|
22
|
+
threads: Channel[];
|
|
23
|
+
members: APIThreadMember[];
|
|
24
|
+
hasMore: boolean;
|
|
25
|
+
}
|
|
3
26
|
/** Manages thread resources created from a parent channel. */
|
|
4
27
|
export declare class ThreadManager {
|
|
5
28
|
#private;
|
|
@@ -11,4 +34,49 @@ export declare class ThreadManager {
|
|
|
11
34
|
autoArchiveDuration?: 60 | 1440 | 4320 | 10080;
|
|
12
35
|
rateLimitPerUser?: number;
|
|
13
36
|
}): Promise<Channel>;
|
|
37
|
+
/**
|
|
38
|
+
* Starts a thread that is not attached to a message: a private thread
|
|
39
|
+
* (`type: 12`, the default) or a public one (`type: 11`) in a text or
|
|
40
|
+
* announcement channel.
|
|
41
|
+
*/
|
|
42
|
+
create(options: ThreadCreateOptions & {
|
|
43
|
+
/** 11 public, 12 private (default), 10 announcement. */
|
|
44
|
+
type?: 10 | 11 | 12;
|
|
45
|
+
/** Whether non-moderators can add other members to a private thread. */
|
|
46
|
+
invitable?: boolean;
|
|
47
|
+
}): Promise<Channel>;
|
|
48
|
+
/**
|
|
49
|
+
* Posts to a forum or media channel: one request creates the thread and its
|
|
50
|
+
* first message. `message` takes everything `send()` does, files included.
|
|
51
|
+
*/
|
|
52
|
+
createForumPost(options: ThreadCreateOptions & {
|
|
53
|
+
message: MessageCreateOptions;
|
|
54
|
+
/** IDs of the channel's tags to apply. */
|
|
55
|
+
appliedTags?: string[];
|
|
56
|
+
}): Promise<Channel>;
|
|
57
|
+
/**
|
|
58
|
+
* Lists archived threads of this channel, newest first. `joined-private`
|
|
59
|
+
* is the private archived threads the bot is a member of.
|
|
60
|
+
*/
|
|
61
|
+
fetchArchived(scope: ArchivedThreadScope, options?: {
|
|
62
|
+
before?: string;
|
|
63
|
+
limit?: number;
|
|
64
|
+
}): Promise<ArchivedThreads>;
|
|
65
|
+
/** Joins a thread as the bot. */
|
|
66
|
+
join(threadId: string): Promise<void>;
|
|
67
|
+
/** Leaves a thread as the bot. */
|
|
68
|
+
leave(threadId: string): Promise<void>;
|
|
69
|
+
/** Adds a member to a thread. */
|
|
70
|
+
addMember(threadId: string, userId: string): Promise<void>;
|
|
71
|
+
/** Removes a member from a thread. */
|
|
72
|
+
removeMember(threadId: string, userId: string): Promise<void>;
|
|
73
|
+
/** Fetches one thread member; rejects with a 404 when they have not joined. */
|
|
74
|
+
fetchMember(threadId: string, userId: string, query?: ThreadMemberQuery): Promise<APIThreadMember & {
|
|
75
|
+
member?: APIGuildMember;
|
|
76
|
+
}>;
|
|
77
|
+
/** Lists thread members (needs the Guild Members intent), one page at a time (`limit` 1-100). */
|
|
78
|
+
fetchMembers(threadId: string, options?: ThreadMemberQuery & {
|
|
79
|
+
after?: string;
|
|
80
|
+
limit?: number;
|
|
81
|
+
}): Promise<APIThreadMember[]>;
|
|
14
82
|
}
|
package/dist/managers/user.d.ts
CHANGED
|
@@ -2,6 +2,17 @@ import { ResourceManager } from "./base.js";
|
|
|
2
2
|
import { User } from "@lunibee/structures";
|
|
3
3
|
import { type REST } from "@lunibee/rest";
|
|
4
4
|
import type { APIChannel } from "@lunibee/types";
|
|
5
|
+
/** A guild as `GET /users/@me/guilds` lists it. */
|
|
6
|
+
export interface APIPartialGuild {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
icon: string | null;
|
|
10
|
+
owner: boolean;
|
|
11
|
+
permissions: string;
|
|
12
|
+
features: string[];
|
|
13
|
+
approximate_member_count?: number;
|
|
14
|
+
approximate_presence_count?: number;
|
|
15
|
+
}
|
|
5
16
|
export interface UserEditOptions {
|
|
6
17
|
username?: string;
|
|
7
18
|
avatar?: string | null;
|
|
@@ -13,6 +24,13 @@ export declare class UserManager extends ResourceManager<string, User> {
|
|
|
13
24
|
fetchMe(): Promise<User>;
|
|
14
25
|
/** Modifies the currently logged-in bot user. */
|
|
15
26
|
editMe(options: UserEditOptions): Promise<User>;
|
|
27
|
+
/** Lists the guilds the bot is in, one page at a time (`limit` 1-200, `before` / `after` guild-ID cursors). */
|
|
28
|
+
fetchGuilds(options?: {
|
|
29
|
+
limit?: number;
|
|
30
|
+
before?: string;
|
|
31
|
+
after?: string;
|
|
32
|
+
withCounts?: boolean;
|
|
33
|
+
}): Promise<APIPartialGuild[]>;
|
|
16
34
|
/** Leaves a guild. */
|
|
17
35
|
leaveGuild(guildId: string): Promise<void>;
|
|
18
36
|
/** Creates a DM channel with a user. */
|
package/dist/rest/errors.d.ts
CHANGED
|
@@ -28,13 +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
|
-
|
|
37
|
-
/**
|
|
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;
|
|
38
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. */
|
|
39
46
|
constructor(message: string, status: number, code?: number, errors?: unknown, options?: {
|
|
40
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.
|
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.
|
|
5
|
+
version: "0.3.0",
|
|
6
6
|
type: "module",
|
|
7
7
|
module: "./src/index.ts",
|
|
8
8
|
types: "./src/index.ts",
|
|
@@ -83,7 +83,7 @@ function kindFromStatus(status) {
|
|
|
83
83
|
return "client";
|
|
84
84
|
}
|
|
85
85
|
function redactPath(path) {
|
|
86
|
-
return path.replace(/^(\/webhooks\/[^/?]+\/)[^/?]
|
|
86
|
+
return path.replace(/^(\/webhooks\/[^/?]+\/)[^/?]+/i, "$1:token").replace(/^(\/interactions\/[^/?]+\/)[^/?]+/i, "$1:token");
|
|
87
87
|
}
|
|
88
88
|
var HINTS = {
|
|
89
89
|
50001: "The bot cannot see this resource: check that it is in the guild and has View Channel there.",
|
|
@@ -142,19 +142,23 @@ async function abortable(promise, signal, path) {
|
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
// packages/rest/src/route.ts
|
|
145
|
+
import { createHash } from "crypto";
|
|
145
146
|
function normalizeRoutePath(path) {
|
|
146
147
|
const queryIndex = path.indexOf("?");
|
|
147
148
|
const routePath = queryIndex === -1 ? path : path.slice(0, queryIndex);
|
|
148
|
-
return routePath.replace(/\/\d+(?=\/|$)/g, "/:id");
|
|
149
|
+
return redactPath(routePath).replace(/\/\d+(?=\/|$)/g, "/:id");
|
|
149
150
|
}
|
|
150
151
|
function majorParameter(path) {
|
|
151
|
-
const match = /^\/(channels|guilds|webhooks)\/(\d+)(?:\/([^/?]+))
|
|
152
|
+
const match = /^\/(channels|guilds|webhooks)\/(\d+)(?:\/([^/?]+))?/i.exec(path);
|
|
152
153
|
if (!match)
|
|
153
154
|
return "@none";
|
|
154
|
-
if (match[1] === "webhooks" && match[3] !== undefined)
|
|
155
|
-
return `${match[2]}:${match[3]}`;
|
|
155
|
+
if (match[1].toLowerCase() === "webhooks" && match[3] !== undefined)
|
|
156
|
+
return `${match[2]}:${tokenDigest(match[3])}`;
|
|
156
157
|
return match[2];
|
|
157
158
|
}
|
|
159
|
+
function tokenDigest(token) {
|
|
160
|
+
return createHash("sha256").update(token).digest("hex").slice(0, 16);
|
|
161
|
+
}
|
|
158
162
|
function scopeBucket(hashOrRoute, major) {
|
|
159
163
|
return `${hashOrRoute}|${major}`;
|
|
160
164
|
}
|
|
@@ -396,6 +400,9 @@ var Routes = {
|
|
|
396
400
|
user: () => "/users/@me",
|
|
397
401
|
userById: (userId) => `/users/${snowflake(userId, "User ID")}`,
|
|
398
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")}`,
|
|
399
406
|
guildPreview: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/preview`,
|
|
400
407
|
guildActiveThreads: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/threads/active`,
|
|
401
408
|
guildWebhooks: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/webhooks`,
|
|
@@ -412,11 +419,10 @@ var Routes = {
|
|
|
412
419
|
message: (channelId, messageId) => `/channels/${snowflake(channelId, "Channel ID")}/messages/${snowflake(messageId, "Message ID")}`,
|
|
413
420
|
crosspostMessage: (channelId, messageId) => `${Routes.message(channelId, messageId)}/crosspost`,
|
|
414
421
|
messageReactions: (channelId, messageId, emoji) => `${Routes.message(channelId, messageId)}/reactions/${encodeURIComponent(emoji)}`,
|
|
422
|
+
messageReactionMe: (channelId, messageId, emoji) => `${Routes.messageReactions(channelId, messageId, emoji)}/@me`,
|
|
415
423
|
messageReactionsAll: (channelId, messageId) => `${Routes.message(channelId, messageId)}/reactions`,
|
|
416
424
|
channelMessagesPins: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/messages/pins`,
|
|
417
425
|
channelMessagesPin: (channelId, messageId) => `/channels/${snowflake(channelId, "Channel ID")}/messages/pins/${snowflake(messageId, "Message ID")}`,
|
|
418
|
-
channelPins: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/pins`,
|
|
419
|
-
channelPin: (channelId, messageId) => `/channels/${snowflake(channelId, "Channel ID")}/pins/${snowflake(messageId, "Message ID")}`,
|
|
420
426
|
messageThread: (channelId, messageId) => `${Routes.message(channelId, messageId)}/threads`,
|
|
421
427
|
channelBulkDelete: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/messages/bulk-delete`,
|
|
422
428
|
channelWebhooks: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/webhooks`,
|
|
@@ -431,6 +437,10 @@ var Routes = {
|
|
|
431
437
|
interactionOriginalResponse: (applicationId, token) => `/webhooks/${snowflake(applicationId, "Application ID")}/${encodeURIComponent(token)}/messages/@original`,
|
|
432
438
|
channelPublicArchivedThreads: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/threads/archived/public`,
|
|
433
439
|
channelPrivateArchivedThreads: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/threads/archived/private`,
|
|
440
|
+
channelJoinedPrivateArchivedThreads: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/users/@me/threads/archived/private`,
|
|
441
|
+
threadMember: (threadId, userId) => `/channels/${snowflake(threadId, "Thread ID")}/thread-members/${userOrMe(userId)}`,
|
|
442
|
+
channelTyping: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/typing`,
|
|
443
|
+
channelThreads: (channelId) => `/channels/${snowflake(channelId, "Channel ID")}/threads`,
|
|
434
444
|
threadMembers: (threadId) => `/channels/${snowflake(threadId, "Thread ID")}/thread-members`,
|
|
435
445
|
guildScheduledEvents: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/scheduled-events`,
|
|
436
446
|
guildScheduledEvent: (guildId, eventId) => `/guilds/${snowflake(guildId, "Guild ID")}/scheduled-events/${snowflake(eventId, "Event ID")}`,
|
|
@@ -443,6 +453,13 @@ var Routes = {
|
|
|
443
453
|
gatewayBot: () => "/gateway/bot",
|
|
444
454
|
guildAuditLog: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/audit-logs`,
|
|
445
455
|
guildMembers: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/members`,
|
|
456
|
+
guildMembersSearch: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/members/search`,
|
|
457
|
+
guildMemberMe: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/members/@me`,
|
|
458
|
+
guildBulkBan: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/bulk-ban`,
|
|
459
|
+
guildVoiceState: (guildId, userId) => `/guilds/${snowflake(guildId, "Guild ID")}/voice-states/${userOrMe(userId)}`,
|
|
460
|
+
guildIntegration: (guildId, integrationId) => `/guilds/${snowflake(guildId, "Guild ID")}/integrations/${snowflake(integrationId, "Integration ID")}`,
|
|
461
|
+
userGuilds: () => "/users/@me/guilds",
|
|
462
|
+
stickerPacks: (packId) => packId ? `/sticker-packs/${snowflake(packId, "Sticker pack ID")}` : "/sticker-packs",
|
|
446
463
|
guildWelcomeScreen: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/welcome-screen`,
|
|
447
464
|
guildOnboarding: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/onboarding`,
|
|
448
465
|
guildPrune: (guildId) => `/guilds/${snowflake(guildId, "Guild ID")}/prune`,
|
|
@@ -463,6 +480,9 @@ var Routes = {
|
|
|
463
480
|
consumeEntitlement: (applicationId, entitlementId) => `/applications/${snowflake(applicationId, "Application ID")}/entitlements/${snowflake(entitlementId, "Entitlement ID")}/consume`,
|
|
464
481
|
skuSubscription: (skuId, subscriptionId) => subscriptionId ? `/skus/${snowflake(skuId, "SKU ID")}/subscriptions/${snowflake(subscriptionId, "Subscription ID")}` : `/skus/${snowflake(skuId, "SKU ID")}/subscriptions`
|
|
465
482
|
};
|
|
483
|
+
function userOrMe(value) {
|
|
484
|
+
return value === "@me" ? value : snowflake(value, "User ID");
|
|
485
|
+
}
|
|
466
486
|
function integer(value, field) {
|
|
467
487
|
if (!Number.isInteger(value) || value < 0)
|
|
468
488
|
throw new TypeError(`${field} must be a non-negative integer.`);
|
|
@@ -657,7 +677,7 @@ class WebhookClient {
|
|
|
657
677
|
#rest;
|
|
658
678
|
constructor(options, restOptions) {
|
|
659
679
|
if (options.url) {
|
|
660
|
-
const match = options.url.match(
|
|
680
|
+
const match = options.url.match(/^https:\/\/(?:(?:ptb|canary)\.)?discord(?:app)?\.com\/api(?:\/v\d+)?\/webhooks\/(\d{1,20})\/([A-Za-z0-9_-]+)\/?(?:[?#].*)?$/);
|
|
661
681
|
if (!match)
|
|
662
682
|
throw new Error("Invalid Discord webhook URL format.");
|
|
663
683
|
this.id = match[1];
|
|
@@ -672,13 +692,20 @@ class WebhookClient {
|
|
|
672
692
|
}
|
|
673
693
|
async send(options) {
|
|
674
694
|
const payload = typeof options === "string" ? { content: options } : options;
|
|
675
|
-
const { thread_id, ...body } = payload;
|
|
676
|
-
const
|
|
695
|
+
const { thread_id, files, ...body } = payload;
|
|
696
|
+
const params = new URLSearchParams({ wait: "true" });
|
|
697
|
+
if (thread_id)
|
|
698
|
+
params.set("thread_id", String(thread_id));
|
|
699
|
+
const query = `?${params}`;
|
|
677
700
|
const formattedEmbeds = body.embeds?.map((e) => ("toJSON" in e) ? e.toJSON() : e);
|
|
678
|
-
|
|
701
|
+
const formattedComponents = body.components?.map((c) => ("toJSON" in c) ? c.toJSON() : c);
|
|
702
|
+
const path = `${Routes.webhook(this.id, this.token)}${query}`;
|
|
703
|
+
const json = {
|
|
679
704
|
...body,
|
|
680
|
-
embeds: formattedEmbeds
|
|
681
|
-
|
|
705
|
+
embeds: formattedEmbeds,
|
|
706
|
+
components: formattedComponents
|
|
707
|
+
};
|
|
708
|
+
return files?.length ? this.#rest.postWithFiles(path, json, files) : this.#rest.post(path, json);
|
|
682
709
|
}
|
|
683
710
|
async editMessage(messageId, options) {
|
|
684
711
|
const payload = typeof options === "string" ? { content: options } : options;
|
|
@@ -693,6 +720,22 @@ class WebhookClient {
|
|
|
693
720
|
var LIBRARY_VERSION = package_default.version;
|
|
694
721
|
var LIBRARY_URL = "https://github.com/Ekretos/lunibee";
|
|
695
722
|
var USER_AGENT = `DiscordBot (${LIBRARY_URL}, ${LIBRARY_VERSION})`;
|
|
723
|
+
function assertSafePath(path) {
|
|
724
|
+
const end = path.search(/[?#]/);
|
|
725
|
+
const pathname = end === -1 ? path : path.slice(0, end);
|
|
726
|
+
if (pathname.includes("\\"))
|
|
727
|
+
throw new TypeError("REST paths must not contain backslashes.");
|
|
728
|
+
for (const segment of pathname.split("/")) {
|
|
729
|
+
let decoded;
|
|
730
|
+
try {
|
|
731
|
+
decoded = decodeURIComponent(segment);
|
|
732
|
+
} catch {
|
|
733
|
+
throw new TypeError("REST path has malformed percent-encoding.");
|
|
734
|
+
}
|
|
735
|
+
if (decoded === "." || decoded === "..")
|
|
736
|
+
throw new TypeError("REST paths must not contain '.' or '..' segments.");
|
|
737
|
+
}
|
|
738
|
+
}
|
|
696
739
|
var REQUEST_DATA_KEYS = new Set([
|
|
697
740
|
"body",
|
|
698
741
|
"files",
|
|
@@ -753,7 +796,7 @@ class REST {
|
|
|
753
796
|
timeout: options.timeout
|
|
754
797
|
});
|
|
755
798
|
const store = options.store ?? new MemoryRateLimitStore;
|
|
756
|
-
this.#concurrentBuckets = (options.concurrentBuckets ??
|
|
799
|
+
this.#concurrentBuckets = (options.concurrentBuckets ?? true) && typeof store.reserve === "function";
|
|
757
800
|
this.#limiter = new RateLimiter(store, {
|
|
758
801
|
concurrent: this.#concurrentBuckets
|
|
759
802
|
});
|
|
@@ -777,6 +820,7 @@ class REST {
|
|
|
777
820
|
throw new TypeError("REST method is required.");
|
|
778
821
|
if (!path.startsWith("/"))
|
|
779
822
|
throw new TypeError("REST paths must start with '/'.");
|
|
823
|
+
assertSafePath(path);
|
|
780
824
|
const route = createRouteKey(method, path);
|
|
781
825
|
const files = options.files;
|
|
782
826
|
if (files && files.length > 0 && !(body instanceof FormData))
|
|
@@ -864,13 +908,19 @@ class REST {
|
|
|
864
908
|
#headers(body, options) {
|
|
865
909
|
const isFormData = typeof FormData !== "undefined" && body instanceof FormData;
|
|
866
910
|
const headers = { ...options.headers };
|
|
911
|
+
const set = (name, value) => {
|
|
912
|
+
for (const key of Object.keys(headers))
|
|
913
|
+
if (key.toLowerCase() === name.toLowerCase())
|
|
914
|
+
delete headers[key];
|
|
915
|
+
headers[name] = value;
|
|
916
|
+
};
|
|
867
917
|
if (options.auth !== false && this.#token)
|
|
868
|
-
|
|
869
|
-
|
|
918
|
+
set("Authorization", `Bot ${this.#token}`);
|
|
919
|
+
set("User-Agent", USER_AGENT);
|
|
870
920
|
if (options.reason !== undefined)
|
|
871
|
-
|
|
921
|
+
set("X-Audit-Log-Reason", encodeURIComponent(options.reason));
|
|
872
922
|
if (!isFormData)
|
|
873
|
-
|
|
923
|
+
set("Content-Type", "application/json");
|
|
874
924
|
return headers;
|
|
875
925
|
}
|
|
876
926
|
#encodeBody(body) {
|
|
@@ -949,4 +999,4 @@ export {
|
|
|
949
999
|
serializeQuery
|
|
950
1000
|
};
|
|
951
1001
|
|
|
952
|
-
//# debugId=
|
|
1002
|
+
//# debugId=76878940534439C564756E2164756E21
|