discord-embed-router 0.1.0 → 0.2.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/dist/index.mjs CHANGED
@@ -1,10 +1,28 @@
1
1
  // src/EmbedRouter.ts
2
2
  import path from "path";
3
+ import { createHash } from "crypto";
3
4
  import { match } from "path-to-regexp";
4
5
 
5
6
  // src/consts.ts
6
7
  var ID_PREFIX = "der";
7
- var BASE_URL = "x://x";
8
+ var METHOD_TO_ENCODING = {
9
+ GET: "G",
10
+ POST: "P",
11
+ PUT: "U",
12
+ PATCH: "A",
13
+ DELETE: "D"
14
+ };
15
+ var ENCODING_TO_METHOD = {
16
+ G: "GET",
17
+ P: "POST",
18
+ U: "PUT",
19
+ A: "PATCH",
20
+ D: "DELETE"
21
+ };
22
+ var BASE_URL = "discord://embed.router";
23
+ var PUA_START = 57344;
24
+ var PUA_END = 63743;
25
+ var PUA_RANGE = PUA_END - PUA_START + 1;
8
26
 
9
27
  // src/helpers/pathToString.ts
10
28
  import { parse, stringify, TokenData } from "path-to-regexp";
@@ -15,36 +33,127 @@ var pathToString = (path2, checkValidity = true) => {
15
33
  return typeof path2 === "string" ? path2 : stringify(path2);
16
34
  };
17
35
 
36
+ // src/helpers/decodePath.ts
37
+ import { compile } from "path-to-regexp";
38
+ var decodePath = ({
39
+ idPrefix,
40
+ interaction
41
+ }) => {
42
+ const customId = interaction.customId;
43
+ if (!customId.startsWith(idPrefix)) return false;
44
+ if (interaction.isButton()) {
45
+ return parseMethodAndPath(customId.slice(idPrefix.length));
46
+ } else if (interaction.isAnySelectMenu()) {
47
+ if (interaction.values.length === 0) return false;
48
+ const res = parseMethodAndPath(customId.slice(idPrefix.length));
49
+ if (!res) return false;
50
+ const { method, path: path2 } = res;
51
+ return {
52
+ method,
53
+ path: fillParams(path2, {
54
+ [interaction.isStringSelectMenu() ? "to" : interaction.isChannelSelectMenu() ? "channelId" : interaction.isRoleSelectMenu() ? "roleId" : "userId"]: interaction.values[0].split("/").slice(1)
55
+ })
56
+ };
57
+ }
58
+ return false;
59
+ };
60
+ var parseMethodAndPath = (pathWithMethod) => {
61
+ const firstSlash = pathWithMethod.indexOf("/");
62
+ if (firstSlash <= 0) return false;
63
+ const method = ENCODING_TO_METHOD[pathWithMethod.slice(0, firstSlash)];
64
+ if (method === void 0) return false;
65
+ return {
66
+ method,
67
+ path: pathWithMethod.slice(firstSlash)
68
+ };
69
+ };
70
+ var fillParams = (path2, params = {}) => {
71
+ const url = new URL(path2, BASE_URL);
72
+ const toPath = compile(url.pathname);
73
+ url.pathname = toPath(params);
74
+ for (const [key, value] of url.searchParams) {
75
+ if (value.startsWith(":") && key.slice(1) in params) {
76
+ const paramValue = params?.[key.slice(1)];
77
+ if (paramValue) {
78
+ url.searchParams.set(
79
+ key,
80
+ Array.isArray(paramValue) ? paramValue.join("/") : paramValue
81
+ );
82
+ } else {
83
+ url.searchParams.delete(key);
84
+ }
85
+ }
86
+ }
87
+ return `${url.pathname}${url.search}`;
88
+ };
89
+
18
90
  // src/EmbedRouter.ts
19
91
  var EmbedRouter = class _EmbedRouter {
20
- static usedIdentifiers = /* @__PURE__ */ new Set();
21
- static generateUniqueIdentifier() {
22
- const PUA_START = 57344;
23
- const PUA_END = 63743;
24
- let char;
25
- do {
26
- const codepoint = PUA_START + Math.floor(Math.random() * (PUA_END - PUA_START + 1));
27
- char = String.fromCodePoint(codepoint);
28
- } while (_EmbedRouter.usedIdentifiers.has(char));
29
- _EmbedRouter.usedIdentifiers.add(char);
30
- return char;
31
- }
92
+ // identifier -> embedRouter
93
+ static #usedIdentifiers = /* @__PURE__ */ new Map();
94
+ // Name used to generate prefixes
95
+ #name = "";
32
96
  // Prefix for customIds of RouteButtonBuilders
33
- idPrefix;
97
+ #idPrefix;
98
+ #identifier = "";
34
99
  getIdPrefix() {
35
- return this.idPrefix;
100
+ return `${this.#idPrefix}${this.#identifier}`;
36
101
  }
37
102
  // All added routes
38
- routes = [];
103
+ #routes = /* @__PURE__ */ new Map();
39
104
  /**
40
105
  *
106
+ * @param name the name to give the router. ensures buttons stay connected across restarts
41
107
  * @param idPrefix the prefix for RouteButtonBuilder customIds
42
108
  */
43
- constructor(idPrefix = ID_PREFIX) {
109
+ constructor({
110
+ name = "",
111
+ idPrefix = ID_PREFIX
112
+ } = {}) {
113
+ if (_EmbedRouter.#usedIdentifiers.size >= PUA_RANGE) {
114
+ throw new Error(`You can not have more than ${PUA_RANGE} routers`);
115
+ }
44
116
  if (idPrefix.includes("/")) {
45
117
  throw new Error(`Prefix can't contain "/": ${idPrefix}`);
46
118
  }
47
- this.idPrefix = `${idPrefix}${_EmbedRouter.generateUniqueIdentifier()}`;
119
+ this.#idPrefix = idPrefix;
120
+ this.#name = name;
121
+ this.#updateIdentifier();
122
+ }
123
+ #updateIdentifier() {
124
+ const hash = createHash("sha256").update(this.#name).digest();
125
+ let raw = hash.readUint32BE(0);
126
+ let char;
127
+ const nameCollisions = [];
128
+ while (true) {
129
+ const codepoint = PUA_START + raw++ % PUA_RANGE;
130
+ char = String.fromCodePoint(codepoint);
131
+ const collisionRouter = _EmbedRouter.#usedIdentifiers.get(char);
132
+ if (collisionRouter === void 0) break;
133
+ if (this.#name.length > 0 && collisionRouter.#name.length === 0) {
134
+ collisionRouter.#updateIdentifier();
135
+ break;
136
+ }
137
+ nameCollisions.push(collisionRouter);
138
+ }
139
+ _EmbedRouter.#usedIdentifiers.set(char, this);
140
+ if (nameCollisions.length > 0 && this.#name.length > 0) {
141
+ process.emitWarning(
142
+ `EmbedRouter identifier collision for name "${this.#name}" with ${nameCollisions.map((c) => `"${c.#name}"`).join(", ")}`,
143
+ "EmbedRouterWarning"
144
+ );
145
+ }
146
+ this.#identifier = char;
147
+ }
148
+ #addRoute(method, routePath, handler) {
149
+ const methodRoutes = this.#routes.get(method) ?? [];
150
+ methodRoutes.push({
151
+ method,
152
+ path: Array.isArray(routePath) ? routePath : [routePath],
153
+ matchFunction: match(routePath),
154
+ handler
155
+ });
156
+ this.#routes.set(method, methodRoutes);
48
157
  }
49
158
  /**
50
159
  * Registers a path with the router
@@ -52,12 +161,44 @@ var EmbedRouter = class _EmbedRouter {
52
161
  * @param routePath path to match with
53
162
  * @param handler function that generates the message when a path is matched
54
163
  */
55
- on(routePath, handler) {
56
- this.routes.push({
57
- path: Array.isArray(routePath) ? routePath : [routePath],
58
- matchFunction: match(routePath),
59
- handler
60
- });
164
+ get(routePath, handler) {
165
+ this.#addRoute("GET", routePath, handler);
166
+ }
167
+ /**
168
+ * Registers a path with the router
169
+ *
170
+ * @param routePath path to match with
171
+ * @param handler function that generates the message when a path is matched
172
+ */
173
+ post(routePath, handler) {
174
+ this.#addRoute("POST", routePath, handler);
175
+ }
176
+ /**
177
+ * Registers a path with the router
178
+ *
179
+ * @param routePath path to match with
180
+ * @param handler function that generates the message when a path is matched
181
+ */
182
+ put(routePath, handler) {
183
+ this.#addRoute("PUT", routePath, handler);
184
+ }
185
+ /**
186
+ * Registers a path with the router
187
+ *
188
+ * @param routePath path to match with
189
+ * @param handler function that generates the message when a path is matched
190
+ */
191
+ patch(routePath, handler) {
192
+ this.#addRoute("PATCH", routePath, handler);
193
+ }
194
+ /**
195
+ * Registers a path with the router
196
+ *
197
+ * @param routePath path to match with
198
+ * @param handler function that generates the message when a path is matched
199
+ */
200
+ delete(routePath, handler) {
201
+ this.#addRoute("DELETE", routePath, handler);
61
202
  }
62
203
  /**
63
204
  * Adds a subrouter to the router
@@ -67,11 +208,14 @@ var EmbedRouter = class _EmbedRouter {
67
208
  */
68
209
  use(routePath, embedRouter) {
69
210
  const pathString = pathToString(routePath);
70
- for (const route of embedRouter.routes) {
71
- this.on(
72
- route.path.map((p) => path.posix.join(pathString, pathToString(p))),
73
- route.handler
74
- );
211
+ for (const [method, routes] of embedRouter.#routes) {
212
+ for (const route of routes) {
213
+ this.#addRoute(
214
+ method,
215
+ route.path.map((p) => path.posix.join(pathString, pathToString(p))),
216
+ route.handler
217
+ );
218
+ }
75
219
  }
76
220
  }
77
221
  /**
@@ -79,30 +223,36 @@ var EmbedRouter = class _EmbedRouter {
79
223
  *
80
224
  * @param interaction interactions from "interactionCreate" (filter for ButtonInteractions)
81
225
  */
82
- async listener(interaction) {
83
- if (!interaction.isButton()) return;
84
- const customId = interaction.customId;
85
- if (!customId.startsWith(this.idPrefix)) return;
86
- const path2 = customId.slice(this.idPrefix.length);
87
- this.dispatch(interaction, path2);
226
+ async listener(interaction, locals) {
227
+ const res = decodePath({ idPrefix: this.getIdPrefix(), interaction });
228
+ if (!res)
229
+ throw new Error(`Invalid component found: id ${interaction.customId}`);
230
+ this.dispatch({ interaction, method: res.method, path: res.path, locals });
88
231
  }
89
232
  /**
90
233
  * Connect or update an interaction message to a path
91
234
  *
92
235
  * @param interaction interaction to connect to
93
236
  * @param path path to route the interaction to
237
+ * @param method method to send to route
94
238
  * @param flags optional discord flags to send with message (only allowed on first reply)
95
239
  */
96
- async dispatch(interaction, path2, flags) {
240
+ async dispatch({
241
+ interaction,
242
+ method = "GET",
243
+ path: path2,
244
+ flags,
245
+ locals
246
+ }) {
97
247
  if (interaction.isAutocomplete())
98
248
  throw new Error("Autocomplete Interactions aren't supported");
99
- const resolvedRoute = this.resolve(pathToString(path2, false));
249
+ const resolvedRoute = this.#resolve(method, pathToString(path2, false));
100
250
  if (!resolvedRoute)
101
251
  throw new Error(`No route found for ${pathToString(path2, false)}`);
102
- const routeResponse = resolvedRoute.handler(
103
- interaction,
104
- resolvedRoute.state
105
- );
252
+ const routeResponse = await resolvedRoute.handler(interaction, {
253
+ ...resolvedRoute.state,
254
+ locals
255
+ });
106
256
  if (interaction.replied || interaction.deferred) {
107
257
  if (flags)
108
258
  throw new Error(
@@ -122,27 +272,61 @@ var EmbedRouter = class _EmbedRouter {
122
272
  });
123
273
  }
124
274
  }
125
- resolve(routePath) {
275
+ #resolve(method, routePath) {
126
276
  const url = new URL(routePath, BASE_URL);
127
- for (const route of this.routes) {
277
+ for (const route of this.#routes.get(method) ?? []) {
128
278
  const result = route.matchFunction(url.pathname);
129
279
  if (result) {
130
280
  return {
131
281
  state: {
132
282
  ...result,
133
- searchParams: url.searchParams
283
+ query: url.searchParams,
284
+ embedRouter: this
134
285
  },
135
286
  handler: route.handler
136
287
  };
137
288
  }
138
289
  }
139
- return null;
290
+ return false;
140
291
  }
141
292
  };
142
293
 
143
- // src/RouteButtonBuilder.ts
294
+ // src/componentBuilders/RouteButtonBuilder.ts
144
295
  import { ButtonBuilder } from "discord.js";
296
+
297
+ // src/helpers/encodePath.ts
298
+ var encodePath = ({
299
+ idPrefix,
300
+ method,
301
+ path: path2,
302
+ query
303
+ }) => {
304
+ const url = new URL(pathToString(path2), BASE_URL);
305
+ if (query) {
306
+ for (const [key, value] of new URLSearchParams(query)) {
307
+ url.searchParams.set(key, value);
308
+ }
309
+ }
310
+ return `${idPrefix}${METHOD_TO_ENCODING[method]}${url.pathname}${url.search}`;
311
+ };
312
+
313
+ // src/types/componentBuilders.ts
314
+ var isSetOptions = (u) => {
315
+ return typeof u === "object" && u !== null && (!("method" in u) || "method" in u && typeof u.method === "string" || u.method === void 0) && "path" in u && typeof u.path === "string" && (!("query" in u) || "query" in u && typeof u.query in ["object", "string"] || u.query === void 0);
316
+ };
317
+
318
+ // src/componentBuilders/RouteButtonBuilder.ts
145
319
  var RouteButtonBuilder = class extends ButtonBuilder {
320
+ #embedRouter;
321
+ /**
322
+ *
323
+ * @param embedRouter the router you want to route with
324
+ * @param data the data to construct a component out of
325
+ */
326
+ constructor(embedRouter, data) {
327
+ super(data);
328
+ this.#embedRouter = embedRouter;
329
+ }
146
330
  /**
147
331
  * Not supported for RouteButtonBuilder
148
332
  *
@@ -153,7 +337,7 @@ var RouteButtonBuilder = class extends ButtonBuilder {
153
337
  throw new Error("setURL is not supported on RouteButtonBuilder");
154
338
  }
155
339
  /**
156
- * Not supported for RouteButtonBuilder (setTo uses customId)
340
+ * Not supported for RouteButtonBuilder (use setTo)
157
341
  *
158
342
  * @remarks
159
343
  * @param
@@ -161,21 +345,300 @@ var RouteButtonBuilder = class extends ButtonBuilder {
161
345
  setCustomId() {
162
346
  throw new Error("setCustomId is not supported on RouteButtonBuilder");
163
347
  }
348
+ setTo(arg) {
349
+ const {
350
+ method = "GET",
351
+ path: path2,
352
+ query
353
+ } = isSetOptions(arg) ? arg : { path: arg };
354
+ super.setCustomId(
355
+ encodePath({
356
+ idPrefix: this.#embedRouter.getIdPrefix(),
357
+ method,
358
+ path: path2,
359
+ query
360
+ })
361
+ );
362
+ return this;
363
+ }
364
+ };
365
+
366
+ // src/componentBuilders/RouteStringSelectMenuBuilder.ts
367
+ import {
368
+ normalizeArray,
369
+ StringSelectMenuBuilder
370
+ } from "discord.js";
371
+
372
+ // src/componentBuilders/RouteStringMenuOptionBuilder.ts
373
+ import { StringSelectMenuOptionBuilder } from "discord.js";
374
+ var RouteStringSelectMenuOptionBuilder = class extends StringSelectMenuOptionBuilder {
375
+ /**
376
+ * Not supported for RouteStringSelectMenuOptionBuilder (use setTo)
377
+ *
378
+ * @remarks
379
+ * @param
380
+ */
381
+ setValue() {
382
+ throw new Error(
383
+ "setValue is not supported on RouteStringSelectMenuOptionBuilder"
384
+ );
385
+ }
386
+ setTo(arg) {
387
+ const {
388
+ method = "GET",
389
+ path: path2,
390
+ query
391
+ } = isSetOptions(arg) ? arg : { path: arg };
392
+ super.setValue(
393
+ encodePath({
394
+ idPrefix: "",
395
+ method,
396
+ path: path2,
397
+ query
398
+ })
399
+ );
400
+ return this;
401
+ }
402
+ };
403
+
404
+ // src/componentBuilders/RouteStringSelectMenuBuilder.ts
405
+ var RouteStringSelectMenuBuilder = class extends StringSelectMenuBuilder {
406
+ #embedRouter;
407
+ /**
408
+ *
409
+ * @param embedRouter the router you want to route with
410
+ * @param path the path to redirect to, :to or *to in path will be replaced with the selected user's id
411
+ * @param query any query parameters you want to add, :to will be replaced with the selected user's id
412
+ * @param data the data to construct a component out of
413
+ */
414
+ constructor(embedRouter, data) {
415
+ super(data);
416
+ this.#embedRouter = embedRouter;
417
+ super.setCustomId(
418
+ encodePath({
419
+ idPrefix: this.#embedRouter.getIdPrefix(),
420
+ method: "GET",
421
+ path: "/*to"
422
+ })
423
+ );
424
+ }
425
+ /**
426
+ * Not supported for RouteStringSelectMenuBuilder (customId set from embedRouter)
427
+ *
428
+ * @remarks
429
+ * @param
430
+ */
431
+ setCustomId() {
432
+ throw new Error(
433
+ "setCustomId is not supported on RouteStringSelectMenuBuilder"
434
+ );
435
+ }
436
+ /**
437
+ * Not supported for RouteStringSelectMenuBuilder (use addTos)
438
+ *
439
+ * @remarks
440
+ * @param
441
+ */
442
+ addOptions() {
443
+ throw new Error(
444
+ "addOptions is not supported on RouteStringSelectMenuBuilder"
445
+ );
446
+ }
447
+ /**
448
+ * Not supported for RouteStringSelectMenuBuilder (use setTos)
449
+ *
450
+ * @remarks
451
+ * @param
452
+ */
453
+ setOptions() {
454
+ throw new Error(
455
+ "setOptions is not supported on RouteStringSelectMenuBuilder"
456
+ );
457
+ }
458
+ /**
459
+ * Adds route select menu options to builder
460
+ *
461
+ * @param tos the list of route select menu options
462
+ */
463
+ addTos(...tos) {
464
+ const resolved = normalizeArray(tos);
465
+ super.addOptions(
466
+ resolved.map(
467
+ (o) => o instanceof RouteStringSelectMenuOptionBuilder ? o : new RouteStringSelectMenuOptionBuilder(o)
468
+ )
469
+ );
470
+ return this;
471
+ }
164
472
  /**
165
- * Sets the path to route to when clicked
473
+ * Sets route select menu options to builder
166
474
  *
167
- * @param path the path to route to
168
- * @param idPrefix the prefix to add before the custom_id
475
+ * @param tos the list of route select menu options
169
476
  */
170
- setTo(embedRouter, path2) {
171
- const idPrefix = embedRouter.getIdPrefix();
172
- const url = new URL(pathToString(path2, false), BASE_URL);
173
- const customId = `${idPrefix}${url.pathname}${url.search}`;
174
- super.setCustomId(customId);
477
+ setTos(...tos) {
478
+ const resolved = normalizeArray(tos);
479
+ super.setOptions(
480
+ resolved.map(
481
+ (o) => o instanceof RouteStringSelectMenuOptionBuilder ? o : new RouteStringSelectMenuOptionBuilder(o)
482
+ )
483
+ );
484
+ return this;
485
+ }
486
+ setPattern(arg) {
487
+ const {
488
+ method = "GET",
489
+ path: path2,
490
+ query
491
+ } = isSetOptions(arg) ? arg : { path: arg };
492
+ super.setCustomId(
493
+ encodePath({
494
+ idPrefix: this.#embedRouter.getIdPrefix(),
495
+ method,
496
+ path: path2,
497
+ query
498
+ })
499
+ );
500
+ return this;
501
+ }
502
+ };
503
+
504
+ // src/componentBuilders/RouteChannelSelectMenuBuilder.ts
505
+ import {
506
+ ChannelSelectMenuBuilder
507
+ } from "discord.js";
508
+ var RouteChannelSelectMenuBuilder = class extends ChannelSelectMenuBuilder {
509
+ #embedRouter;
510
+ /**
511
+ *
512
+ * @param embedRouter the router you want to route with
513
+ * @param data the data to construct a component out of
514
+ */
515
+ constructor(embedRouter, data) {
516
+ super(data);
517
+ this.#embedRouter = embedRouter;
518
+ }
519
+ /**
520
+ * Not supported for RouteChannelSelectMenuBuilder (customId set from embedRouter)
521
+ *
522
+ * @remarks
523
+ * @param
524
+ */
525
+ setCustomId() {
526
+ throw new Error(
527
+ "setCustomId is not supported on RouteChannelSelectMenuBuilder"
528
+ );
529
+ }
530
+ setPattern(arg) {
531
+ const {
532
+ method = "GET",
533
+ path: path2,
534
+ query
535
+ } = isSetOptions(arg) ? arg : { path: arg };
536
+ super.setCustomId(
537
+ encodePath({
538
+ idPrefix: this.#embedRouter.getIdPrefix(),
539
+ method,
540
+ path: path2,
541
+ query
542
+ })
543
+ );
544
+ return this;
545
+ }
546
+ };
547
+
548
+ // src/componentBuilders/RouteRoleSelectMenuBuilder.ts
549
+ import {
550
+ RoleSelectMenuBuilder
551
+ } from "discord.js";
552
+ var RouteRoleSelectMenuBuilder = class extends RoleSelectMenuBuilder {
553
+ #embedRouter;
554
+ /**
555
+ *
556
+ * @param embedRouter the router you want to route with
557
+ * @param data the data to construct a component out of
558
+ */
559
+ constructor(embedRouter, data) {
560
+ super(data);
561
+ this.#embedRouter = embedRouter;
562
+ }
563
+ /**
564
+ * Not supported for RouteRoleSelectMenuBuilder (customId set from embedRouter)
565
+ *
566
+ * @remarks
567
+ * @param
568
+ */
569
+ setCustomId() {
570
+ throw new Error(
571
+ "setCustomId is not supported on RouteRoleSelectMenuBuilder"
572
+ );
573
+ }
574
+ setPattern(arg) {
575
+ const {
576
+ method = "GET",
577
+ path: path2,
578
+ query
579
+ } = isSetOptions(arg) ? arg : { path: arg };
580
+ super.setCustomId(
581
+ encodePath({
582
+ idPrefix: this.#embedRouter.getIdPrefix(),
583
+ method,
584
+ path: path2,
585
+ query
586
+ })
587
+ );
588
+ return this;
589
+ }
590
+ };
591
+
592
+ // src/componentBuilders/RouteUserSelectMenuBuilder.ts
593
+ import {
594
+ UserSelectMenuBuilder
595
+ } from "discord.js";
596
+ var RouteUserSelectMenuBuilder = class extends UserSelectMenuBuilder {
597
+ #embedRouter;
598
+ /**
599
+ *
600
+ * @param embedRouter the router you want to route with
601
+ * @param data the data to construct a component out of
602
+ */
603
+ constructor(embedRouter, data) {
604
+ super(data);
605
+ this.#embedRouter = embedRouter;
606
+ }
607
+ /**
608
+ * Not supported for RouteUserSelectMenuBuilder (customId set from embedRouter)
609
+ *
610
+ * @remarks
611
+ * @param
612
+ */
613
+ setCustomId() {
614
+ throw new Error(
615
+ "setCustomId is not supported on RouteUserSelectMenuBuilder"
616
+ );
617
+ }
618
+ setPattern(arg) {
619
+ const {
620
+ method = "GET",
621
+ path: path2,
622
+ query
623
+ } = isSetOptions(arg) ? arg : { path: arg };
624
+ super.setCustomId(
625
+ encodePath({
626
+ idPrefix: this.#embedRouter.getIdPrefix(),
627
+ method,
628
+ path: path2,
629
+ query
630
+ })
631
+ );
632
+ return this;
175
633
  }
176
634
  };
177
635
  export {
178
636
  EmbedRouter,
179
- RouteButtonBuilder
637
+ RouteButtonBuilder,
638
+ RouteChannelSelectMenuBuilder,
639
+ RouteRoleSelectMenuBuilder,
640
+ RouteStringSelectMenuBuilder,
641
+ RouteStringSelectMenuOptionBuilder,
642
+ RouteUserSelectMenuBuilder
180
643
  };
181
644
  //# sourceMappingURL=index.mjs.map