lunibee 0.1.8 → 0.2.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 +2 -0
- package/dist/builders/components.d.ts +5 -0
- package/dist/builders/index.js +72 -12
- package/dist/builders/index.js.map +5 -5
- package/dist/collection/index.d.ts +68 -1
- package/dist/collection/index.js +334 -1
- package/dist/collection/index.js.map +3 -3
- package/dist/core/collector.d.ts +13 -0
- package/dist/core/events.d.ts +29 -3
- package/dist/core/index.d.ts +22 -8
- package/dist/core/index.js +1526 -124
- package/dist/core/index.js.map +26 -22
- package/dist/core/permissions.d.ts +48 -0
- package/dist/index.js +1578 -268
- package/dist/index.js.map +30 -29
- package/dist/managers/advanced.d.ts +116 -0
- package/dist/managers/base.d.ts +13 -2
- package/dist/managers/emoji.d.ts +1 -1
- package/dist/managers/guild.d.ts +28 -2
- package/dist/managers/index.d.ts +37 -5
- package/dist/managers/index.js +870 -152
- package/dist/managers/index.js.map +18 -16
- package/dist/managers/message.d.ts +10 -1
- package/dist/rest/errors.d.ts +33 -0
- package/dist/rest/index.d.ts +1 -1
- package/dist/rest/index.js +52 -6
- package/dist/rest/index.js.map +5 -5
- package/dist/rest/routes.d.ts +20 -0
- package/dist/sharding/index.d.ts +29 -0
- package/dist/sharding/index.js +99 -15
- package/dist/sharding/index.js.map +8 -8
- package/dist/structures/base.d.ts +2 -0
- package/dist/structures/index.js +96 -42
- package/dist/structures/index.js.map +10 -9
- package/dist/structures/interactions.d.ts +26 -0
- package/dist/types/gateway.d.ts +16 -0
- package/dist/types/index.d.ts +55 -1
- package/dist/types/index.js.map +2 -2
- package/dist/voice/index.d.ts +3 -0
- package/dist/voice/index.js +15 -1
- package/dist/voice/index.js.map +3 -3
- package/dist/ws/index.js +13 -5
- package/dist/ws/index.js.map +6 -6
- package/package.json +14 -14
package/dist/sharding/index.js
CHANGED
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
// packages/sharding/package.json
|
|
3
|
+
var package_default = {
|
|
4
|
+
name: "@lunibee/sharding",
|
|
5
|
+
version: "0.2.0",
|
|
6
|
+
type: "module",
|
|
7
|
+
module: "./src/index.ts",
|
|
8
|
+
types: "./src/index.ts",
|
|
9
|
+
exports: {
|
|
10
|
+
".": "./src/index.ts"
|
|
11
|
+
},
|
|
12
|
+
dependencies: {
|
|
13
|
+
"@lunibee/ws": "workspace:*"
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
2
17
|
// packages/ws/src/session.ts
|
|
3
18
|
class GatewaySession {
|
|
4
19
|
#state = { status: "none" };
|
|
@@ -34,6 +49,8 @@ class GatewaySession {
|
|
|
34
49
|
return false;
|
|
35
50
|
if (!Number.isInteger(sequence))
|
|
36
51
|
return false;
|
|
52
|
+
if (this.#sequence !== null && sequence < this.#sequence)
|
|
53
|
+
return false;
|
|
37
54
|
this.#sequence = sequence;
|
|
38
55
|
return true;
|
|
39
56
|
}
|
|
@@ -132,8 +149,11 @@ class GatewayHeartbeat {
|
|
|
132
149
|
this.#clearBeatTimers();
|
|
133
150
|
this.#interval = interval;
|
|
134
151
|
this.#acknowledged = true;
|
|
135
|
-
this.#initialTimer = setTimeout(() =>
|
|
136
|
-
|
|
152
|
+
this.#initialTimer = setTimeout(() => {
|
|
153
|
+
this.#initialTimer = undefined;
|
|
154
|
+
this.sendHeartbeat();
|
|
155
|
+
this.#timer = setInterval(() => this.sendHeartbeat(), interval);
|
|
156
|
+
}, Math.random() * interval);
|
|
137
157
|
}
|
|
138
158
|
stop() {
|
|
139
159
|
this.#clearBeatTimers();
|
|
@@ -159,6 +179,8 @@ class GatewayHeartbeat {
|
|
|
159
179
|
}, this.#options.ackTimeout);
|
|
160
180
|
}
|
|
161
181
|
acknowledge() {
|
|
182
|
+
if (this.#acknowledged)
|
|
183
|
+
return;
|
|
162
184
|
this.#acknowledged = true;
|
|
163
185
|
this.#latency = this.#now() - this.#sentAt;
|
|
164
186
|
this.#clearAckTimer();
|
|
@@ -804,6 +826,7 @@ class SendBudget {
|
|
|
804
826
|
}
|
|
805
827
|
|
|
806
828
|
// packages/ws/src/index.ts
|
|
829
|
+
var RESUMABLE_CLOSE_CODE = 4900;
|
|
807
830
|
var DEFAULT_GATEWAY_URL = "wss://gateway.discord.gg/?v=10&encoding=json";
|
|
808
831
|
|
|
809
832
|
class Gateway {
|
|
@@ -889,7 +912,7 @@ class Gateway {
|
|
|
889
912
|
} else {
|
|
890
913
|
this.#emitError(new GatewayError(`Gateway heartbeat acknowledgement timed out after ${timeout.elapsedMs}ms.`));
|
|
891
914
|
}
|
|
892
|
-
this.#transport.close(
|
|
915
|
+
this.#transport.close(RESUMABLE_CLOSE_CODE, timeout.type === "zombie" ? "Zombie Gateway connection" : "Heartbeat timeout");
|
|
893
916
|
}
|
|
894
917
|
connect(url = DEFAULT_GATEWAY_URL) {
|
|
895
918
|
if (this.state === "CLOSED" /* Closed */)
|
|
@@ -1025,7 +1048,7 @@ class Gateway {
|
|
|
1025
1048
|
this.#emit("heartbeatAck", action.data);
|
|
1026
1049
|
return;
|
|
1027
1050
|
case "reconnect":
|
|
1028
|
-
this.#transport.close(
|
|
1051
|
+
this.#transport.close(RESUMABLE_CLOSE_CODE, "Server requested reconnect");
|
|
1029
1052
|
return;
|
|
1030
1053
|
case "invalid-session": {
|
|
1031
1054
|
if (!action.resumable)
|
|
@@ -1326,7 +1349,7 @@ class ClusterManager {
|
|
|
1326
1349
|
const response = await fetch("https://discord.com/api/v10/gateway/bot", {
|
|
1327
1350
|
headers: {
|
|
1328
1351
|
Authorization: `Bot ${this.#options.token}`,
|
|
1329
|
-
"User-Agent":
|
|
1352
|
+
"User-Agent": `Lunibee/${package_default.version}`
|
|
1330
1353
|
}
|
|
1331
1354
|
});
|
|
1332
1355
|
if (!response.ok) {
|
|
@@ -1477,6 +1500,34 @@ class ClusterManager {
|
|
|
1477
1500
|
|
|
1478
1501
|
// packages/sharding/src/index.ts
|
|
1479
1502
|
var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
1503
|
+
function needsConnection(gateway) {
|
|
1504
|
+
return gateway.state === "CONNECT" /* Connect */ || gateway.state === "RECONNECT" /* Reconnect */ || gateway.state === "CLOSED" /* Closed */;
|
|
1505
|
+
}
|
|
1506
|
+
var HANDSHAKE_SENT = new Set([
|
|
1507
|
+
"IDENTIFY" /* Identify */,
|
|
1508
|
+
"RESUME" /* Resume */,
|
|
1509
|
+
"READY" /* Ready */,
|
|
1510
|
+
"DISPATCH" /* Dispatch */,
|
|
1511
|
+
"HEARTBEAT" /* Heartbeat */,
|
|
1512
|
+
"CLOSED" /* Closed */
|
|
1513
|
+
]);
|
|
1514
|
+
function handshakeSent(gateway, timeout) {
|
|
1515
|
+
if (HANDSHAKE_SENT.has(gateway.state))
|
|
1516
|
+
return Promise.resolve();
|
|
1517
|
+
return new Promise((resolve) => {
|
|
1518
|
+
const done = () => {
|
|
1519
|
+
clearTimeout(timer);
|
|
1520
|
+
gateway.off("stateChange", onState);
|
|
1521
|
+
resolve();
|
|
1522
|
+
};
|
|
1523
|
+
const onState = (change) => {
|
|
1524
|
+
if (HANDSHAKE_SENT.has(change.next))
|
|
1525
|
+
done();
|
|
1526
|
+
};
|
|
1527
|
+
const timer = setTimeout(done, timeout);
|
|
1528
|
+
gateway.on("stateChange", onState);
|
|
1529
|
+
});
|
|
1530
|
+
}
|
|
1480
1531
|
|
|
1481
1532
|
class ShardManager {
|
|
1482
1533
|
static IDENTIFY_INTERVAL = 5000;
|
|
@@ -1489,6 +1540,7 @@ class ShardManager {
|
|
|
1489
1540
|
#destroyed = false;
|
|
1490
1541
|
#auto;
|
|
1491
1542
|
#autoScaleTimer;
|
|
1543
|
+
#gatewayInfo;
|
|
1492
1544
|
constructor(options) {
|
|
1493
1545
|
if (!options.token?.trim())
|
|
1494
1546
|
throw new TypeError("A Discord bot token is required.");
|
|
@@ -1501,6 +1553,10 @@ class ShardManager {
|
|
|
1501
1553
|
throw new RangeError("autoScaleInterval must be an integer of at least 1000 milliseconds.");
|
|
1502
1554
|
if (options.spawnDelay !== undefined && (!Number.isFinite(options.spawnDelay) || options.spawnDelay < 0))
|
|
1503
1555
|
throw new RangeError("spawnDelay must be a non-negative finite number of milliseconds.");
|
|
1556
|
+
if (options.maxConcurrency !== undefined && (!Number.isInteger(options.maxConcurrency) || options.maxConcurrency < 1))
|
|
1557
|
+
throw new RangeError("maxConcurrency must be a positive integer.");
|
|
1558
|
+
if (options.handshakeTimeout !== undefined && (!Number.isFinite(options.handshakeTimeout) || options.handshakeTimeout < 0))
|
|
1559
|
+
throw new RangeError("handshakeTimeout must be a non-negative number of milliseconds.");
|
|
1504
1560
|
this.#auto = options.shardCount === "auto";
|
|
1505
1561
|
this.#options = {
|
|
1506
1562
|
spawnDelay: ShardManager.IDENTIFY_INTERVAL,
|
|
@@ -1510,10 +1566,13 @@ class ShardManager {
|
|
|
1510
1566
|
this.#initialize(count);
|
|
1511
1567
|
}
|
|
1512
1568
|
async fetchRecommendedShardCount() {
|
|
1569
|
+
return (await this.fetchGatewayInfo()).shards;
|
|
1570
|
+
}
|
|
1571
|
+
async fetchGatewayInfo() {
|
|
1513
1572
|
const response = await fetch("https://discord.com/api/v10/gateway/bot", {
|
|
1514
1573
|
headers: {
|
|
1515
1574
|
Authorization: `Bot ${this.#options.token}`,
|
|
1516
|
-
"User-Agent":
|
|
1575
|
+
"User-Agent": `Lunibee/${package_default.version}`
|
|
1517
1576
|
}
|
|
1518
1577
|
});
|
|
1519
1578
|
if (!response.ok)
|
|
@@ -1521,7 +1580,17 @@ class ShardManager {
|
|
|
1521
1580
|
const data = await response.json();
|
|
1522
1581
|
if (typeof data.shards !== "number" || !Number.isInteger(data.shards) || data.shards < 1)
|
|
1523
1582
|
throw new Error("Gateway discovery returned an invalid shard count.");
|
|
1524
|
-
|
|
1583
|
+
const limit = data.session_start_limit;
|
|
1584
|
+
const info = { shards: data.shards };
|
|
1585
|
+
if (limit && typeof limit.total === "number" && typeof limit.remaining === "number" && typeof limit.reset_after === "number" && typeof limit.max_concurrency === "number")
|
|
1586
|
+
info.sessionStartLimit = {
|
|
1587
|
+
total: limit.total,
|
|
1588
|
+
remaining: limit.remaining,
|
|
1589
|
+
resetAfter: limit.reset_after,
|
|
1590
|
+
maxConcurrency: Math.max(1, limit.max_concurrency)
|
|
1591
|
+
};
|
|
1592
|
+
this.#gatewayInfo = info;
|
|
1593
|
+
return info;
|
|
1525
1594
|
}
|
|
1526
1595
|
async connect() {
|
|
1527
1596
|
if (this.#autoScaleTimer) {
|
|
@@ -1529,17 +1598,25 @@ class ShardManager {
|
|
|
1529
1598
|
this.#autoScaleTimer = undefined;
|
|
1530
1599
|
}
|
|
1531
1600
|
await this.#ensureInitialized();
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
}
|
|
1601
|
+
const limit = this.#gatewayInfo?.sessionStartLimit;
|
|
1602
|
+
const ids = [...this.shards].filter(([, gateway]) => needsConnection(gateway)).map(([id]) => id);
|
|
1603
|
+
if (limit && limit.remaining < ids.length)
|
|
1604
|
+
throw new Error(`Session start limit exhausted: ${limit.remaining} of ${limit.total} IDENTIFYs left for ${ids.length} shards; resets in ${Math.ceil(limit.resetAfter / 1000)}s.`);
|
|
1605
|
+
const concurrency = Math.min(this.#options.maxConcurrency ?? limit?.maxConcurrency ?? 1, limit?.maxConcurrency ?? Infinity);
|
|
1606
|
+
for (let start = 0;start < ids.length; start += concurrency) {
|
|
1607
|
+
const round = ids.slice(start, start + concurrency);
|
|
1608
|
+
const results = await Promise.allSettled(round.map((id) => this.shards.get(id).connect()));
|
|
1609
|
+
const failed = results.findIndex((result) => result.status === "rejected");
|
|
1610
|
+
if (failed !== -1) {
|
|
1536
1611
|
this.destroy();
|
|
1537
|
-
throw new Error(`Failed to connect shard ${
|
|
1538
|
-
cause:
|
|
1612
|
+
throw new Error(`Failed to connect shard ${round[failed]}.`, {
|
|
1613
|
+
cause: results[failed].reason
|
|
1539
1614
|
});
|
|
1540
1615
|
}
|
|
1541
|
-
if (
|
|
1616
|
+
if (start + concurrency < ids.length && this.#options.spawnDelay && this.#options.spawnDelay > 0) {
|
|
1617
|
+
await Promise.all(round.map((id) => handshakeSent(this.shards.get(id), this.#options.handshakeTimeout ?? 15000)));
|
|
1542
1618
|
await sleep2(this.#options.spawnDelay);
|
|
1619
|
+
}
|
|
1543
1620
|
}
|
|
1544
1621
|
if (this.#options.autoScaleInterval && !this.#autoScaleTimer) {
|
|
1545
1622
|
this.#autoScaleTimer = setInterval(() => {
|
|
@@ -1582,6 +1659,13 @@ class ShardManager {
|
|
|
1582
1659
|
get(id) {
|
|
1583
1660
|
return this.shards.get(id);
|
|
1584
1661
|
}
|
|
1662
|
+
health() {
|
|
1663
|
+
return [...this.shards].map(([id, gateway]) => ({
|
|
1664
|
+
id,
|
|
1665
|
+
state: gateway.state,
|
|
1666
|
+
ping: gateway.ping
|
|
1667
|
+
}));
|
|
1668
|
+
}
|
|
1585
1669
|
values() {
|
|
1586
1670
|
return [...this.shards].map(([id, gateway]) => ({ id, gateway }));
|
|
1587
1671
|
}
|
|
@@ -1617,4 +1701,4 @@ export {
|
|
|
1617
1701
|
ShardManager as ShardingManager
|
|
1618
1702
|
};
|
|
1619
1703
|
|
|
1620
|
-
//# debugId=
|
|
1704
|
+
//# debugId=80E4CAFE56ABED2364756E2164756E21
|