guilds.js 0.0.0 → 0.0.2

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 CHANGED
@@ -175,7 +175,7 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
175
175
 
176
176
  END OF TERMS AND CONDITIONS
177
177
 
178
- Copyright 2026 Andrew (e60m5ss / wlix)
178
+ Copyright 2026 Andrew (andrewdku / wlix)
179
179
 
180
180
  Licensed under the Apache License, Version 2.0 (the "License");
181
181
  you may not use this file except in compliance with the License.
package/README.md ADDED
@@ -0,0 +1,52 @@
1
+ <p align="center">
2
+ <img src="public/logo.png" alt="guilds.js Logo" width="85" />
3
+ </p>
4
+
5
+ <div align="center">
6
+ <a href="https://github.com/andrewdku/guilds.js">GitHub</a> |
7
+ <a href="https://npmjs.com/package/guilds.js">npm</a>
8
+ </div>
9
+ <h1 align="center">guilds.js</h1>
10
+
11
+ > Interact with Discord's API with ease
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install guilds.js
17
+ # or
18
+ yarn add guilds.js
19
+ # or
20
+ pnpm add guilds.js
21
+ # or
22
+ bun add guilds.js
23
+ ```
24
+
25
+ ## Example
26
+
27
+ ```js
28
+ import { Client } from "guilds.js";
29
+
30
+ const client = new Client({
31
+ // https://discord.com/developers/applications
32
+ token: "bot token",
33
+
34
+ // client intents (as a number)
35
+ intents: 0,
36
+ });
37
+
38
+ client.once("ready", () => {
39
+ console.log("Client is ready!");
40
+ });
41
+
42
+ // start connection to Discord gateway
43
+ client.connect();
44
+ ```
45
+
46
+ # Contributing
47
+
48
+ [pnpm](https://pnpm.io) is used throughout this project for packages and scripts. Pull requests are always welcome. For major changes, please open an issue to discuss what you wish to change.
49
+
50
+ # License
51
+
52
+ guilds.js is licensed under the [Apache 2.0 license](LICENSE).
package/dist/index.cjs ADDED
@@ -0,0 +1,238 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ //#region src/utils/constants.ts
4
+ const activityTypes = {
5
+ Competing: 5,
6
+ Custom: 4,
7
+ Listening: 2,
8
+ Playing: 0,
9
+ Streaming: 1,
10
+ Watching: 3
11
+ };
12
+ const baseApiUrl = "https://discord.com/api/v10";
13
+ const errorCodes = [
14
+ "ClientIntentsError",
15
+ "ClientPropsError",
16
+ "ClientTokenError",
17
+ "DiscordAPIError",
18
+ "GatewayError",
19
+ "WebSocketError"
20
+ ];
21
+ const opCodes = {
22
+ Dispatch: 0,
23
+ Heartbeat: 1,
24
+ HeartbeatACK: 11,
25
+ Hello: 10,
26
+ Identify: 2,
27
+ InvalidSession: 9,
28
+ PresenceUpdate: 3,
29
+ Reconnect: 7,
30
+ RequestGuildMembers: 8,
31
+ RequestSoundboardSounds: 12,
32
+ Resume: 6,
33
+ VoiceStateUpdate: 3
34
+ };
35
+
36
+ //#endregion
37
+ //#region src/classes/EventHandler.ts
38
+ var EventHandler = class {
39
+ #listeners = {};
40
+ on(event, listener) {
41
+ if (!this.#listeners[event]) this.#listeners[event] = [];
42
+ this.#listeners[event].push(listener);
43
+ return this;
44
+ }
45
+ once(event, listener) {
46
+ const wrapped = (...args) => {
47
+ listener(...args);
48
+ this.off(event, wrapped);
49
+ };
50
+ this.on(event, wrapped);
51
+ return this;
52
+ }
53
+ off(event, listener) {
54
+ if (!this.#listeners[event]) return this;
55
+ this.#listeners[event] = this.#listeners[event].filter((l) => l !== listener);
56
+ return this;
57
+ }
58
+ async emit(event, ...args) {
59
+ if (!this.#listeners[event]) return false;
60
+ for (const listener of this.#listeners[event]) await listener(...args);
61
+ return true;
62
+ }
63
+ };
64
+
65
+ //#endregion
66
+ //#region src/classes/GuildsError.ts
67
+ var GuildsError = class extends Error {
68
+ static name = "GuildsError";
69
+ scope;
70
+ get name() {
71
+ return this.scope ? `${this.constructor.name} (${this.scope})` : this.constructor.name;
72
+ }
73
+ constructor(message, scope) {
74
+ super(message);
75
+ if (scope) this.scope = scope;
76
+ Error.captureStackTrace?.(this, this.constructor);
77
+ }
78
+ };
79
+
80
+ //#endregion
81
+ //#region src/classes/Routes.ts
82
+ var Routes = class {
83
+ static gateway(bot = false) {
84
+ return `${baseApiUrl}/gateway${bot ? "/bot" : ""}`;
85
+ }
86
+ static user(userId = "@me") {
87
+ return `${baseApiUrl}/users/${userId}`;
88
+ }
89
+ };
90
+
91
+ //#endregion
92
+ //#region src/classes/DiscordAPI.ts
93
+ var DiscordAPI = class {
94
+ #token;
95
+ constructor(token) {
96
+ if (!token) throw new GuildsError("Token must be provided", "DiscordAPIError");
97
+ this.#token = token;
98
+ }
99
+ get token() {
100
+ return this.#token;
101
+ }
102
+ async get(input, init) {
103
+ return await fetch(input, init);
104
+ }
105
+ };
106
+
107
+ //#endregion
108
+ //#region src/classes/Client.ts
109
+ var Client = class extends EventHandler {
110
+ #api;
111
+ #token;
112
+ #heartbeatInterval;
113
+ #presence = {
114
+ platform: "desktop",
115
+ status: "online",
116
+ activities: []
117
+ };
118
+ #sequenceNumber = null;
119
+ #sessionId;
120
+ #intents;
121
+ #ready = false;
122
+ #ws;
123
+ get token() {
124
+ return this.#token;
125
+ }
126
+ get intents() {
127
+ return this.#intents;
128
+ }
129
+ get heartbeatInterval() {
130
+ return this.#heartbeatInterval;
131
+ }
132
+ get presence() {
133
+ return this.#presence;
134
+ }
135
+ isReady() {
136
+ return this.#ready;
137
+ }
138
+ constructor(props) {
139
+ super();
140
+ if (!props || typeof props !== "object") throw new GuildsError("Invalid client props were provided", "ClientPropsError");
141
+ if (!props.token || typeof props.token !== "string") throw new GuildsError("Invalid token was provided", "ClientTokenError");
142
+ if (!props.intents || typeof props.intents !== "number") throw new GuildsError("Invalid intents were provided", "ClientIntentsError");
143
+ if (props.presence) {
144
+ if (typeof props.presence !== "object") throw new GuildsError("Invalid client presence was provided", "ClientPropsError");
145
+ this.setPresence(props.presence);
146
+ }
147
+ this.#token = props.token.trim().toLowerCase().startsWith("bot ") ? props.token : `Bot ${props.token}`;
148
+ this.#intents = props.intents;
149
+ this.#api = new DiscordAPI(this.#token);
150
+ return this;
151
+ }
152
+ async connect() {
153
+ const res = await this.#api.get(Routes.gateway(true));
154
+ const userRes = await this.#api.get(Routes.user());
155
+ if (!res.ok || !userRes.ok || !res || !userRes) throw new GuildsError("Failed to connect to Discord", "GatewayError");
156
+ const data = await res.json();
157
+ this.#ws = new WebSocket(`${data.url}?v=10&encoding=json`);
158
+ this.#ws.onmessage = (event) => {
159
+ this.#handleGatewayEvent(JSON.parse(event.data.toString()));
160
+ };
161
+ return this;
162
+ }
163
+ #handleGatewayEvent(payload) {
164
+ if (payload.s !== void 0 && payload.s !== null) this.#sequenceNumber = payload.s;
165
+ switch (payload.op) {
166
+ case opCodes.Hello:
167
+ this.emit("debug", "Received Hello event");
168
+ this.#heartbeatInterval = setInterval(() => {
169
+ this.#ws?.send(JSON.stringify({
170
+ op: opCodes.Heartbeat,
171
+ d: this.#sequenceNumber
172
+ }));
173
+ }, payload.d.heartbeat_interval);
174
+ this.emit("debug", "Identifying...");
175
+ this.#ws?.send(JSON.stringify({
176
+ op: opCodes.Identify,
177
+ d: {
178
+ token: this.#token,
179
+ intents: this.#intents,
180
+ presence: this.#presence,
181
+ properties: this.#presence.platform === "desktop" ? {
182
+ $os: "linux",
183
+ $browser: "guilds.js",
184
+ $device: "guilds.js"
185
+ } : {
186
+ $os: "Discord Android",
187
+ $browser: "Discord Android",
188
+ $device: "Discord Android"
189
+ }
190
+ }
191
+ }));
192
+ break;
193
+ case opCodes.Dispatch:
194
+ if (payload.t !== "READY") break;
195
+ this.#sessionId = payload.d.session_id;
196
+ this.#ready = true;
197
+ this.emit("ready", this);
198
+ break;
199
+ }
200
+ }
201
+ setPresence(presence) {
202
+ this.#presence = {
203
+ ...this.#presence,
204
+ ...presence
205
+ };
206
+ if (this.#ws) this.#ws.send(JSON.stringify({
207
+ op: opCodes.PresenceUpdate,
208
+ d: {
209
+ status: this.#presence.status,
210
+ since: null,
211
+ afk: false,
212
+ activities: (this.#presence.activities ?? []).map((a) => ({
213
+ ...a,
214
+ type: typeof a.type === "string" ? activityTypes[a.type] : a.type
215
+ }))
216
+ }
217
+ }));
218
+ return this;
219
+ }
220
+ async disconnect() {
221
+ if (this.#heartbeatInterval) clearInterval(this.#heartbeatInterval);
222
+ if (this.#ws) {
223
+ this.#ws.close(1e3, "Client disconnected");
224
+ this.#ws = void 0;
225
+ }
226
+ }
227
+ };
228
+
229
+ //#endregion
230
+ exports.Client = Client;
231
+ exports.DiscordAPI = DiscordAPI;
232
+ exports.EventHandler = EventHandler;
233
+ exports.GuildsError = GuildsError;
234
+ exports.Routes = Routes;
235
+ exports.activityTypes = activityTypes;
236
+ exports.baseApiUrl = baseApiUrl;
237
+ exports.errorCodes = errorCodes;
238
+ exports.opCodes = opCodes;
@@ -0,0 +1,106 @@
1
+ //#region src/utils/constants.d.ts
2
+ declare const activityTypes: {
3
+ readonly Competing: 5;
4
+ readonly Custom: 4;
5
+ readonly Listening: 2;
6
+ readonly Playing: 0;
7
+ readonly Streaming: 1;
8
+ readonly Watching: 3;
9
+ };
10
+ declare const baseApiUrl = "https://discord.com/api/v10";
11
+ declare const errorCodes: readonly ["ClientIntentsError", "ClientPropsError", "ClientTokenError", "DiscordAPIError", "GatewayError", "WebSocketError"];
12
+ declare const opCodes: {
13
+ readonly Dispatch: 0;
14
+ readonly Heartbeat: 1;
15
+ readonly HeartbeatACK: 11;
16
+ readonly Hello: 10;
17
+ readonly Identify: 2;
18
+ readonly InvalidSession: 9;
19
+ readonly PresenceUpdate: 3;
20
+ readonly Reconnect: 7;
21
+ readonly RequestGuildMembers: 8;
22
+ readonly RequestSoundboardSounds: 12;
23
+ readonly Resume: 6;
24
+ readonly VoiceStateUpdate: 3;
25
+ };
26
+ //#endregion
27
+ //#region src/classes/EventHandler.d.ts
28
+ declare class EventHandler<Events extends Record<string, any[]>> {
29
+ #private;
30
+ on<K extends keyof Events>(event: K, listener: (...args: Events[K]) => any): this;
31
+ once<K extends keyof Events>(event: K, listener: (...args: Events[K]) => any): this;
32
+ off<K extends keyof Events>(event: K, listener: (...args: Events[K]) => any): this;
33
+ emit<K extends keyof Events>(event: K, ...args: Events[K]): Promise<boolean>;
34
+ }
35
+ //#endregion
36
+ //#region src/classes/GuildsError.d.ts
37
+ declare class GuildsError extends Error {
38
+ static name: string;
39
+ readonly scope?: ErrorCode;
40
+ get name(): string;
41
+ constructor(message: string, scope?: ErrorCode);
42
+ }
43
+ //#endregion
44
+ //#region src/classes/Routes.d.ts
45
+ declare class Routes {
46
+ static gateway(bot?: boolean): "https://discord.com/api/v10/gateway/bot" | "https://discord.com/api/v10/gateway";
47
+ static user(userId?: string): `https://discord.com/api/v10/users/${string}`;
48
+ }
49
+ //#endregion
50
+ //#region src/classes/DiscordAPI.d.ts
51
+ declare class DiscordAPI {
52
+ #private;
53
+ constructor(token: string);
54
+ get token(): string;
55
+ get(input: string | URL | Request, init?: RequestInit): Promise<Response>;
56
+ }
57
+ //#endregion
58
+ //#region src/classes/Client.d.ts
59
+ declare class Client<Ready extends boolean = false> extends EventHandler<ClientEvents> {
60
+ #private;
61
+ get token(): string;
62
+ get intents(): number;
63
+ get heartbeatInterval(): NodeJS.Timeout | undefined;
64
+ get presence(): ClientPresence;
65
+ isReady(): this is Client<true>;
66
+ constructor(props: ClientProps);
67
+ connect(): Promise<Client<true>>;
68
+ setPresence(presence: Partial<ClientPresence>): this;
69
+ disconnect(): Promise<void>;
70
+ }
71
+ //#endregion
72
+ //#region src/types.d.ts
73
+ type ActivityType = keyof typeof activityTypes | (typeof activityTypes)[keyof typeof activityTypes];
74
+ type ClientEvents = {
75
+ debug: [message: string];
76
+ error: [error: any];
77
+ ready: [readyClient: Client<true>];
78
+ };
79
+ interface ClientPresence {
80
+ activities: ClientActivity[];
81
+ platform: "desktop" | "mobile";
82
+ status: UserStatus;
83
+ }
84
+ interface ClientActivity {
85
+ name: string;
86
+ state?: string;
87
+ type: ActivityType;
88
+ url?: string;
89
+ }
90
+ interface ClientPresence {}
91
+ interface ClientProps {
92
+ token: string;
93
+ intents: number;
94
+ presence?: Partial<ClientPresence>;
95
+ }
96
+ type ErrorCode = (typeof errorCodes)[keyof typeof errorCodes];
97
+ interface GatewayPayload {
98
+ op: (typeof opCodes)[keyof typeof opCodes];
99
+ d?: any;
100
+ s?: number | null;
101
+ t?: string | null;
102
+ }
103
+ type If<Condition extends boolean, Then, Else = never> = Condition extends true ? Then : Else;
104
+ type UserStatus = "online" | "idle" | "dnd" | "offline";
105
+ //#endregion
106
+ export { ActivityType, Client, ClientActivity, ClientEvents, ClientPresence, ClientProps, DiscordAPI, ErrorCode, EventHandler, GatewayPayload, GuildsError, If, Routes, UserStatus, activityTypes, baseApiUrl, errorCodes, opCodes };
@@ -0,0 +1,106 @@
1
+ //#region src/utils/constants.d.ts
2
+ declare const activityTypes: {
3
+ readonly Competing: 5;
4
+ readonly Custom: 4;
5
+ readonly Listening: 2;
6
+ readonly Playing: 0;
7
+ readonly Streaming: 1;
8
+ readonly Watching: 3;
9
+ };
10
+ declare const baseApiUrl = "https://discord.com/api/v10";
11
+ declare const errorCodes: readonly ["ClientIntentsError", "ClientPropsError", "ClientTokenError", "DiscordAPIError", "GatewayError", "WebSocketError"];
12
+ declare const opCodes: {
13
+ readonly Dispatch: 0;
14
+ readonly Heartbeat: 1;
15
+ readonly HeartbeatACK: 11;
16
+ readonly Hello: 10;
17
+ readonly Identify: 2;
18
+ readonly InvalidSession: 9;
19
+ readonly PresenceUpdate: 3;
20
+ readonly Reconnect: 7;
21
+ readonly RequestGuildMembers: 8;
22
+ readonly RequestSoundboardSounds: 12;
23
+ readonly Resume: 6;
24
+ readonly VoiceStateUpdate: 3;
25
+ };
26
+ //#endregion
27
+ //#region src/classes/EventHandler.d.ts
28
+ declare class EventHandler<Events extends Record<string, any[]>> {
29
+ #private;
30
+ on<K extends keyof Events>(event: K, listener: (...args: Events[K]) => any): this;
31
+ once<K extends keyof Events>(event: K, listener: (...args: Events[K]) => any): this;
32
+ off<K extends keyof Events>(event: K, listener: (...args: Events[K]) => any): this;
33
+ emit<K extends keyof Events>(event: K, ...args: Events[K]): Promise<boolean>;
34
+ }
35
+ //#endregion
36
+ //#region src/classes/GuildsError.d.ts
37
+ declare class GuildsError extends Error {
38
+ static name: string;
39
+ readonly scope?: ErrorCode;
40
+ get name(): string;
41
+ constructor(message: string, scope?: ErrorCode);
42
+ }
43
+ //#endregion
44
+ //#region src/classes/Routes.d.ts
45
+ declare class Routes {
46
+ static gateway(bot?: boolean): "https://discord.com/api/v10/gateway/bot" | "https://discord.com/api/v10/gateway";
47
+ static user(userId?: string): `https://discord.com/api/v10/users/${string}`;
48
+ }
49
+ //#endregion
50
+ //#region src/classes/DiscordAPI.d.ts
51
+ declare class DiscordAPI {
52
+ #private;
53
+ constructor(token: string);
54
+ get token(): string;
55
+ get(input: string | URL | Request, init?: RequestInit): Promise<Response>;
56
+ }
57
+ //#endregion
58
+ //#region src/classes/Client.d.ts
59
+ declare class Client<Ready extends boolean = false> extends EventHandler<ClientEvents> {
60
+ #private;
61
+ get token(): string;
62
+ get intents(): number;
63
+ get heartbeatInterval(): NodeJS.Timeout | undefined;
64
+ get presence(): ClientPresence;
65
+ isReady(): this is Client<true>;
66
+ constructor(props: ClientProps);
67
+ connect(): Promise<Client<true>>;
68
+ setPresence(presence: Partial<ClientPresence>): this;
69
+ disconnect(): Promise<void>;
70
+ }
71
+ //#endregion
72
+ //#region src/types.d.ts
73
+ type ActivityType = keyof typeof activityTypes | (typeof activityTypes)[keyof typeof activityTypes];
74
+ type ClientEvents = {
75
+ debug: [message: string];
76
+ error: [error: any];
77
+ ready: [readyClient: Client<true>];
78
+ };
79
+ interface ClientPresence {
80
+ activities: ClientActivity[];
81
+ platform: "desktop" | "mobile";
82
+ status: UserStatus;
83
+ }
84
+ interface ClientActivity {
85
+ name: string;
86
+ state?: string;
87
+ type: ActivityType;
88
+ url?: string;
89
+ }
90
+ interface ClientPresence {}
91
+ interface ClientProps {
92
+ token: string;
93
+ intents: number;
94
+ presence?: Partial<ClientPresence>;
95
+ }
96
+ type ErrorCode = (typeof errorCodes)[keyof typeof errorCodes];
97
+ interface GatewayPayload {
98
+ op: (typeof opCodes)[keyof typeof opCodes];
99
+ d?: any;
100
+ s?: number | null;
101
+ t?: string | null;
102
+ }
103
+ type If<Condition extends boolean, Then, Else = never> = Condition extends true ? Then : Else;
104
+ type UserStatus = "online" | "idle" | "dnd" | "offline";
105
+ //#endregion
106
+ export { ActivityType, Client, ClientActivity, ClientEvents, ClientPresence, ClientProps, DiscordAPI, ErrorCode, EventHandler, GatewayPayload, GuildsError, If, Routes, UserStatus, activityTypes, baseApiUrl, errorCodes, opCodes };
package/dist/index.mjs ADDED
@@ -0,0 +1,228 @@
1
+ //#region src/utils/constants.ts
2
+ const activityTypes = {
3
+ Competing: 5,
4
+ Custom: 4,
5
+ Listening: 2,
6
+ Playing: 0,
7
+ Streaming: 1,
8
+ Watching: 3
9
+ };
10
+ const baseApiUrl = "https://discord.com/api/v10";
11
+ const errorCodes = [
12
+ "ClientIntentsError",
13
+ "ClientPropsError",
14
+ "ClientTokenError",
15
+ "DiscordAPIError",
16
+ "GatewayError",
17
+ "WebSocketError"
18
+ ];
19
+ const opCodes = {
20
+ Dispatch: 0,
21
+ Heartbeat: 1,
22
+ HeartbeatACK: 11,
23
+ Hello: 10,
24
+ Identify: 2,
25
+ InvalidSession: 9,
26
+ PresenceUpdate: 3,
27
+ Reconnect: 7,
28
+ RequestGuildMembers: 8,
29
+ RequestSoundboardSounds: 12,
30
+ Resume: 6,
31
+ VoiceStateUpdate: 3
32
+ };
33
+
34
+ //#endregion
35
+ //#region src/classes/EventHandler.ts
36
+ var EventHandler = class {
37
+ #listeners = {};
38
+ on(event, listener) {
39
+ if (!this.#listeners[event]) this.#listeners[event] = [];
40
+ this.#listeners[event].push(listener);
41
+ return this;
42
+ }
43
+ once(event, listener) {
44
+ const wrapped = (...args) => {
45
+ listener(...args);
46
+ this.off(event, wrapped);
47
+ };
48
+ this.on(event, wrapped);
49
+ return this;
50
+ }
51
+ off(event, listener) {
52
+ if (!this.#listeners[event]) return this;
53
+ this.#listeners[event] = this.#listeners[event].filter((l) => l !== listener);
54
+ return this;
55
+ }
56
+ async emit(event, ...args) {
57
+ if (!this.#listeners[event]) return false;
58
+ for (const listener of this.#listeners[event]) await listener(...args);
59
+ return true;
60
+ }
61
+ };
62
+
63
+ //#endregion
64
+ //#region src/classes/GuildsError.ts
65
+ var GuildsError = class extends Error {
66
+ static name = "GuildsError";
67
+ scope;
68
+ get name() {
69
+ return this.scope ? `${this.constructor.name} (${this.scope})` : this.constructor.name;
70
+ }
71
+ constructor(message, scope) {
72
+ super(message);
73
+ if (scope) this.scope = scope;
74
+ Error.captureStackTrace?.(this, this.constructor);
75
+ }
76
+ };
77
+
78
+ //#endregion
79
+ //#region src/classes/Routes.ts
80
+ var Routes = class {
81
+ static gateway(bot = false) {
82
+ return `${baseApiUrl}/gateway${bot ? "/bot" : ""}`;
83
+ }
84
+ static user(userId = "@me") {
85
+ return `${baseApiUrl}/users/${userId}`;
86
+ }
87
+ };
88
+
89
+ //#endregion
90
+ //#region src/classes/DiscordAPI.ts
91
+ var DiscordAPI = class {
92
+ #token;
93
+ constructor(token) {
94
+ if (!token) throw new GuildsError("Token must be provided", "DiscordAPIError");
95
+ this.#token = token;
96
+ }
97
+ get token() {
98
+ return this.#token;
99
+ }
100
+ async get(input, init) {
101
+ return await fetch(input, init);
102
+ }
103
+ };
104
+
105
+ //#endregion
106
+ //#region src/classes/Client.ts
107
+ var Client = class extends EventHandler {
108
+ #api;
109
+ #token;
110
+ #heartbeatInterval;
111
+ #presence = {
112
+ platform: "desktop",
113
+ status: "online",
114
+ activities: []
115
+ };
116
+ #sequenceNumber = null;
117
+ #sessionId;
118
+ #intents;
119
+ #ready = false;
120
+ #ws;
121
+ get token() {
122
+ return this.#token;
123
+ }
124
+ get intents() {
125
+ return this.#intents;
126
+ }
127
+ get heartbeatInterval() {
128
+ return this.#heartbeatInterval;
129
+ }
130
+ get presence() {
131
+ return this.#presence;
132
+ }
133
+ isReady() {
134
+ return this.#ready;
135
+ }
136
+ constructor(props) {
137
+ super();
138
+ if (!props || typeof props !== "object") throw new GuildsError("Invalid client props were provided", "ClientPropsError");
139
+ if (!props.token || typeof props.token !== "string") throw new GuildsError("Invalid token was provided", "ClientTokenError");
140
+ if (!props.intents || typeof props.intents !== "number") throw new GuildsError("Invalid intents were provided", "ClientIntentsError");
141
+ if (props.presence) {
142
+ if (typeof props.presence !== "object") throw new GuildsError("Invalid client presence was provided", "ClientPropsError");
143
+ this.setPresence(props.presence);
144
+ }
145
+ this.#token = props.token.trim().toLowerCase().startsWith("bot ") ? props.token : `Bot ${props.token}`;
146
+ this.#intents = props.intents;
147
+ this.#api = new DiscordAPI(this.#token);
148
+ return this;
149
+ }
150
+ async connect() {
151
+ const res = await this.#api.get(Routes.gateway(true));
152
+ const userRes = await this.#api.get(Routes.user());
153
+ if (!res.ok || !userRes.ok || !res || !userRes) throw new GuildsError("Failed to connect to Discord", "GatewayError");
154
+ const data = await res.json();
155
+ this.#ws = new WebSocket(`${data.url}?v=10&encoding=json`);
156
+ this.#ws.onmessage = (event) => {
157
+ this.#handleGatewayEvent(JSON.parse(event.data.toString()));
158
+ };
159
+ return this;
160
+ }
161
+ #handleGatewayEvent(payload) {
162
+ if (payload.s !== void 0 && payload.s !== null) this.#sequenceNumber = payload.s;
163
+ switch (payload.op) {
164
+ case opCodes.Hello:
165
+ this.emit("debug", "Received Hello event");
166
+ this.#heartbeatInterval = setInterval(() => {
167
+ this.#ws?.send(JSON.stringify({
168
+ op: opCodes.Heartbeat,
169
+ d: this.#sequenceNumber
170
+ }));
171
+ }, payload.d.heartbeat_interval);
172
+ this.emit("debug", "Identifying...");
173
+ this.#ws?.send(JSON.stringify({
174
+ op: opCodes.Identify,
175
+ d: {
176
+ token: this.#token,
177
+ intents: this.#intents,
178
+ presence: this.#presence,
179
+ properties: this.#presence.platform === "desktop" ? {
180
+ $os: "linux",
181
+ $browser: "guilds.js",
182
+ $device: "guilds.js"
183
+ } : {
184
+ $os: "Discord Android",
185
+ $browser: "Discord Android",
186
+ $device: "Discord Android"
187
+ }
188
+ }
189
+ }));
190
+ break;
191
+ case opCodes.Dispatch:
192
+ if (payload.t !== "READY") break;
193
+ this.#sessionId = payload.d.session_id;
194
+ this.#ready = true;
195
+ this.emit("ready", this);
196
+ break;
197
+ }
198
+ }
199
+ setPresence(presence) {
200
+ this.#presence = {
201
+ ...this.#presence,
202
+ ...presence
203
+ };
204
+ if (this.#ws) this.#ws.send(JSON.stringify({
205
+ op: opCodes.PresenceUpdate,
206
+ d: {
207
+ status: this.#presence.status,
208
+ since: null,
209
+ afk: false,
210
+ activities: (this.#presence.activities ?? []).map((a) => ({
211
+ ...a,
212
+ type: typeof a.type === "string" ? activityTypes[a.type] : a.type
213
+ }))
214
+ }
215
+ }));
216
+ return this;
217
+ }
218
+ async disconnect() {
219
+ if (this.#heartbeatInterval) clearInterval(this.#heartbeatInterval);
220
+ if (this.#ws) {
221
+ this.#ws.close(1e3, "Client disconnected");
222
+ this.#ws = void 0;
223
+ }
224
+ }
225
+ };
226
+
227
+ //#endregion
228
+ export { Client, DiscordAPI, EventHandler, GuildsError, Routes, activityTypes, baseApiUrl, errorCodes, opCodes };
package/package.json CHANGED
@@ -1,7 +1,71 @@
1
1
  {
2
2
  "name": "guilds.js",
3
- "version": "0.0.0",
3
+ "description": "Interact with Discord's API with ease",
4
+ "version": "0.0.2",
5
+ "license": "Apache-2.0",
6
+ "exports": {
7
+ "default": "./dist/index.cjs",
8
+ "import": "./dist/index.mjs",
9
+ "require": "./dist/index.cjs",
10
+ "types": "./dist/index.d.cts"
11
+ },
12
+ "main": "./dist/index.mjs",
13
+ "module": "./dist/index.mjs",
14
+ "types": "./dist/index.d.mts",
15
+ "type": "module",
16
+ "devDependencies": {
17
+ "@types/node": "^25.3.0",
18
+ "prettier": "^3.8.1",
19
+ "tsdown": "^0.20.3",
20
+ "typescript": "^5.9.3"
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "LICENSE",
25
+ "package.json",
26
+ "public/logo.png",
27
+ "README.md"
28
+ ],
29
+ "keywords": [
30
+ "api",
31
+ "discord",
32
+ "discord-bot",
33
+ "javascript",
34
+ "library",
35
+ "module",
36
+ "node",
37
+ "node-js",
38
+ "npm",
39
+ "pnpm",
40
+ "tsdown",
41
+ "typescript",
42
+ "websocket",
43
+ "ws"
44
+ ],
45
+ "engines": {
46
+ "node": ">=20"
47
+ },
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "https://github.com/andrewdku/guilds"
51
+ },
4
52
  "publishConfig": {
5
53
  "access": "public"
54
+ },
55
+ "prettier": {
56
+ "arrowParens": "always",
57
+ "jsxSingleQuote": false,
58
+ "printWidth": 90,
59
+ "quoteProps": "as-needed",
60
+ "semi": true,
61
+ "singleQuote": false,
62
+ "tabWidth": 4,
63
+ "trailingComma": "es5",
64
+ "useTabs": false
65
+ },
66
+ "scripts": {
67
+ "build": "tsdown",
68
+ "format": "prettier --write . --config package.json --ignore-path .prettierignore",
69
+ "prepublish": "tsdown"
6
70
  }
7
71
  }
Binary file