privage.js 0.21.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/LICENSE +21 -0
- package/README.md +503 -0
- package/dist/Client.d.ts +192 -0
- package/dist/Client.js +904 -0
- package/dist/attachments.d.ts +41 -0
- package/dist/attachments.js +63 -0
- package/dist/collectors.d.ts +41 -0
- package/dist/collectors.js +52 -0
- package/dist/commands.d.ts +108 -0
- package/dist/commands.js +216 -0
- package/dist/compat.d.ts +72 -0
- package/dist/compat.js +75 -0
- package/dist/components.d.ts +137 -0
- package/dist/components.js +226 -0
- package/dist/embeds.d.ts +97 -0
- package/dist/embeds.js +125 -0
- package/dist/errors.d.ts +32 -0
- package/dist/errors.js +48 -0
- package/dist/formatters.d.ts +16 -0
- package/dist/formatters.js +43 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +101 -0
- package/dist/intents.d.ts +28 -0
- package/dist/intents.js +33 -0
- package/dist/modals.d.ts +96 -0
- package/dist/modals.js +162 -0
- package/dist/rest.d.ts +208 -0
- package/dist/rest.js +356 -0
- package/dist/structures/Channel.d.ts +25 -0
- package/dist/structures/Channel.js +34 -0
- package/dist/structures/Interaction.d.ts +149 -0
- package/dist/structures/Interaction.js +170 -0
- package/dist/structures/Member.d.ts +35 -0
- package/dist/structures/Member.js +55 -0
- package/dist/structures/Message.d.ts +181 -0
- package/dist/structures/Message.js +191 -0
- package/dist/structures/Role.d.ts +17 -0
- package/dist/structures/Role.js +20 -0
- package/dist/structures/Server.d.ts +29 -0
- package/dist/structures/Server.js +36 -0
- package/dist/structures/ServerChannels.d.ts +24 -0
- package/dist/structures/ServerChannels.js +50 -0
- package/dist/types.d.ts +195 -0
- package/dist/types.js +2 -0
- package/package.json +49 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import type { Client } from '../Client';
|
|
2
|
+
import type { EmbedBuilder, Embed } from '../embeds';
|
|
3
|
+
import type { ActionRow, ActionRowBuilder } from '../components';
|
|
4
|
+
import { ModalBuilder, type Modal } from '../modals';
|
|
5
|
+
/** Discriminates what the user did. Pre-v2 envelopes (no `kind`) read as `'button'`. */
|
|
6
|
+
export type InteractionKind = 'button' | 'select' | 'command' | 'modal_submit';
|
|
7
|
+
export interface InteractionUpdateData {
|
|
8
|
+
content?: string;
|
|
9
|
+
embeds?: (Embed | EmbedBuilder | Record<string, unknown>)[];
|
|
10
|
+
components?: (ActionRow | ActionRowBuilder | Record<string, unknown>)[];
|
|
11
|
+
}
|
|
12
|
+
export interface InteractionReplyData {
|
|
13
|
+
content?: string;
|
|
14
|
+
embeds?: (Embed | EmbedBuilder | Record<string, unknown>)[];
|
|
15
|
+
/**
|
|
16
|
+
* Only-you reply: never persisted, delivered as an event to the
|
|
17
|
+
* interacting user alone ("Only you can see this"). Valid for every
|
|
18
|
+
* interaction kind. Still terminal.
|
|
19
|
+
*/
|
|
20
|
+
ephemeral?: boolean;
|
|
21
|
+
/** Components on the reply — ephemeral replies only (they render, but aren't clickable v1). */
|
|
22
|
+
components?: (ActionRow | ActionRowBuilder | Record<string, unknown>)[];
|
|
23
|
+
}
|
|
24
|
+
export type CommandOptionType = 'string' | 'integer' | 'number' | 'boolean' | 'user' | 'channel' | 'role';
|
|
25
|
+
/** One resolved option of a slash-command invocation (already validated + coerced by the server). */
|
|
26
|
+
export interface CommandInteractionOption {
|
|
27
|
+
name: string;
|
|
28
|
+
type: CommandOptionType;
|
|
29
|
+
/** string/user/channel/role → string (ids are snowflake strings); integer/number → number; boolean → boolean. */
|
|
30
|
+
value: string | number | boolean;
|
|
31
|
+
}
|
|
32
|
+
/** The invoked slash command on a `kind: 'command'` interaction. */
|
|
33
|
+
export declare class InteractionCommand {
|
|
34
|
+
/** Registry id of the command. */
|
|
35
|
+
readonly id: string;
|
|
36
|
+
readonly name: string;
|
|
37
|
+
/** The raw options array, in schema order. */
|
|
38
|
+
readonly options: CommandInteractionOption[];
|
|
39
|
+
constructor(data: any);
|
|
40
|
+
/** The typed value of an option by name (`undefined` when the invoker omitted an optional one). */
|
|
41
|
+
getOption<T extends string | number | boolean = string | number | boolean>(name: string): T | undefined;
|
|
42
|
+
}
|
|
43
|
+
/** One submitted field of a modal (`kind: 'modal_submit'`). */
|
|
44
|
+
export interface ModalSubmitField {
|
|
45
|
+
customId: string;
|
|
46
|
+
value: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A user interaction with the bot — a button click, select-menu choice,
|
|
50
|
+
* slash-command invocation, or modal submission (discriminated by `kind`).
|
|
51
|
+
* Respond within the window (5 min; 15 after `defer()`) with exactly one
|
|
52
|
+
* terminal callback — `update()` or `reply()` — optionally preceded by
|
|
53
|
+
* `defer()`, or open a modal with `showModal()` (pending interactions only).
|
|
54
|
+
* The token is single-use; after responding, further changes go through the
|
|
55
|
+
* normal `client.editMessage`/`client.send` APIs.
|
|
56
|
+
*/
|
|
57
|
+
export declare class Interaction {
|
|
58
|
+
private readonly client;
|
|
59
|
+
readonly id: string;
|
|
60
|
+
/** Single-use callback credential — treat like a secret; expires with the window. */
|
|
61
|
+
readonly token: string;
|
|
62
|
+
/** What the user did — `'button' | 'select' | 'command' | 'modal_submit'`. */
|
|
63
|
+
readonly kind: InteractionKind;
|
|
64
|
+
/**
|
|
65
|
+
* The component's custom_id (clicks), or the modal's custom_id
|
|
66
|
+
* (modal_submit), exactly as the sending bot chose it. `null` for
|
|
67
|
+
* slash commands.
|
|
68
|
+
*/
|
|
69
|
+
readonly customId: string | null;
|
|
70
|
+
/** Selected option values — `kind: 'select'` only, `null` otherwise. */
|
|
71
|
+
readonly values: string[] | null;
|
|
72
|
+
/** The invoked slash command — `kind: 'command'` only, `null` otherwise. */
|
|
73
|
+
readonly command: InteractionCommand | null;
|
|
74
|
+
/** Submitted modal fields — `kind: 'modal_submit'` only, `null` otherwise. */
|
|
75
|
+
readonly fields: ModalSubmitField[] | null;
|
|
76
|
+
/** The source message. `null` for commands (and command-born modal submits) — `update()` is invalid then. */
|
|
77
|
+
readonly messageId: string | null;
|
|
78
|
+
readonly channelId: string;
|
|
79
|
+
readonly serverId: string | null;
|
|
80
|
+
readonly user: {
|
|
81
|
+
id: string;
|
|
82
|
+
username: string | null;
|
|
83
|
+
displayName: string | null;
|
|
84
|
+
};
|
|
85
|
+
readonly createdAt: string;
|
|
86
|
+
/** The raw wire payload. */
|
|
87
|
+
readonly raw: any;
|
|
88
|
+
/** Client-side mirror of the server's state machine — guards `showModal()`. */
|
|
89
|
+
private state;
|
|
90
|
+
constructor(client: Client, data: any);
|
|
91
|
+
/** A submitted modal field's value by custom_id (`kind: 'modal_submit'`; `undefined` for omitted optional fields). */
|
|
92
|
+
getField(customId: string): string | undefined;
|
|
93
|
+
/** `kind === 'button'` (discord.js-style type guard). */
|
|
94
|
+
isButton(): boolean;
|
|
95
|
+
/** `kind === 'select'`. */
|
|
96
|
+
isSelect(): boolean;
|
|
97
|
+
/** discord.js alias for {@link isSelect}. */
|
|
98
|
+
isStringSelectMenu(): boolean;
|
|
99
|
+
/** `kind === 'command'`. */
|
|
100
|
+
isCommand(): boolean;
|
|
101
|
+
/** discord.js alias for {@link isCommand}. */
|
|
102
|
+
isChatInputCommand(): boolean;
|
|
103
|
+
/** `kind === 'modal_submit'`. */
|
|
104
|
+
isModalSubmit(): boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Terminal: edit the original message (content/embeds/components).
|
|
107
|
+
* Broadcasts a normal edit. Only valid when the interaction HAS a source
|
|
108
|
+
* message — throws client-side for `kind: 'command'` and for modal submits
|
|
109
|
+
* born from a command (the server would 400).
|
|
110
|
+
*/
|
|
111
|
+
update(data: InteractionUpdateData): Promise<any>;
|
|
112
|
+
/**
|
|
113
|
+
* Terminal: post a bot message replying to the original (a plain channel
|
|
114
|
+
* message for commands). Pass `{ ephemeral: true }` for an only-you reply
|
|
115
|
+
* that is never persisted.
|
|
116
|
+
*/
|
|
117
|
+
reply(data: string | InteractionReplyData): Promise<any>;
|
|
118
|
+
/**
|
|
119
|
+
* discord.js alias for {@link defer} — extends the response window; follow
|
|
120
|
+
* with `editReply()`/`reply()`. (No flags/ephemeral options here: set
|
|
121
|
+
* `ephemeral` on the eventual reply instead.)
|
|
122
|
+
*/
|
|
123
|
+
deferReply(): Promise<any>;
|
|
124
|
+
/**
|
|
125
|
+
* discord.js alias for {@link reply} — in this SDK the deferred response
|
|
126
|
+
* IS the reply (there is no placeholder message to edit), so editing the
|
|
127
|
+
* deferred reply and replying are the same terminal callback.
|
|
128
|
+
*/
|
|
129
|
+
editReply(data: string | InteractionReplyData): Promise<any>;
|
|
130
|
+
/** Extend the response window to 15 minutes; must still be followed by `update()` or `reply()`. */
|
|
131
|
+
defer(): Promise<any>;
|
|
132
|
+
/**
|
|
133
|
+
* Open a modal dialog for the interacting user; their submission arrives
|
|
134
|
+
* as a fresh `interaction` event with `kind: 'modal_submit'` (matched via
|
|
135
|
+
* the modal's custom_id).
|
|
136
|
+
*
|
|
137
|
+
* Only valid from a PENDING interaction, once: not after `defer()`, not
|
|
138
|
+
* after a terminal callback, and never in response to a modal submit — the
|
|
139
|
+
* server 400s all of these, and this method throws client-side first.
|
|
140
|
+
* Showing a modal does NOT extend the 5-minute window.
|
|
141
|
+
*/
|
|
142
|
+
showModal(modal: Modal | ModalBuilder | Record<string, unknown>): Promise<any>;
|
|
143
|
+
/**
|
|
144
|
+
* Advance the state optimistically (so a concurrent second call sees it),
|
|
145
|
+
* but roll back when the wire call rejects — a transient failure must not
|
|
146
|
+
* strand the interaction in a state that blocks the legitimate retry.
|
|
147
|
+
*/
|
|
148
|
+
private transition;
|
|
149
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Interaction = exports.InteractionCommand = void 0;
|
|
4
|
+
const modals_1 = require("../modals");
|
|
5
|
+
/** The invoked slash command on a `kind: 'command'` interaction. */
|
|
6
|
+
class InteractionCommand {
|
|
7
|
+
constructor(data) {
|
|
8
|
+
this.id = String(data?.id ?? '');
|
|
9
|
+
this.name = String(data?.name ?? '');
|
|
10
|
+
this.options = Array.isArray(data?.options)
|
|
11
|
+
? data.options.map((o) => ({
|
|
12
|
+
name: String(o?.name ?? ''),
|
|
13
|
+
type: (o?.type ?? 'string'),
|
|
14
|
+
value: o?.value,
|
|
15
|
+
}))
|
|
16
|
+
: [];
|
|
17
|
+
}
|
|
18
|
+
/** The typed value of an option by name (`undefined` when the invoker omitted an optional one). */
|
|
19
|
+
getOption(name) {
|
|
20
|
+
return this.options.find((o) => o.name === name)?.value;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.InteractionCommand = InteractionCommand;
|
|
24
|
+
/**
|
|
25
|
+
* A user interaction with the bot — a button click, select-menu choice,
|
|
26
|
+
* slash-command invocation, or modal submission (discriminated by `kind`).
|
|
27
|
+
* Respond within the window (5 min; 15 after `defer()`) with exactly one
|
|
28
|
+
* terminal callback — `update()` or `reply()` — optionally preceded by
|
|
29
|
+
* `defer()`, or open a modal with `showModal()` (pending interactions only).
|
|
30
|
+
* The token is single-use; after responding, further changes go through the
|
|
31
|
+
* normal `client.editMessage`/`client.send` APIs.
|
|
32
|
+
*/
|
|
33
|
+
class Interaction {
|
|
34
|
+
constructor(client, data) {
|
|
35
|
+
this.client = client;
|
|
36
|
+
/** Client-side mirror of the server's state machine — guards `showModal()`. */
|
|
37
|
+
this.state = 'pending';
|
|
38
|
+
this.raw = data;
|
|
39
|
+
this.id = String(data.id ?? '');
|
|
40
|
+
this.token = String(data.token ?? '');
|
|
41
|
+
this.kind =
|
|
42
|
+
data.kind === 'select' || data.kind === 'command' || data.kind === 'modal_submit'
|
|
43
|
+
? data.kind
|
|
44
|
+
: 'button'; // absent kind = pre-v2 payload = button
|
|
45
|
+
this.customId = data.custom_id != null ? String(data.custom_id) : null;
|
|
46
|
+
this.values = Array.isArray(data.values) ? data.values.map(String) : null;
|
|
47
|
+
this.command = data.command != null && typeof data.command === 'object' ? new InteractionCommand(data.command) : null;
|
|
48
|
+
this.fields = Array.isArray(data.modal?.fields)
|
|
49
|
+
? data.modal.fields.map((f) => ({ customId: String(f?.custom_id ?? ''), value: String(f?.value ?? '') }))
|
|
50
|
+
: null;
|
|
51
|
+
this.messageId = data.message_id != null ? String(data.message_id) : null;
|
|
52
|
+
this.channelId = String(data.channel_id ?? '');
|
|
53
|
+
this.serverId = data.server_id != null ? String(data.server_id) : null;
|
|
54
|
+
this.user = {
|
|
55
|
+
id: String(data.user?.id ?? ''),
|
|
56
|
+
username: data.user?.username ?? null,
|
|
57
|
+
displayName: data.user?.display_name ?? null,
|
|
58
|
+
};
|
|
59
|
+
this.createdAt = String(data.created_at ?? '');
|
|
60
|
+
}
|
|
61
|
+
/** A submitted modal field's value by custom_id (`kind: 'modal_submit'`; `undefined` for omitted optional fields). */
|
|
62
|
+
getField(customId) {
|
|
63
|
+
return this.fields?.find((f) => f.customId === customId)?.value;
|
|
64
|
+
}
|
|
65
|
+
/** `kind === 'button'` (discord.js-style type guard). */
|
|
66
|
+
isButton() {
|
|
67
|
+
return this.kind === 'button';
|
|
68
|
+
}
|
|
69
|
+
/** `kind === 'select'`. */
|
|
70
|
+
isSelect() {
|
|
71
|
+
return this.kind === 'select';
|
|
72
|
+
}
|
|
73
|
+
/** discord.js alias for {@link isSelect}. */
|
|
74
|
+
isStringSelectMenu() {
|
|
75
|
+
return this.kind === 'select';
|
|
76
|
+
}
|
|
77
|
+
/** `kind === 'command'`. */
|
|
78
|
+
isCommand() {
|
|
79
|
+
return this.kind === 'command';
|
|
80
|
+
}
|
|
81
|
+
/** discord.js alias for {@link isCommand}. */
|
|
82
|
+
isChatInputCommand() {
|
|
83
|
+
return this.kind === 'command';
|
|
84
|
+
}
|
|
85
|
+
/** `kind === 'modal_submit'`. */
|
|
86
|
+
isModalSubmit() {
|
|
87
|
+
return this.kind === 'modal_submit';
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Terminal: edit the original message (content/embeds/components).
|
|
91
|
+
* Broadcasts a normal edit. Only valid when the interaction HAS a source
|
|
92
|
+
* message — throws client-side for `kind: 'command'` and for modal submits
|
|
93
|
+
* born from a command (the server would 400).
|
|
94
|
+
*/
|
|
95
|
+
update(data) {
|
|
96
|
+
if (this.kind === 'command') {
|
|
97
|
+
throw new RangeError('update() is not valid for command interactions — there is no source message. Use reply() instead.');
|
|
98
|
+
}
|
|
99
|
+
if (this.kind === 'modal_submit' && !this.messageId) {
|
|
100
|
+
throw new RangeError('update() is not valid for this modal submit — its parent interaction had no source message. Use reply() instead.');
|
|
101
|
+
}
|
|
102
|
+
return this.transition('responded', () => this.client.rest.interactionCallback(this.id, this.token, 'update', data));
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Terminal: post a bot message replying to the original (a plain channel
|
|
106
|
+
* message for commands). Pass `{ ephemeral: true }` for an only-you reply
|
|
107
|
+
* that is never persisted.
|
|
108
|
+
*/
|
|
109
|
+
reply(data) {
|
|
110
|
+
return this.transition('responded', () => this.client.rest.interactionCallback(this.id, this.token, 'reply', typeof data === 'string' ? { content: data } : data));
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* discord.js alias for {@link defer} — extends the response window; follow
|
|
114
|
+
* with `editReply()`/`reply()`. (No flags/ephemeral options here: set
|
|
115
|
+
* `ephemeral` on the eventual reply instead.)
|
|
116
|
+
*/
|
|
117
|
+
deferReply() {
|
|
118
|
+
return this.defer();
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* discord.js alias for {@link reply} — in this SDK the deferred response
|
|
122
|
+
* IS the reply (there is no placeholder message to edit), so editing the
|
|
123
|
+
* deferred reply and replying are the same terminal callback.
|
|
124
|
+
*/
|
|
125
|
+
editReply(data) {
|
|
126
|
+
return this.reply(data);
|
|
127
|
+
}
|
|
128
|
+
/** Extend the response window to 15 minutes; must still be followed by `update()` or `reply()`. */
|
|
129
|
+
defer() {
|
|
130
|
+
if (this.state !== 'pending') {
|
|
131
|
+
return this.client.rest.interactionCallback(this.id, this.token, 'defer');
|
|
132
|
+
}
|
|
133
|
+
return this.transition('deferred', () => this.client.rest.interactionCallback(this.id, this.token, 'defer'));
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Open a modal dialog for the interacting user; their submission arrives
|
|
137
|
+
* as a fresh `interaction` event with `kind: 'modal_submit'` (matched via
|
|
138
|
+
* the modal's custom_id).
|
|
139
|
+
*
|
|
140
|
+
* Only valid from a PENDING interaction, once: not after `defer()`, not
|
|
141
|
+
* after a terminal callback, and never in response to a modal submit — the
|
|
142
|
+
* server 400s all of these, and this method throws client-side first.
|
|
143
|
+
* Showing a modal does NOT extend the 5-minute window.
|
|
144
|
+
*/
|
|
145
|
+
showModal(modal) {
|
|
146
|
+
if (this.kind === 'modal_submit') {
|
|
147
|
+
throw new RangeError('showModal() is not valid in response to a modal submit — respond with reply() or update() instead.');
|
|
148
|
+
}
|
|
149
|
+
if (this.state !== 'pending') {
|
|
150
|
+
throw new RangeError(`showModal() is only valid once, from a pending interaction — not after defer(), a previous showModal(), or a terminal callback (state: ${this.state}).`);
|
|
151
|
+
}
|
|
152
|
+
const payload = modal instanceof modals_1.ModalBuilder ? modal.toJSON() : modal;
|
|
153
|
+
return this.transition('awaiting_modal', () => this.client.rest.interactionCallback(this.id, this.token, 'modal', payload));
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Advance the state optimistically (so a concurrent second call sees it),
|
|
157
|
+
* but roll back when the wire call rejects — a transient failure must not
|
|
158
|
+
* strand the interaction in a state that blocks the legitimate retry.
|
|
159
|
+
*/
|
|
160
|
+
transition(next, send) {
|
|
161
|
+
const prev = this.state;
|
|
162
|
+
this.state = next;
|
|
163
|
+
return send().catch((err) => {
|
|
164
|
+
if (this.state === next)
|
|
165
|
+
this.state = prev;
|
|
166
|
+
throw err;
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
exports.Interaction = Interaction;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Client } from '../Client';
|
|
2
|
+
import type { KickBanOptions, TimeoutOptions } from '../rest';
|
|
3
|
+
/** A server member, with role-management helpers. */
|
|
4
|
+
export declare class Member {
|
|
5
|
+
private readonly client;
|
|
6
|
+
/** The member's user id. */
|
|
7
|
+
readonly id: string;
|
|
8
|
+
readonly username: string;
|
|
9
|
+
readonly displayName: string | null;
|
|
10
|
+
readonly avatarUrl: string | null;
|
|
11
|
+
readonly bot: boolean;
|
|
12
|
+
readonly serverId: string | null;
|
|
13
|
+
/** The raw wire payload. */
|
|
14
|
+
readonly raw: any;
|
|
15
|
+
constructor(client: Client, data: any);
|
|
16
|
+
/**
|
|
17
|
+
* Grant a role to this member. Requires the bot to have `MANAGE_ROLES`, the
|
|
18
|
+
* role to be below the bot's highest role, and its permissions to be
|
|
19
|
+
* delegatable by the bot. Rejects with `PrivagePermissionError` (403) otherwise.
|
|
20
|
+
*/
|
|
21
|
+
addRole(roleId: string): Promise<any>;
|
|
22
|
+
/** Remove a role from this member. */
|
|
23
|
+
removeRole(roleId: string): Promise<any>;
|
|
24
|
+
/** Kick this member (needs KICK_MEMBERS + outrank them). */
|
|
25
|
+
kick(opts?: KickBanOptions): Promise<any>;
|
|
26
|
+
/** Ban this member (needs BAN_MEMBERS + outrank them). */
|
|
27
|
+
ban(opts?: KickBanOptions): Promise<any>;
|
|
28
|
+
/** Time out this member (needs TIMEOUT_MEMBERS). Provide `durationSeconds` or `until`. */
|
|
29
|
+
timeout(opts: TimeoutOptions): Promise<any>;
|
|
30
|
+
/** Remove this member's timeout. */
|
|
31
|
+
removeTimeout(): Promise<any>;
|
|
32
|
+
/** Set (or clear, with `null`) this member's nickname. Others need MANAGE_NICKNAMES. */
|
|
33
|
+
setNickname(nickname: string | null): Promise<any>;
|
|
34
|
+
private requireServer;
|
|
35
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Member = void 0;
|
|
4
|
+
const errors_1 = require("../errors");
|
|
5
|
+
/** A server member, with role-management helpers. */
|
|
6
|
+
class Member {
|
|
7
|
+
constructor(client, data) {
|
|
8
|
+
this.client = client;
|
|
9
|
+
this.raw = data;
|
|
10
|
+
this.id = String(data.user_id ?? data.id ?? '');
|
|
11
|
+
this.username = data.username ?? 'unknown';
|
|
12
|
+
this.displayName = data.display_name ?? null;
|
|
13
|
+
this.avatarUrl = data.avatar_url ?? null;
|
|
14
|
+
this.bot = !!data.is_bot;
|
|
15
|
+
this.serverId = data.serverId != null ? String(data.serverId) : (data.server_id != null ? String(data.server_id) : null);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Grant a role to this member. Requires the bot to have `MANAGE_ROLES`, the
|
|
19
|
+
* role to be below the bot's highest role, and its permissions to be
|
|
20
|
+
* delegatable by the bot. Rejects with `PrivagePermissionError` (403) otherwise.
|
|
21
|
+
*/
|
|
22
|
+
addRole(roleId) {
|
|
23
|
+
return this.client.addRole(this.requireServer(), this.id, roleId);
|
|
24
|
+
}
|
|
25
|
+
/** Remove a role from this member. */
|
|
26
|
+
removeRole(roleId) {
|
|
27
|
+
return this.client.removeRole(this.requireServer(), this.id, roleId);
|
|
28
|
+
}
|
|
29
|
+
/** Kick this member (needs KICK_MEMBERS + outrank them). */
|
|
30
|
+
kick(opts) {
|
|
31
|
+
return this.client.kick(this.requireServer(), this.id, opts);
|
|
32
|
+
}
|
|
33
|
+
/** Ban this member (needs BAN_MEMBERS + outrank them). */
|
|
34
|
+
ban(opts) {
|
|
35
|
+
return this.client.ban(this.requireServer(), this.id, opts);
|
|
36
|
+
}
|
|
37
|
+
/** Time out this member (needs TIMEOUT_MEMBERS). Provide `durationSeconds` or `until`. */
|
|
38
|
+
timeout(opts) {
|
|
39
|
+
return this.client.timeout(this.requireServer(), this.id, opts);
|
|
40
|
+
}
|
|
41
|
+
/** Remove this member's timeout. */
|
|
42
|
+
removeTimeout() {
|
|
43
|
+
return this.client.removeTimeout(this.requireServer(), this.id);
|
|
44
|
+
}
|
|
45
|
+
/** Set (or clear, with `null`) this member's nickname. Others need MANAGE_NICKNAMES. */
|
|
46
|
+
setNickname(nickname) {
|
|
47
|
+
return this.client.setNickname(this.requireServer(), this.id, nickname);
|
|
48
|
+
}
|
|
49
|
+
requireServer() {
|
|
50
|
+
if (!this.serverId)
|
|
51
|
+
throw new errors_1.PrivagePermissionError('Roles can only be managed on server members, not in DMs.');
|
|
52
|
+
return this.serverId;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
exports.Member = Member;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import type { Client } from '../Client';
|
|
2
|
+
import type { Author } from '../types';
|
|
3
|
+
import type { SendMessageOptions } from '../rest';
|
|
4
|
+
import { Member } from './Member';
|
|
5
|
+
import { Channel, TextChannel } from './Channel';
|
|
6
|
+
import type { Server } from './Server';
|
|
7
|
+
export { TextChannel };
|
|
8
|
+
type Sendable = string | Omit<SendMessageOptions, 'replyTo'>;
|
|
9
|
+
/**
|
|
10
|
+
* A message's thread badge — present only when a thread exists (or existed:
|
|
11
|
+
* a tombstoned thread keeps `deletedAt` set with `id: null` semantics
|
|
12
|
+
* preserved from the wire, so "deleted" is distinguishable from "never had
|
|
13
|
+
* one"). Non-thread messages carry `thread: null`.
|
|
14
|
+
*/
|
|
15
|
+
export interface MessageThread {
|
|
16
|
+
/** The thread channel's id (`null` on a tombstoned thread). */
|
|
17
|
+
id: string | null;
|
|
18
|
+
replyCount: number;
|
|
19
|
+
lastActivityAt: Date | null;
|
|
20
|
+
/** Set when the thread was deleted. */
|
|
21
|
+
deletedAt: Date | null;
|
|
22
|
+
}
|
|
23
|
+
/** A file attached to a received message (normalized from the wire row). */
|
|
24
|
+
export interface MessageAttachment {
|
|
25
|
+
id: string;
|
|
26
|
+
/** Filename shown in the client. */
|
|
27
|
+
filename: string;
|
|
28
|
+
/** Download URL. */
|
|
29
|
+
url: string;
|
|
30
|
+
mimeType: string;
|
|
31
|
+
/** Size in bytes. */
|
|
32
|
+
size: number;
|
|
33
|
+
/** Image/video dimensions, when known. */
|
|
34
|
+
width: number | null;
|
|
35
|
+
height: number | null;
|
|
36
|
+
/** Renders blurred in the client until the viewer reveals it. */
|
|
37
|
+
spoiler: boolean;
|
|
38
|
+
createdAt: Date | null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* An embed as received on a message — the flattened STORED shape, not the
|
|
42
|
+
* nested shape you send. On persist the server flattens the nested input:
|
|
43
|
+
* `author.*` becomes `authorName`/`authorUrl`/`icon`, `image`/`thumbnail`
|
|
44
|
+
* collapse into the single `thumbnail` slot, and numeric colors are stored
|
|
45
|
+
* as hex strings. `type` is `'rich'` for bot-built embeds, `'link'` for
|
|
46
|
+
* URL unfurls.
|
|
47
|
+
*/
|
|
48
|
+
export interface MessageEmbed {
|
|
49
|
+
id: string;
|
|
50
|
+
type: string;
|
|
51
|
+
url: string | null;
|
|
52
|
+
title: string | null;
|
|
53
|
+
description: string | null;
|
|
54
|
+
/** Hex color string (`'#2ea043'`) — numeric colors are stored as hex. */
|
|
55
|
+
color: string | null;
|
|
56
|
+
/** The single image slot (send-side `image`/`thumbnail` collapse here). */
|
|
57
|
+
thumbnail: string | null;
|
|
58
|
+
authorName: string | null;
|
|
59
|
+
authorUrl: string | null;
|
|
60
|
+
icon: string | null;
|
|
61
|
+
siteName: string | null;
|
|
62
|
+
provider: string | null;
|
|
63
|
+
videoUrl: string | null;
|
|
64
|
+
/** Preview image/video dimensions, when known. */
|
|
65
|
+
width: number | null;
|
|
66
|
+
height: number | null;
|
|
67
|
+
fields: {
|
|
68
|
+
name: string;
|
|
69
|
+
value: string;
|
|
70
|
+
inline: boolean;
|
|
71
|
+
}[];
|
|
72
|
+
footer: {
|
|
73
|
+
text: string;
|
|
74
|
+
} | null;
|
|
75
|
+
/** The embed's own display timestamp (ISO string), if one was set. */
|
|
76
|
+
timestamp: string | null;
|
|
77
|
+
createdAt: Date | null;
|
|
78
|
+
}
|
|
79
|
+
/** A frozen or live preview of the message a reference points at. */
|
|
80
|
+
export interface ReferencedMessage {
|
|
81
|
+
id: string;
|
|
82
|
+
content: string;
|
|
83
|
+
author: Author | null;
|
|
84
|
+
createdAt: Date | null;
|
|
85
|
+
attachments: MessageAttachment[];
|
|
86
|
+
embeds: MessageEmbed[];
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* A self-contained pointer at another message.
|
|
90
|
+
*
|
|
91
|
+
* - `reply` — resolves live (edits to the target reflect; deleted target → `message: null`).
|
|
92
|
+
* - `forward` — an anti-tamper snapshot: content/embeds/attachments are frozen
|
|
93
|
+
* at forward time; the author stays live while the original exists.
|
|
94
|
+
* - `pin` — "X pinned a message" system rows.
|
|
95
|
+
*
|
|
96
|
+
* `message` is `undefined` when the referent wasn't resolved (e.g. edit
|
|
97
|
+
* broadcasts), `null` when it was deleted, and a preview otherwise.
|
|
98
|
+
* `channelId`/`serverId` are set only when the referent lives in another
|
|
99
|
+
* channel/server (forwards).
|
|
100
|
+
*/
|
|
101
|
+
export interface MessageReference {
|
|
102
|
+
type: 'reply' | 'forward' | 'pin';
|
|
103
|
+
messageId: string;
|
|
104
|
+
channelId: string | null;
|
|
105
|
+
serverId: string | null;
|
|
106
|
+
message?: ReferencedMessage | null;
|
|
107
|
+
}
|
|
108
|
+
/** A received message. */
|
|
109
|
+
export declare class Message {
|
|
110
|
+
private readonly client;
|
|
111
|
+
readonly id: string;
|
|
112
|
+
readonly channelId: string;
|
|
113
|
+
readonly serverId: string | null;
|
|
114
|
+
readonly content: string;
|
|
115
|
+
readonly author: Author;
|
|
116
|
+
readonly createdAt: Date | null;
|
|
117
|
+
/**
|
|
118
|
+
* When the CONTENT was last edited, or `null` if never edited (the wire
|
|
119
|
+
* omits the key; the SDK normalizes to an explicit null, discord.js
|
|
120
|
+
* editedTimestamp-style). Component-only updates never set this.
|
|
121
|
+
*/
|
|
122
|
+
readonly editedAt: Date | null;
|
|
123
|
+
/** Users mentioned in this message (from `mentions`). */
|
|
124
|
+
readonly mentions: {
|
|
125
|
+
id: string;
|
|
126
|
+
username: string | null;
|
|
127
|
+
}[];
|
|
128
|
+
/** Role ids mentioned in this message (from `mention_role_ids`). */
|
|
129
|
+
readonly mentionRoleIds: string[];
|
|
130
|
+
/** `true` if this message mentions `@everyone`/`@here`. */
|
|
131
|
+
readonly mentionEveryone: boolean;
|
|
132
|
+
/** Files attached to this message. */
|
|
133
|
+
readonly attachments: MessageAttachment[];
|
|
134
|
+
/** Embeds on this message — the flattened received shape (see {@link MessageEmbed}). */
|
|
135
|
+
readonly embeds: MessageEmbed[];
|
|
136
|
+
/**
|
|
137
|
+
* `true` if the message was pinned when this payload was produced.
|
|
138
|
+
* Fetched history (`fetchMessages`) carries pin state; a live
|
|
139
|
+
* `messageCreate` is always `false` (a new message can't be pinned
|
|
140
|
+
* yet). Track later changes via `messagePin` / `messageUnpin`.
|
|
141
|
+
*/
|
|
142
|
+
readonly pinned: boolean;
|
|
143
|
+
/** Pointer at another message (reply/forward/pin), or `null`. */
|
|
144
|
+
readonly reference: MessageReference | null;
|
|
145
|
+
/** Thread badge — `null` unless this message has (or had) a thread. */
|
|
146
|
+
readonly thread: MessageThread | null;
|
|
147
|
+
/** The raw wire payload, for anything the typed surface doesn't expose yet. */
|
|
148
|
+
readonly raw: any;
|
|
149
|
+
constructor(client: Client, data: any);
|
|
150
|
+
/**
|
|
151
|
+
* Compat alias (discord.js-style): the id of the message this one replies
|
|
152
|
+
* to, or `null`. Derived from {@link reference} — prefer that for new code;
|
|
153
|
+
* forwards and pins are not surfaced here.
|
|
154
|
+
*/
|
|
155
|
+
get replyToId(): string | null;
|
|
156
|
+
/**
|
|
157
|
+
* The channel this message was sent in. Resolved from the SDK's name
|
|
158
|
+
* cache when available (`.name` populated); falls back to a minimal
|
|
159
|
+
* handle (`.name === null`) that still supports `.send()` while the
|
|
160
|
+
* cache lazily fills in the background.
|
|
161
|
+
*/
|
|
162
|
+
get channel(): Channel;
|
|
163
|
+
/** The server this message was sent in, or `null` in a DM. Resolved from the SDK's cache. */
|
|
164
|
+
get server(): Server | null;
|
|
165
|
+
/** Reply to this message (threads it via `reply_to`). */
|
|
166
|
+
reply(content: Sendable): Promise<any>;
|
|
167
|
+
/** Delete this message (needs MANAGE_MESSAGES, or it's the bot's own). */
|
|
168
|
+
delete(): Promise<any>;
|
|
169
|
+
/** React to this message. */
|
|
170
|
+
react(emoji: string): Promise<any>;
|
|
171
|
+
/** Remove the bot's own reaction from this message. */
|
|
172
|
+
removeReaction(emoji: string): Promise<any>;
|
|
173
|
+
/** Edit this message's content. Own messages only (403 otherwise). */
|
|
174
|
+
edit(content: string): Promise<any>;
|
|
175
|
+
/** Pin this message. */
|
|
176
|
+
pin(): Promise<any>;
|
|
177
|
+
/** Unpin this message. */
|
|
178
|
+
unpin(): Promise<any>;
|
|
179
|
+
/** The author as a server member (with `addRole`/`removeRole`), or null in DMs. */
|
|
180
|
+
get member(): Member | null;
|
|
181
|
+
}
|