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