@squord/sdk 0.0.0-stage → 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.
@@ -0,0 +1,789 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/testing/index.ts
21
+ var testing_exports = {};
22
+ __export(testing_exports, {
23
+ MockGatewayServer: () => MockGatewayServer,
24
+ MockRest: () => MockRest,
25
+ createMockEnvironment: () => createMockEnvironment,
26
+ createMockGateway: () => createMockGateway,
27
+ createMockRest: () => createMockRest,
28
+ fixtures: () => fixtures_exports
29
+ });
30
+ module.exports = __toCommonJS(testing_exports);
31
+
32
+ // src/testing/MockRest.ts
33
+ var API_ERROR_HEADERS = { "x-request-id": "mock-request-id" };
34
+ var MockRest = class {
35
+ routes = [];
36
+ calls = [];
37
+ /** Quando definido, todo request recebe esta resposta (testes de falha). */
38
+ failingHandler = null;
39
+ /** Token esperado no header Authorization (sem o prefixo `Bot `). */
40
+ expectedToken = null;
41
+ /** Registra uma rota. `handler` devolve `{ status, body }` ou o corpo puro (status 200). */
42
+ on(method, pattern, handler) {
43
+ this.routes.push({
44
+ method: method.toUpperCase(),
45
+ pattern,
46
+ segments: pattern.split("/").filter(Boolean),
47
+ handler
48
+ });
49
+ return this;
50
+ }
51
+ get(pattern, handler) {
52
+ return this.on("GET", pattern, handler);
53
+ }
54
+ post(pattern, handler) {
55
+ return this.on("POST", pattern, handler);
56
+ }
57
+ put(pattern, handler) {
58
+ return this.on("PUT", pattern, handler);
59
+ }
60
+ patch(pattern, handler) {
61
+ return this.on("PATCH", pattern, handler);
62
+ }
63
+ delete(pattern, handler) {
64
+ return this.on("DELETE", pattern, handler);
65
+ }
66
+ /** Força falha em todas as requisições (ex.: simular queda de rede). */
67
+ failWith(handler) {
68
+ this.failingHandler = handler;
69
+ }
70
+ /** Volta ao comportamento normal. */
71
+ clearFailure() {
72
+ this.failingHandler = null;
73
+ }
74
+ /** Histórico de chamadas recebidas. */
75
+ get callLog() {
76
+ return this.calls;
77
+ }
78
+ /** Última chamada registrada. */
79
+ get lastCall() {
80
+ return this.calls[this.calls.length - 1];
81
+ }
82
+ /** Remove rotas e histórico. */
83
+ reset() {
84
+ this.routes = [];
85
+ this.calls.length = 0;
86
+ this.failingHandler = null;
87
+ }
88
+ /** A implementação de `fetch` para passar em `new SquordClient({ fetchImpl })`. */
89
+ fetch = async (input, init) => {
90
+ const request = input instanceof Request ? input : new Request(input, init);
91
+ const url = new URL(request.url);
92
+ const method = request.method.toUpperCase();
93
+ let body = void 0;
94
+ const rawBody = init?.body ?? (input instanceof Request ? void 0 : void 0);
95
+ if (rawBody !== void 0 && rawBody !== null) {
96
+ if (typeof rawBody === "string") {
97
+ body = rawBody ? JSON.parse(rawBody) : void 0;
98
+ } else if (rawBody instanceof ArrayBuffer || ArrayBuffer.isView(rawBody)) {
99
+ body = rawBody;
100
+ } else {
101
+ body = rawBody;
102
+ }
103
+ } else if (input instanceof Request) {
104
+ const clone = input.clone();
105
+ const text = await clone.text().catch(() => "");
106
+ if (text) {
107
+ try {
108
+ body = JSON.parse(text);
109
+ } catch {
110
+ body = text;
111
+ }
112
+ }
113
+ }
114
+ const headers = {};
115
+ for (const [key, value] of request.headers) headers[key] = value;
116
+ const call = {
117
+ method,
118
+ path: url.pathname,
119
+ params: {},
120
+ query: url.searchParams,
121
+ body,
122
+ headers,
123
+ requestId: headers["x-request-id"] ?? null
124
+ };
125
+ this.calls.push(call);
126
+ if (this.failingHandler) {
127
+ return this.failingHandler(call);
128
+ }
129
+ if (this.expectedToken) {
130
+ const auth = headers.authorization ?? "";
131
+ if (auth !== `Bot ${this.expectedToken}`) {
132
+ return jsonResponse(401, {
133
+ statusCode: 401,
134
+ code: "INVALID_TOKEN",
135
+ message: "Invalid token"
136
+ });
137
+ }
138
+ }
139
+ const pathSegments = url.pathname.split("/").filter(Boolean);
140
+ for (const route of this.routes) {
141
+ if (route.method !== method) continue;
142
+ const match = matchSegments(route.segments, pathSegments);
143
+ if (!match) continue;
144
+ const matchInfo = {
145
+ params: match,
146
+ query: url.searchParams,
147
+ body,
148
+ call: { ...call, params: match }
149
+ };
150
+ const result = await route.handler(matchInfo);
151
+ const response = result && typeof result === "object" && "status" in result ? result : { status: 200, body: result };
152
+ return jsonResponse(response.status, response.body, response.headers);
153
+ }
154
+ return jsonResponse(404, {
155
+ statusCode: 404,
156
+ code: "NOT_FOUND",
157
+ message: `Rota n\xE3o mockada: ${method} ${url.pathname}`
158
+ });
159
+ };
160
+ };
161
+ function matchSegments(pattern, path) {
162
+ if (pattern.length !== path.length) return null;
163
+ const params = {};
164
+ for (let i = 0; i < pattern.length; i++) {
165
+ const p = pattern[i];
166
+ const s = path[i];
167
+ if (p.startsWith(":")) {
168
+ params[p.slice(1)] = decodeURIComponent(s);
169
+ } else if (p !== s) {
170
+ return null;
171
+ }
172
+ }
173
+ return params;
174
+ }
175
+ function jsonResponse(status, body, headers) {
176
+ const payload = body === void 0 || body === null ? void 0 : JSON.stringify(body);
177
+ return new Response(payload, {
178
+ status,
179
+ headers: {
180
+ ...payload !== void 0 ? { "Content-Type": "application/json" } : {},
181
+ ...API_ERROR_HEADERS,
182
+ ...headers
183
+ }
184
+ });
185
+ }
186
+ function createMockRest(options = {}) {
187
+ const rest = new MockRest();
188
+ if (options.token) rest.expectedToken = options.token;
189
+ return rest;
190
+ }
191
+
192
+ // src/testing/MockGateway.ts
193
+ var MockWebSocket = class _MockWebSocket {
194
+ constructor(server) {
195
+ this.server = server;
196
+ queueMicrotask(() => {
197
+ this.readyState = _MockWebSocket.OPEN;
198
+ this.dispatch("open", {});
199
+ this.server.handleClientOpen(this);
200
+ });
201
+ }
202
+ server;
203
+ static OPEN = 1;
204
+ static CLOSING = 2;
205
+ static CLOSED = 3;
206
+ readyState = 0;
207
+ // CONNECTING
208
+ listeners = /* @__PURE__ */ new Map();
209
+ addEventListener(type, listener) {
210
+ const list = this.listeners.get(type) ?? [];
211
+ list.push(listener);
212
+ this.listeners.set(type, list);
213
+ }
214
+ removeEventListener(type, listener) {
215
+ const list = this.listeners.get(type) ?? [];
216
+ const index = list.indexOf(listener);
217
+ if (index >= 0) list.splice(index, 1);
218
+ }
219
+ dispatch(type, event) {
220
+ for (const listener of [...this.listeners.get(type) ?? []]) {
221
+ listener(event);
222
+ }
223
+ }
224
+ /** Frame do cliente: entrega ao servidor. */
225
+ send(data) {
226
+ if (this.readyState !== _MockWebSocket.OPEN) return;
227
+ if (Buffer.byteLength(data, "utf8") > 65536) {
228
+ this.serverClose(1009, "frame too large");
229
+ return;
230
+ }
231
+ let frame;
232
+ try {
233
+ frame = JSON.parse(data);
234
+ } catch {
235
+ this.serverClose(4002, "decode error");
236
+ return;
237
+ }
238
+ this.server.handleClientFrame(this, frame);
239
+ }
240
+ close(code = 1e3, reason = "") {
241
+ if (this.readyState === _MockWebSocket.CLOSED) return;
242
+ this.readyState = _MockWebSocket.CLOSED;
243
+ this.server.handleClientClose(this, code, reason);
244
+ this.dispatch("close", { code, reason, wasClean: true });
245
+ }
246
+ /** Servidor fecha a conexão. */
247
+ serverClose(code, reason) {
248
+ if (this.readyState === _MockWebSocket.CLOSED) return;
249
+ this.readyState = _MockWebSocket.CLOSED;
250
+ this.server.handleClientClose(this, code, reason, true);
251
+ this.dispatch("close", { code, reason, wasClean: true });
252
+ }
253
+ /** Servidor envia frame. */
254
+ receive(frame) {
255
+ this.dispatch("message", { data: JSON.stringify(frame) });
256
+ }
257
+ };
258
+ var MockGatewayServer = class {
259
+ options;
260
+ sockets = /* @__PURE__ */ new Set();
261
+ eventBuffer = [];
262
+ globalSequence = 0;
263
+ refuseResumePending;
264
+ knownSessionIds = /* @__PURE__ */ new Set();
265
+ constructor(options = {}) {
266
+ this.options = options;
267
+ this.refuseResumePending = options.refuseResumeOnce ?? false;
268
+ }
269
+ /** Fábrica de WebSocket para passar ao cliente. */
270
+ wsFactory = (url) => {
271
+ const pathname = (() => {
272
+ try {
273
+ return new URL(url.replace(/^wss/, "https")).pathname;
274
+ } catch {
275
+ return url;
276
+ }
277
+ })();
278
+ if (!/\/gateway$/.test(pathname)) {
279
+ throw new Error(`MockGateway: caminho inv\xE1lido ${url} (use wss://.../gateway)`);
280
+ }
281
+ return new MockWebSocket(this);
282
+ };
283
+ /** Conexões abertas no momento. */
284
+ get connectionCount() {
285
+ return this.sockets.size;
286
+ }
287
+ /** Última sequência emitida. */
288
+ get lastSequence() {
289
+ return this.eventBuffer.length > 0 ? this.eventBuffer[this.eventBuffer.length - 1].s : 0;
290
+ }
291
+ /** Total de eventos já emitidos. */
292
+ get totalEvents() {
293
+ return this.globalSequence;
294
+ }
295
+ /**
296
+ * Emite um evento durável: guarda no buffer (sequência crescente) e
297
+ * entrega às conexões autenticadas.
298
+ */
299
+ emitEvent(type, d) {
300
+ const s = ++this.globalSequence;
301
+ this.eventBuffer.push({ type, d, s });
302
+ if (this.eventBuffer.length > 500) this.eventBuffer.shift();
303
+ for (const socket of this.sockets) {
304
+ const state = socket;
305
+ if (state.session?.authenticated) {
306
+ socket.receive({ op: "event", type, d, s, timestamp: Date.now() });
307
+ }
308
+ }
309
+ }
310
+ /** Envia um frame cru às conexões autenticadas (sem `s`). */
311
+ sendFrame(frame) {
312
+ for (const socket of this.sockets) {
313
+ const state = socket;
314
+ if (state.session?.authenticated) socket.receive({ ...frame, timestamp: Date.now() });
315
+ }
316
+ }
317
+ /**
318
+ * Envia um evento com sequência arbitrária (para treinar a deduplicação
319
+ * do cliente: `s` repetido ou antigo deve ser descartado).
320
+ */
321
+ sendEventWithSequence(type, d, s) {
322
+ for (const socket of this.sockets) {
323
+ const state = socket;
324
+ if (state.session?.authenticated) {
325
+ socket.receive({ op: "event", type, d, s, timestamp: Date.now() });
326
+ }
327
+ }
328
+ }
329
+ /** Fecha as conexões com um código (ex.: 4009 para treinar resume). */
330
+ closeAll(code, reason) {
331
+ for (const socket of [...this.sockets]) {
332
+ socket.serverClose(code, reason);
333
+ }
334
+ }
335
+ /** Pede reconexão (frame `reconnect` + fechamento 4007, como o real). */
336
+ requestReconnect(reason = "gateway shutting down") {
337
+ for (const socket of [...this.sockets]) {
338
+ socket.receive({
339
+ op: "reconnect",
340
+ d: { reason, resumable: true },
341
+ timestamp: Date.now()
342
+ });
343
+ }
344
+ this.closeAll(4007, reason);
345
+ }
346
+ /** Descarta o histórico de eventos (o próximo resume falha com `invalid_session`). */
347
+ expireHistory() {
348
+ this.eventBuffer = [];
349
+ }
350
+ /** Reinicia o estado do mock. */
351
+ reset() {
352
+ this.sockets.clear();
353
+ this.eventBuffer = [];
354
+ this.globalSequence = 0;
355
+ this.knownSessionIds.clear();
356
+ this.refuseResumePending = this.options.refuseResumeOnce ?? false;
357
+ }
358
+ // ------------------------------------------------------------------
359
+ // "Servidor": handlers chamados pelo MockWebSocket
360
+ // ------------------------------------------------------------------
361
+ handleClientOpen(socket) {
362
+ this.sockets.add(socket);
363
+ socket.receive({
364
+ op: "hello",
365
+ d: {
366
+ heartbeatIntervalMs: this.options.heartbeatIntervalMs ?? 3e4,
367
+ sessionId: `mock-${Math.random().toString(36).slice(2, 12)}`,
368
+ protocolVersion: 1
369
+ },
370
+ timestamp: Date.now()
371
+ });
372
+ }
373
+ handleClientFrame(socket, frame) {
374
+ const op = frame.op;
375
+ const d = frame.d ?? {};
376
+ const state = socket;
377
+ switch (op) {
378
+ case "identify": {
379
+ if (state.session?.authenticated) {
380
+ socket.serverClose(4005, "already authenticated");
381
+ return;
382
+ }
383
+ if (this.options.token && d.token !== this.options.token) {
384
+ socket.serverClose(4004, "invalid token");
385
+ return;
386
+ }
387
+ const sessionId = `mock-${Math.random().toString(36).slice(2, 12)}`;
388
+ this.knownSessionIds.add(sessionId);
389
+ state.session = { authenticated: true, sessionId };
390
+ socket.receive({
391
+ op: "ready",
392
+ d: {
393
+ sessionId,
394
+ userId: this.options.ready?.userId ?? "1300000000000000010",
395
+ guilds: this.options.ready?.guilds ?? [],
396
+ resumeGatewayUrl: "wss://gateway.squord.com.br/gateway"
397
+ },
398
+ timestamp: Date.now()
399
+ });
400
+ return;
401
+ }
402
+ case "resume": {
403
+ const sessionId = d.sessionId;
404
+ const lastSequence = d.lastSequence ?? 0;
405
+ if (this.refuseResumePending) {
406
+ this.refuseResumePending = false;
407
+ socket.receive({
408
+ op: "invalid_session",
409
+ d: { resumable: false },
410
+ timestamp: Date.now()
411
+ });
412
+ return;
413
+ }
414
+ if (!this.knownSessionIds.has(sessionId)) {
415
+ socket.receive({
416
+ op: "invalid_session",
417
+ d: { resumable: false },
418
+ timestamp: Date.now()
419
+ });
420
+ return;
421
+ }
422
+ state.session = { authenticated: true, sessionId };
423
+ const replay = this.eventBuffer.filter((event) => event.s > lastSequence);
424
+ for (const event of replay) {
425
+ socket.receive({
426
+ op: "event",
427
+ type: event.type,
428
+ d: event.d,
429
+ s: event.s,
430
+ timestamp: Date.now()
431
+ });
432
+ }
433
+ const sequence = replay.length > 0 ? replay[replay.length - 1].s : lastSequence;
434
+ socket.receive({
435
+ op: "resumed",
436
+ d: { sessionId, replayed: replay.length, sequence },
437
+ timestamp: Date.now()
438
+ });
439
+ return;
440
+ }
441
+ case "heartbeat": {
442
+ if (!state.session?.authenticated) {
443
+ socket.serverClose(4003, "not authenticated");
444
+ return;
445
+ }
446
+ if (this.options.suppressHeartbeatAck) return;
447
+ socket.receive({
448
+ op: "heartbeat.ack",
449
+ d: { sequence: this.lastSequence },
450
+ timestamp: Date.now()
451
+ });
452
+ return;
453
+ }
454
+ case "presence.update":
455
+ case "subscribe":
456
+ case "unsubscribe":
457
+ case "typing.start":
458
+ case "voice.state.update":
459
+ return;
460
+ // aceitos e ignorados, como o real
461
+ default:
462
+ socket.serverClose(4001, "unknown opcode");
463
+ }
464
+ }
465
+ handleClientClose(socket, code, reason, byServer = false) {
466
+ this.sockets.delete(socket);
467
+ socket.session = void 0;
468
+ void code;
469
+ void reason;
470
+ void byServer;
471
+ }
472
+ };
473
+ function createMockGateway(options = {}) {
474
+ return new MockGatewayServer(options);
475
+ }
476
+
477
+ // src/testing/fixtures.ts
478
+ var fixtures_exports = {};
479
+ __export(fixtures_exports, {
480
+ bot: () => bot,
481
+ botUser: () => botUser,
482
+ channel: () => channel,
483
+ command: () => command,
484
+ commandInteraction: () => commandInteraction,
485
+ componentInteraction: () => componentInteraction,
486
+ guild: () => guild,
487
+ member: () => member,
488
+ message: () => message,
489
+ role: () => role,
490
+ user: () => user
491
+ });
492
+ function user(overrides = {}) {
493
+ return {
494
+ id: "1300000000000000020",
495
+ username: "ana",
496
+ displayName: "Ana",
497
+ avatarUrl: null,
498
+ avatarAnimatedUrl: null,
499
+ nameStyle: null,
500
+ flags: 0,
501
+ deleted: false,
502
+ suspended: false,
503
+ premium: false,
504
+ ...overrides
505
+ };
506
+ }
507
+ function botUser(overrides = {}) {
508
+ return user({
509
+ id: "1300000000000000010",
510
+ username: "bot~meubot",
511
+ displayName: "Meu Bot",
512
+ flags: 32,
513
+ // BOT
514
+ ...overrides
515
+ });
516
+ }
517
+ function member(overrides = {}) {
518
+ return {
519
+ id: "1300000000000000011",
520
+ guildId: "1300000000000000001",
521
+ userId: "1300000000000000020",
522
+ user: user(),
523
+ type: "INTERNAL",
524
+ nickname: null,
525
+ avatarUrl: null,
526
+ avatarAnimatedUrl: null,
527
+ bannerUrl: null,
528
+ bannerAnimatedUrl: null,
529
+ bio: null,
530
+ bioEmojis: [],
531
+ nameStyle: null,
532
+ profileFont: null,
533
+ profileTheme: null,
534
+ roleIds: [],
535
+ joinedAt: "2026-10-01T10:00:00.000Z",
536
+ timeoutUntil: null,
537
+ deaf: false,
538
+ mute: false,
539
+ pending: false,
540
+ boostingSince: null,
541
+ createdAt: "2026-10-01T10:00:00.000Z",
542
+ updatedAt: "2026-10-01T10:00:00.000Z",
543
+ ...overrides
544
+ };
545
+ }
546
+ function channel(overrides = {}) {
547
+ return {
548
+ id: "1300000000000000040",
549
+ guildId: "1300000000000000001",
550
+ categoryId: null,
551
+ name: "geral",
552
+ type: "TEXT",
553
+ position: 0,
554
+ topic: null,
555
+ topicUpdatedAt: null,
556
+ topicUpdatedById: null,
557
+ isPrivate: false,
558
+ rateLimitPerUser: 0,
559
+ bitrate: null,
560
+ userLimit: null,
561
+ chatEnabled: true,
562
+ lastMessageId: null,
563
+ overwrites: [],
564
+ availableTags: [],
565
+ requireTag: false,
566
+ defaultAutoArchiveMinutes: null,
567
+ createdAt: "2026-10-01T10:00:00.000Z",
568
+ updatedAt: "2026-10-01T10:00:00.000Z",
569
+ ...overrides
570
+ };
571
+ }
572
+ function role(overrides = {}) {
573
+ return {
574
+ id: "1300000000000000001",
575
+ guildId: "1300000000000000001",
576
+ name: "@everyone",
577
+ color: null,
578
+ position: 0,
579
+ permissions: "1685839112193",
580
+ hoist: false,
581
+ mentionable: false,
582
+ managed: false,
583
+ managedKind: null,
584
+ botId: null,
585
+ icon: null,
586
+ selfAssignable: false,
587
+ createdAt: "2026-10-01T10:00:00.000Z",
588
+ updatedAt: "2026-10-01T10:00:00.000Z",
589
+ ...overrides
590
+ };
591
+ }
592
+ function guild(overrides = {}) {
593
+ return {
594
+ id: "1300000000000000001",
595
+ ownerId: "1300000000000000009",
596
+ name: "Meu Space",
597
+ slug: "meu-space",
598
+ description: null,
599
+ iconUrl: null,
600
+ iconAnimatedUrl: null,
601
+ bannerUrl: null,
602
+ bannerAnimatedUrl: null,
603
+ bannerPlaceholder: null,
604
+ defaultChannelId: "1300000000000000040",
605
+ systemChannelId: null,
606
+ visibility: "PUBLIC",
607
+ verificationLevel: "NONE",
608
+ accessMode: "LINK",
609
+ requireVerifiedEmail: false,
610
+ requireTwoFactor: false,
611
+ moderationMfaRequired: false,
612
+ joinRequestRoleIds: [],
613
+ requireJoinMessage: false,
614
+ joinRequestRetryDays: 0,
615
+ memberCount: 2,
616
+ flags: 0,
617
+ planId: "free",
618
+ vanityLapsesAt: null,
619
+ vanityInvite: false,
620
+ boostCount: 0,
621
+ boostLevel: 0,
622
+ boostMessages: false,
623
+ discoveryCategory: null,
624
+ locale: null,
625
+ rules: [],
626
+ rulesUpdatedAt: null,
627
+ discoverable: false,
628
+ discoverableSince: null,
629
+ minAccountAgeDays: 0,
630
+ createdAt: "2026-10-01T10:00:00.000Z",
631
+ updatedAt: "2026-10-01T10:00:00.000Z",
632
+ self: {
633
+ memberId: "1300000000000000012",
634
+ roleIds: ["1300000000000000031"],
635
+ permissions: "155649",
636
+ isOwner: false
637
+ },
638
+ ...overrides
639
+ };
640
+ }
641
+ function message(overrides = {}) {
642
+ return {
643
+ id: "1300000000000000100",
644
+ guildId: "1300000000000000001",
645
+ channelId: "1300000000000000040",
646
+ authorId: "1300000000000000020",
647
+ type: "DEFAULT",
648
+ content: "Ol\xE1!",
649
+ replyToId: null,
650
+ attachments: [],
651
+ embeds: [],
652
+ components: [],
653
+ interaction: null,
654
+ mentions: { userIds: [], roleIds: [], channelIds: [], everyone: false },
655
+ reactions: [],
656
+ pinned: false,
657
+ editedAt: null,
658
+ deletedAt: null,
659
+ moderated: false,
660
+ nonce: null,
661
+ call: null,
662
+ poll: null,
663
+ forward: null,
664
+ relay: null,
665
+ relayedCount: null,
666
+ stickers: [],
667
+ emojis: [],
668
+ thread: null,
669
+ automod: null,
670
+ createdAt: "2026-10-05T14:30:00.000Z",
671
+ updatedAt: "2026-10-05T14:30:00.000Z",
672
+ author: user(),
673
+ memberNickname: null,
674
+ memberAvatarUrl: null,
675
+ memberNameStyle: null,
676
+ replyTo: null,
677
+ ...overrides
678
+ };
679
+ }
680
+ function commandInteraction(overrides = {}) {
681
+ return {
682
+ id: "1300000000000000400",
683
+ token: "tk_9f2c1d7e8a4b",
684
+ type: "COMMAND",
685
+ guildId: "1300000000000000001",
686
+ channelId: "1300000000000000040",
687
+ user: user(),
688
+ member: member(),
689
+ command: {
690
+ id: "1300000000000000500",
691
+ name: "ping",
692
+ options: []
693
+ },
694
+ createdAt: "2026-10-05T14:40:00.000Z",
695
+ ...overrides
696
+ };
697
+ }
698
+ function componentInteraction(overrides = {}) {
699
+ return {
700
+ id: "1300000000000000401",
701
+ token: "tk_1b3d5f7a9c2e",
702
+ type: "COMPONENT",
703
+ guildId: "1300000000000000001",
704
+ channelId: "1300000000000000040",
705
+ user: user(),
706
+ member: member(),
707
+ component: {
708
+ messageId: "1300000000000000100",
709
+ customId: "confirmar",
710
+ type: "button",
711
+ values: []
712
+ },
713
+ createdAt: "2026-10-05T14:41:00.000Z",
714
+ ...overrides
715
+ };
716
+ }
717
+ function command(overrides = {}) {
718
+ return {
719
+ id: "1300000000000000500",
720
+ botId: "1300000000000000010",
721
+ guildId: null,
722
+ name: "ping",
723
+ description: "Verifica a lat\xEAncia do bot",
724
+ options: [],
725
+ updatedAt: "2026-10-05T14:00:00.000Z",
726
+ ...overrides
727
+ };
728
+ }
729
+ function bot(overrides = {}) {
730
+ return {
731
+ id: "1300000000000000010",
732
+ user: botUser(),
733
+ description: "Bot de exemplo",
734
+ ownerUsername: "ana",
735
+ public: false,
736
+ verified: false,
737
+ installCount: 1,
738
+ termsUrl: null,
739
+ privacyUrl: null,
740
+ createdAt: "2026-10-01T10:00:00.000Z",
741
+ intents: 13,
742
+ ...overrides
743
+ };
744
+ }
745
+
746
+ // src/testing/index.ts
747
+ function createMockEnvironment(options = {}) {
748
+ const rest = createMockRest();
749
+ rest.get("/bots/@me", () => ({ status: 200, body: bot() }));
750
+ rest.post("/channels/:channelId/messages", (match) => {
751
+ const body = match.body ?? {};
752
+ return {
753
+ status: 201,
754
+ body: message({
755
+ channelId: match.params.channelId,
756
+ content: body.content ?? "",
757
+ replyToId: body.replyToId ?? null,
758
+ nonce: body.nonce ?? null,
759
+ author: botUser()
760
+ })
761
+ };
762
+ });
763
+ rest.put("/bots/@me/commands", () => ({ status: 200, body: [] }));
764
+ rest.put("/bots/@me/guilds/:guildId/commands", () => ({ status: 200, body: [] }));
765
+ const gateway = createMockGateway({
766
+ heartbeatIntervalMs: options.heartbeatIntervalMs ?? 200,
767
+ token: options.token
768
+ });
769
+ return {
770
+ options: {
771
+ apiBaseURL: "https://mock.test",
772
+ fetchImpl: rest.fetch,
773
+ ws: gateway.wsFactory,
774
+ gatewayReconnectBaseMs: options.reconnectBaseMs ?? 20
775
+ },
776
+ gateway,
777
+ rest
778
+ };
779
+ }
780
+ // Annotate the CommonJS export names for ESM import in node:
781
+ 0 && (module.exports = {
782
+ MockGatewayServer,
783
+ MockRest,
784
+ createMockEnvironment,
785
+ createMockGateway,
786
+ createMockRest,
787
+ fixtures
788
+ });
789
+ //# sourceMappingURL=index.cjs.map