discord-embed-router 0.2.3 → 0.2.5

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.js CHANGED
@@ -44,6 +44,7 @@ module.exports = __toCommonJS(index_exports);
44
44
  var import_node_path = __toESM(require("path"));
45
45
  var import_node_crypto = require("crypto");
46
46
  var import_path_to_regexp3 = require("path-to-regexp");
47
+ var import_discord = require("discord.js");
47
48
 
48
49
  // src/consts.ts
49
50
  var ID_PREFIX = "der";
@@ -83,25 +84,52 @@ var decodePath = ({
83
84
  }) => {
84
85
  const customId = interaction.customId;
85
86
  if (!customId.startsWith(idPrefix)) return false;
87
+ const res = parseMethodAndPath(customId.slice(idPrefix.length));
88
+ if (!res) return false;
89
+ const { method, path: path2 } = res;
86
90
  if (interaction.isButton()) {
87
- return parseMethodAndPath(customId.slice(idPrefix.length));
91
+ return {
92
+ method,
93
+ path: urlToPathString(
94
+ fillParams(path2, {
95
+ ts: interaction.createdTimestamp.toString()
96
+ })
97
+ )
98
+ };
88
99
  } else if (interaction.isAnySelectMenu()) {
89
100
  if (interaction.values.length === 0) return false;
90
- const res = parseMethodAndPath(customId.slice(idPrefix.length));
91
- if (!res) return false;
92
- const { method, path: path2 } = res;
101
+ if (interaction.isStringSelectMenu()) {
102
+ const toRes = parseOptionalMethodAndPath(interaction.values[0]);
103
+ const toURL = toRes ? fillParams(toRes.path, {
104
+ ts: interaction.createdTimestamp.toString()
105
+ }) : void 0;
106
+ const pathURL = fillParams(path2, {
107
+ ts: interaction.createdTimestamp.toString(),
108
+ to: toURL ? toURL.pathname.split("/").slice(1) : ""
109
+ });
110
+ for (const [key, value] of toURL?.searchParams ?? []) {
111
+ pathURL.searchParams.append(key, value);
112
+ }
113
+ return {
114
+ method,
115
+ path: urlToPathString(pathURL)
116
+ };
117
+ }
93
118
  return {
94
119
  method,
95
- path: fillParams(path2, {
96
- [interaction.isStringSelectMenu() ? "to" : interaction.isChannelSelectMenu() ? "channelId" : interaction.isRoleSelectMenu() ? "roleId" : "userId"]: interaction.values[0].split("/").slice(1)
97
- })
120
+ path: urlToPathString(
121
+ fillParams(path2, {
122
+ ts: interaction.createdTimestamp.toString(),
123
+ [interaction.isChannelSelectMenu() ? "channelId" : interaction.isRoleSelectMenu() ? "roleId" : "userId"]: interaction.values[0].split("/").slice(1)
124
+ })
125
+ )
98
126
  };
99
127
  }
100
128
  return false;
101
129
  };
102
130
  var parseMethodAndPath = (pathWithMethod) => {
103
131
  const firstSlash = pathWithMethod.indexOf("/");
104
- if (firstSlash <= 0) return false;
132
+ if (firstSlash < 0) return false;
105
133
  const method = ENCODING_TO_METHOD[pathWithMethod.slice(0, firstSlash)];
106
134
  if (method === void 0) return false;
107
135
  return {
@@ -109,13 +137,22 @@ var parseMethodAndPath = (pathWithMethod) => {
109
137
  path: pathWithMethod.slice(firstSlash)
110
138
  };
111
139
  };
140
+ var parseOptionalMethodAndPath = (pathWithMethod) => {
141
+ const firstSlash = pathWithMethod.indexOf("/");
142
+ if (firstSlash < 0) return false;
143
+ const method = ENCODING_TO_METHOD[pathWithMethod.slice(0, firstSlash)];
144
+ return {
145
+ method: method ?? "",
146
+ path: pathWithMethod.slice(firstSlash)
147
+ };
148
+ };
112
149
  var fillParams = (path2, params = {}) => {
113
150
  const url = new URL(path2, BASE_URL);
114
151
  const toPath = (0, import_path_to_regexp2.compile)(url.pathname);
115
152
  url.pathname = toPath(params);
116
153
  for (const [key, value] of url.searchParams) {
117
- if (value.startsWith(":") && key.slice(1) in params) {
118
- const paramValue = params?.[key.slice(1)];
154
+ if (value.startsWith(":") && value.slice(1) in params) {
155
+ const paramValue = params?.[value.slice(1)];
119
156
  if (paramValue) {
120
157
  url.searchParams.set(
121
158
  key,
@@ -126,6 +163,9 @@ var fillParams = (path2, params = {}) => {
126
163
  }
127
164
  }
128
165
  }
166
+ return url;
167
+ };
168
+ var urlToPathString = (url) => {
129
169
  return `${url.pathname}${url.search}`;
130
170
  };
131
171
 
@@ -143,6 +183,8 @@ var EmbedRouter = class _EmbedRouter {
143
183
  }
144
184
  // All added routes
145
185
  #routes = /* @__PURE__ */ new Map();
186
+ // message.id -> cleanup object
187
+ #cleanups = /* @__PURE__ */ new Map();
146
188
  /**
147
189
  *
148
190
  * @param name the name to give the router. ensures buttons stay connected across restarts
@@ -266,10 +308,13 @@ var EmbedRouter = class _EmbedRouter {
266
308
  * @param interaction interactions from "interactionCreate" (filter for ButtonInteractions)
267
309
  */
268
310
  async listener(interaction, locals) {
311
+ if (interaction.isAutocomplete())
312
+ throw new Error("Autocomplete Interactions aren't supported");
313
+ this.#runCleanup(interaction.message.id, false);
269
314
  const res = decodePath({ idPrefix: this.getIdPrefix(), interaction });
270
315
  if (!res)
271
316
  throw new Error(`Invalid component found: id ${interaction.customId}`);
272
- this.dispatch({ interaction, method: res.method, path: res.path, locals });
317
+ this.dispatch(interaction, res.path, { method: res.method, locals });
273
318
  }
274
319
  /**
275
320
  * Replies to or editReplies to an interaction based on the route output
@@ -280,19 +325,16 @@ var EmbedRouter = class _EmbedRouter {
280
325
  * @param flags discord flags to send with message (optional, only allowed on first reply)
281
326
  * @param locals additional info to pass in to page through state.local (optional)
282
327
  */
283
- async dispatch({
284
- interaction,
328
+ async dispatch(interaction, path2, {
285
329
  method = "GET",
286
- path: path2,
287
330
  flags,
288
331
  locals
289
- }) {
332
+ } = {}) {
290
333
  if (interaction.isAutocomplete())
291
334
  throw new Error("Autocomplete Interactions aren't supported");
292
- const routeResponse = await this.#resolve({
335
+ const routeResponse = await this.#resolve(path2, {
293
336
  interaction,
294
337
  method,
295
- path: path2,
296
338
  locals
297
339
  });
298
340
  if (routeResponse === false)
@@ -316,11 +358,28 @@ var EmbedRouter = class _EmbedRouter {
316
358
  );
317
359
  await interaction.update(routeResponse);
318
360
  } else {
319
- interaction.reply({
361
+ await interaction.reply({
320
362
  ...routeResponse,
321
363
  flags
322
364
  });
323
365
  }
366
+ if (!routeResponse?.cleanup) return;
367
+ const message = await interaction.fetchReply();
368
+ const channel = interaction.channel;
369
+ const applyFn = message.flags.has(
370
+ import_discord.MessageFlags.Ephemeral
371
+ ) ? interaction.editReply.bind(interaction) : channel ? (options) => channel.messages.edit(message.id, options) : void 0;
372
+ if (!applyFn)
373
+ return process.emitWarning(
374
+ `Could not derive applyFunction for ${pathToString(path2, false)}. Cleanup return results will not be applied to message.`,
375
+ "EmbedRouterWarning"
376
+ );
377
+ this.#addCleanup(
378
+ message.id,
379
+ routeResponse.cleanup.bind(routeResponse),
380
+ applyFn,
381
+ routeResponse?.timeout
382
+ );
324
383
  }
325
384
  /**
326
385
  * Resolves a route to the associated message (DOES NOT UPDATE MESSAGE)
@@ -331,10 +390,9 @@ var EmbedRouter = class _EmbedRouter {
331
390
  * @param locals additional info to pass in to page through state.local (optional)
332
391
  * @returns discord message associated with route OR false
333
392
  */
334
- async #resolve({
393
+ async #resolve(path2, {
335
394
  interaction,
336
395
  method = "GET",
337
- path: path2,
338
396
  locals
339
397
  }) {
340
398
  const url = new URL(pathToString(path2, false), BASE_URL);
@@ -351,10 +409,34 @@ var EmbedRouter = class _EmbedRouter {
351
409
  }
352
410
  return false;
353
411
  }
412
+ // Helpers for using and storing cleanup functions
413
+ #addCleanup(messageId, cleanupFn, applyFn, timeout) {
414
+ this.#removeCleanup(messageId);
415
+ this.#cleanups.set(messageId, {
416
+ cleanupFn,
417
+ applyFn,
418
+ timeout: isFinite(timeout) ? setTimeout(() => this.#runCleanup(messageId, true), timeout) : void 0
419
+ });
420
+ }
421
+ #removeCleanup(messageId) {
422
+ const cleanup = this.#cleanups.get(messageId);
423
+ if (!cleanup) return;
424
+ clearTimeout(cleanup.timeout);
425
+ this.#cleanups.delete(messageId);
426
+ }
427
+ async #runCleanup(messageId, applyResult) {
428
+ const cleanup = this.#cleanups.get(messageId);
429
+ if (!cleanup) return;
430
+ this.#removeCleanup(messageId);
431
+ const result = await cleanup?.cleanupFn();
432
+ if (applyResult && result) {
433
+ await cleanup.applyFn(result).catch(console.error);
434
+ }
435
+ }
354
436
  };
355
437
 
356
438
  // src/componentBuilders/RouteButtonBuilder.ts
357
- var import_discord = require("discord.js");
439
+ var import_discord2 = require("discord.js");
358
440
 
359
441
  // src/helpers/encodePath.ts
360
442
  var encodePath = ({
@@ -369,16 +451,11 @@ var encodePath = ({
369
451
  url.searchParams.set(key, value);
370
452
  }
371
453
  }
372
- return `${idPrefix}${METHOD_TO_ENCODING[method]}${url.pathname}${url.search}`;
373
- };
374
-
375
- // src/types/componentBuilders.ts
376
- var isSetOptions = (u) => {
377
- 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 && ["object", "string"].includes(typeof u.query) || u.query === void 0);
454
+ return `${idPrefix}${method === "" ? "" : METHOD_TO_ENCODING[method]}${url.pathname}${url.search}`;
378
455
  };
379
456
 
380
457
  // src/componentBuilders/RouteButtonBuilder.ts
381
- var RouteButtonBuilder = class extends import_discord.ButtonBuilder {
458
+ var RouteButtonBuilder = class extends import_discord2.ButtonBuilder {
382
459
  #embedRouter;
383
460
  /**
384
461
  *
@@ -407,12 +484,14 @@ var RouteButtonBuilder = class extends import_discord.ButtonBuilder {
407
484
  setCustomId() {
408
485
  throw new Error("setCustomId is not supported on RouteButtonBuilder");
409
486
  }
410
- setTo(arg) {
411
- const {
412
- method = "GET",
413
- path: path2,
414
- query
415
- } = isSetOptions(arg) ? arg : { path: arg };
487
+ /**
488
+ * Sets the path to route to when clicked
489
+ *
490
+ * @param path the path to route to, can include :ts
491
+ * @param query any query parameters you want to add, can include :ts
492
+ * @param method method to send to route
493
+ */
494
+ setTo(path2, { method = "GET", query } = {}) {
416
495
  super.setCustomId(
417
496
  encodePath({
418
497
  idPrefix: this.#embedRouter.getIdPrefix(),
@@ -426,11 +505,11 @@ var RouteButtonBuilder = class extends import_discord.ButtonBuilder {
426
505
  };
427
506
 
428
507
  // src/componentBuilders/RouteStringSelectMenuBuilder.ts
429
- var import_discord3 = require("discord.js");
508
+ var import_discord4 = require("discord.js");
430
509
 
431
- // src/componentBuilders/RouteStringMenuOptionBuilder.ts
432
- var import_discord2 = require("discord.js");
433
- var RouteStringSelectMenuOptionBuilder = class extends import_discord2.StringSelectMenuOptionBuilder {
510
+ // src/componentBuilders/RouteStringSelectMenuOptionBuilder.ts
511
+ var import_discord3 = require("discord.js");
512
+ var RouteStringSelectMenuOptionBuilder = class extends import_discord3.StringSelectMenuOptionBuilder {
434
513
  /**
435
514
  * Not supported for RouteStringSelectMenuOptionBuilder (use setTo)
436
515
  *
@@ -442,12 +521,14 @@ var RouteStringSelectMenuOptionBuilder = class extends import_discord2.StringSel
442
521
  "setValue is not supported on RouteStringSelectMenuOptionBuilder"
443
522
  );
444
523
  }
445
- setTo(arg) {
446
- const {
447
- method = "GET",
448
- path: path2,
449
- query
450
- } = isSetOptions(arg) ? arg : { path: arg };
524
+ /**
525
+ * Sets the path to route to when selected
526
+ *
527
+ * @param path the path to route to, can include :ts
528
+ * @param query any query parameters you want to add, can include :ts
529
+ * @param method method to send to route
530
+ */
531
+ setTo(path2, { method = "", query } = {}) {
451
532
  super.setValue(
452
533
  encodePath({
453
534
  idPrefix: "",
@@ -461,7 +542,7 @@ var RouteStringSelectMenuOptionBuilder = class extends import_discord2.StringSel
461
542
  };
462
543
 
463
544
  // src/componentBuilders/RouteStringSelectMenuBuilder.ts
464
- var RouteStringSelectMenuBuilder = class extends import_discord3.StringSelectMenuBuilder {
545
+ var RouteStringSelectMenuBuilder = class extends import_discord4.StringSelectMenuBuilder {
465
546
  #embedRouter;
466
547
  /**
467
548
  *
@@ -520,7 +601,7 @@ var RouteStringSelectMenuBuilder = class extends import_discord3.StringSelectMen
520
601
  * @param tos the list of route select menu options
521
602
  */
522
603
  addTos(...tos) {
523
- const resolved = (0, import_discord3.normalizeArray)(tos);
604
+ const resolved = (0, import_discord4.normalizeArray)(tos);
524
605
  super.addOptions(
525
606
  resolved.map(
526
607
  (o) => o instanceof RouteStringSelectMenuOptionBuilder ? o : new RouteStringSelectMenuOptionBuilder(o)
@@ -534,7 +615,7 @@ var RouteStringSelectMenuBuilder = class extends import_discord3.StringSelectMen
534
615
  * @param tos the list of route select menu options
535
616
  */
536
617
  setTos(...tos) {
537
- const resolved = (0, import_discord3.normalizeArray)(tos);
618
+ const resolved = (0, import_discord4.normalizeArray)(tos);
538
619
  super.setOptions(
539
620
  resolved.map(
540
621
  (o) => o instanceof RouteStringSelectMenuOptionBuilder ? o : new RouteStringSelectMenuOptionBuilder(o)
@@ -542,12 +623,14 @@ var RouteStringSelectMenuBuilder = class extends import_discord3.StringSelectMen
542
623
  );
543
624
  return this;
544
625
  }
545
- setPattern(arg) {
546
- const {
547
- method = "GET",
548
- path: path2,
549
- query
550
- } = isSetOptions(arg) ? arg : { path: arg };
626
+ /**
627
+ * Sets the pattern to redirect to (Required)
628
+ *
629
+ * @param path the path to redirect to, can include :ts :to *to
630
+ * @param query any query parameters you want to add, can include :ts :to *to
631
+ * @param method method to send to route
632
+ */
633
+ setPattern(path2, { method = "GET", query } = {}) {
551
634
  super.setCustomId(
552
635
  encodePath({
553
636
  idPrefix: this.#embedRouter.getIdPrefix(),
@@ -561,8 +644,8 @@ var RouteStringSelectMenuBuilder = class extends import_discord3.StringSelectMen
561
644
  };
562
645
 
563
646
  // src/componentBuilders/RouteChannelSelectMenuBuilder.ts
564
- var import_discord4 = require("discord.js");
565
- var RouteChannelSelectMenuBuilder = class extends import_discord4.ChannelSelectMenuBuilder {
647
+ var import_discord5 = require("discord.js");
648
+ var RouteChannelSelectMenuBuilder = class extends import_discord5.ChannelSelectMenuBuilder {
566
649
  #embedRouter;
567
650
  /**
568
651
  *
@@ -584,12 +667,14 @@ var RouteChannelSelectMenuBuilder = class extends import_discord4.ChannelSelectM
584
667
  "setCustomId is not supported on RouteChannelSelectMenuBuilder"
585
668
  );
586
669
  }
587
- setPattern(arg) {
588
- const {
589
- method = "GET",
590
- path: path2,
591
- query
592
- } = isSetOptions(arg) ? arg : { path: arg };
670
+ /**
671
+ * Sets the pattern to redirect to (Required)
672
+ *
673
+ * @param path the path to redirect to, can include :ts :channelId
674
+ * @param query any query parameters you want to add, can include :ts :channelId
675
+ * @param method method to send to route
676
+ */
677
+ setPattern(path2, { method = "GET", query } = {}) {
593
678
  super.setCustomId(
594
679
  encodePath({
595
680
  idPrefix: this.#embedRouter.getIdPrefix(),
@@ -603,8 +688,8 @@ var RouteChannelSelectMenuBuilder = class extends import_discord4.ChannelSelectM
603
688
  };
604
689
 
605
690
  // src/componentBuilders/RouteRoleSelectMenuBuilder.ts
606
- var import_discord5 = require("discord.js");
607
- var RouteRoleSelectMenuBuilder = class extends import_discord5.RoleSelectMenuBuilder {
691
+ var import_discord6 = require("discord.js");
692
+ var RouteRoleSelectMenuBuilder = class extends import_discord6.RoleSelectMenuBuilder {
608
693
  #embedRouter;
609
694
  /**
610
695
  *
@@ -626,12 +711,14 @@ var RouteRoleSelectMenuBuilder = class extends import_discord5.RoleSelectMenuBui
626
711
  "setCustomId is not supported on RouteRoleSelectMenuBuilder"
627
712
  );
628
713
  }
629
- setPattern(arg) {
630
- const {
631
- method = "GET",
632
- path: path2,
633
- query
634
- } = isSetOptions(arg) ? arg : { path: arg };
714
+ /**
715
+ * Sets the pattern to redirect to (Required)
716
+ *
717
+ * @param path the path to redirect to, can include :ts :roleId
718
+ * @param query any query parameters you want to add, can include :ts :roleId
719
+ * @param method method to send to route
720
+ */
721
+ setPattern(path2, { method = "GET", query } = {}) {
635
722
  super.setCustomId(
636
723
  encodePath({
637
724
  idPrefix: this.#embedRouter.getIdPrefix(),
@@ -645,8 +732,8 @@ var RouteRoleSelectMenuBuilder = class extends import_discord5.RoleSelectMenuBui
645
732
  };
646
733
 
647
734
  // src/componentBuilders/RouteUserSelectMenuBuilder.ts
648
- var import_discord6 = require("discord.js");
649
- var RouteUserSelectMenuBuilder = class extends import_discord6.UserSelectMenuBuilder {
735
+ var import_discord7 = require("discord.js");
736
+ var RouteUserSelectMenuBuilder = class extends import_discord7.UserSelectMenuBuilder {
650
737
  #embedRouter;
651
738
  /**
652
739
  *
@@ -668,12 +755,14 @@ var RouteUserSelectMenuBuilder = class extends import_discord6.UserSelectMenuBui
668
755
  "setCustomId is not supported on RouteUserSelectMenuBuilder"
669
756
  );
670
757
  }
671
- setPattern(arg) {
672
- const {
673
- method = "GET",
674
- path: path2,
675
- query
676
- } = isSetOptions(arg) ? arg : { path: arg };
758
+ /**
759
+ * Sets the pattern to redirect to (Required)
760
+ *
761
+ * @param path the path to redirect to, can include :ts :userId
762
+ * @param query any query parameters you want to add, can include :ts :userId
763
+ * @param method method to send to route
764
+ */
765
+ setPattern(path2, { method = "GET", query } = {}) {
677
766
  super.setCustomId(
678
767
  encodePath({
679
768
  idPrefix: this.#embedRouter.getIdPrefix(),
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/EmbedRouter.ts","../src/consts.ts","../src/helpers/pathToString.ts","../src/helpers/decodePath.ts","../src/componentBuilders/RouteButtonBuilder.ts","../src/helpers/encodePath.ts","../src/types/componentBuilders.ts","../src/componentBuilders/RouteStringSelectMenuBuilder.ts","../src/componentBuilders/RouteStringMenuOptionBuilder.ts","../src/componentBuilders/RouteChannelSelectMenuBuilder.ts","../src/componentBuilders/RouteRoleSelectMenuBuilder.ts","../src/componentBuilders/RouteUserSelectMenuBuilder.ts"],"sourcesContent":["export { EmbedRouter } from \"./EmbedRouter\";\n\nexport { RouteButtonBuilder } from \"./componentBuilders/RouteButtonBuilder\";\nexport { RouteStringSelectMenuBuilder } from \"./componentBuilders/RouteStringSelectMenuBuilder\";\nexport { RouteStringSelectMenuOptionBuilder } from \"./componentBuilders/RouteStringMenuOptionBuilder\";\nexport { RouteChannelSelectMenuBuilder } from \"./componentBuilders/RouteChannelSelectMenuBuilder\";\nexport { RouteRoleSelectMenuBuilder } from \"./componentBuilders/RouteRoleSelectMenuBuilder\";\nexport { RouteUserSelectMenuBuilder } from \"./componentBuilders/RouteUserSelectMenuBuilder\";\n\nexport type * from \"./types/routes\";\n","import path from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport { match, MatchResult, Path } from \"path-to-regexp\";\nimport type {\n\tCompiledRoute,\n\tMethod,\n\tRouteHandler,\n\tRouteResponse,\n} from \"./types/routes\";\nimport type { ExtractParams } from \"./types/ExtractParams\";\nimport {\n\tAnySelectMenuInteraction,\n\tButtonInteraction,\n\tInteraction,\n\tInteractionReplyOptions,\n} from \"discord.js\";\nimport { BASE_URL, ID_PREFIX, PUA_RANGE, PUA_START } from \"./consts\";\nimport { pathToString } from \"./helpers/pathToString\";\nimport { decodePath } from \"./helpers/decodePath\";\n\nexport class EmbedRouter<L> {\n\t// identifier -> embedRouter\n\tstatic #usedIdentifiers = new Map<string, EmbedRouter<unknown>>();\n\n\t// Name used to generate prefixes\n\t#name = \"\";\n\t// Prefix for customIds of RouteButtonBuilders\n\t#idPrefix: string;\n\t#identifier: string = \"\";\n\tpublic getIdPrefix() {\n\t\treturn `${this.#idPrefix}${this.#identifier}`;\n\t}\n\n\t// All added routes\n\t#routes: Map<Method, CompiledRoute<Method, L>[]> = new Map();\n\n\t/**\n\t *\n\t * @param name the name to give the router. ensures buttons stay connected across restarts\n\t * @param idPrefix the prefix for RouteButtonBuilder customIds\n\t */\n\tconstructor({\n\t\tname = \"\",\n\t\tidPrefix = ID_PREFIX,\n\t}: {\n\t\tname?: string | undefined;\n\t\tidPrefix?: string | undefined;\n\t} = {}) {\n\t\tif (EmbedRouter.#usedIdentifiers.size >= PUA_RANGE) {\n\t\t\tthrow new Error(`You can not have more than ${PUA_RANGE} routers`);\n\t\t}\n\t\tif (idPrefix.includes(\"/\")) {\n\t\t\tthrow new Error(`Prefix can't contain \"/\": ${idPrefix}`);\n\t\t}\n\t\tthis.#idPrefix = idPrefix;\n\t\tthis.#name = name;\n\t\tthis.#updateIdentifier();\n\t}\n\n\t#updateIdentifier() {\n\t\t// Private Use Area: Unicode Characters not from any language\n\t\tconst hash = createHash(\"sha256\").update(this.#name).digest();\n\t\tlet raw = hash.readUint32BE(0);\n\t\tlet char: string;\n\t\tconst nameCollisions = [];\n\t\t// find next available identifier\n\t\twhile (true) {\n\t\t\tconst codepoint = PUA_START + (raw++ % PUA_RANGE);\n\t\t\tchar = String.fromCodePoint(codepoint);\n\n\t\t\tconst collisionRouter = EmbedRouter.#usedIdentifiers.get(char);\n\t\t\tif (collisionRouter === undefined) break; // no collisions\n\n\t\t\tif (this.#name.length > 0 && collisionRouter.#name.length === 0) {\n\t\t\t\t// evict old name; usedIdentifier is still taken\n\t\t\t\tcollisionRouter.#updateIdentifier();\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tnameCollisions.push(collisionRouter);\n\t\t}\n\t\tEmbedRouter.#usedIdentifiers.set(char, this as EmbedRouter<unknown>);\n\n\t\tif (nameCollisions.length > 0 && this.#name.length > 0) {\n\t\t\tprocess.emitWarning(\n\t\t\t\t`EmbedRouter identifier collision for name \"${this.#name}\" with ${nameCollisions.map((c) => `\"${c.#name}\"`).join(\", \")}`,\n\t\t\t\t\"EmbedRouterWarning\",\n\t\t\t);\n\t\t}\n\t\tthis.#identifier = char;\n\t}\n\n\t#addRoute<M extends Method, P extends Path = Path>(\n\t\tmethod: M,\n\t\troutePath: P | P[],\n\t\thandler: RouteHandler<M, L, ExtractParams<P>>,\n\t) {\n\t\tconst methodRoutes = this.#routes.get(method) ?? [];\n\t\tmethodRoutes.push({\n\t\t\tmethod,\n\t\t\tpath: Array.isArray(routePath) ? routePath : [routePath],\n\t\t\tmatchFunction: match(routePath),\n\t\t\thandler: handler as RouteHandler<M, L>,\n\t\t});\n\t\tthis.#routes.set(method, methodRoutes);\n\t}\n\n\t/**\n\t * Registers a path with the router\n\t *\n\t * @param routePath path to match with\n\t * @param handler function that generates the message when a path is matched\n\t */\n\tpublic get<P extends Path = Path>(\n\t\troutePath: P | P[],\n\t\thandler: RouteHandler<\"GET\", L, ExtractParams<P>>,\n\t) {\n\t\tthis.#addRoute(\"GET\", routePath, handler);\n\t}\n\n\t/**\n\t * Registers a path with the router\n\t *\n\t * @param routePath path to match with\n\t * @param handler function that generates the message when a path is matched\n\t */\n\tpublic post<P extends Path = Path>(\n\t\troutePath: P | P[],\n\t\thandler: RouteHandler<\"POST\", L, ExtractParams<P>>,\n\t) {\n\t\tthis.#addRoute(\"POST\", routePath, handler);\n\t}\n\n\t/**\n\t * Registers a path with the router\n\t *\n\t * @param routePath path to match with\n\t * @param handler function that generates the message when a path is matched\n\t */\n\tpublic put<P extends Path = Path>(\n\t\troutePath: P | P[],\n\t\thandler: RouteHandler<\"PUT\", L, ExtractParams<P>>,\n\t) {\n\t\tthis.#addRoute(\"PUT\", routePath, handler);\n\t}\n\n\t/**\n\t * Registers a path with the router\n\t *\n\t * @param routePath path to match with\n\t * @param handler function that generates the message when a path is matched\n\t */\n\tpublic patch<P extends Path = Path>(\n\t\troutePath: P | P[],\n\t\thandler: RouteHandler<\"PATCH\", L, ExtractParams<P>>,\n\t) {\n\t\tthis.#addRoute(\"PATCH\", routePath, handler);\n\t}\n\n\t/**\n\t * Registers a path with the router\n\t *\n\t * @param routePath path to match with\n\t * @param handler function that generates the message when a path is matched\n\t */\n\tpublic delete<P extends Path = Path>(\n\t\troutePath: P | P[],\n\t\thandler: RouteHandler<\"DELETE\", L, ExtractParams<P>>,\n\t) {\n\t\tthis.#addRoute(\"DELETE\", routePath, handler);\n\t}\n\n\t/**\n\t * Adds a subrouter to the router\n\t *\n\t * @param routePath path of the router\n\t * @param embedRouter router to add at the path\n\t */\n\tpublic use<P extends Path = Path>(routePath: P, embedRouter: EmbedRouter<L>) {\n\t\tconst pathString = pathToString(routePath);\n\t\tfor (const [method, routes] of embedRouter.#routes) {\n\t\t\tfor (const route of routes) {\n\t\t\t\tthis.#addRoute(\n\t\t\t\t\tmethod,\n\t\t\t\t\troute.path.map((p) => path.posix.join(pathString, pathToString(p))),\n\t\t\t\t\troute.handler,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Must be attached to \"interactionCreate\" event for RouteButtonBuilder to work\n\t *\n\t * @param interaction interactions from \"interactionCreate\" (filter for ButtonInteractions)\n\t */\n\tpublic async listener(\n\t\tinteraction: ButtonInteraction | AnySelectMenuInteraction,\n\t\tlocals?: L | undefined,\n\t) {\n\t\tconst res = decodePath({ idPrefix: this.getIdPrefix(), interaction });\n\t\tif (!res)\n\t\t\tthrow new Error(`Invalid component found: id ${interaction.customId}`);\n\n\t\tthis.dispatch({ interaction, method: res.method, path: res.path, locals });\n\t}\n\n\t/**\n\t * Replies to or editReplies to an interaction based on the route output\n\t *\n\t * @param interaction interaction to connect to\n\t * @param path path to route the interaction to\n\t * @param method method to send to route\n\t * @param flags discord flags to send with message (optional, only allowed on first reply)\n\t * @param locals additional info to pass in to page through state.local (optional)\n\t */\n\tpublic async dispatch<P extends Path = Path>({\n\t\tinteraction,\n\t\tmethod = \"GET\",\n\t\tpath,\n\t\tflags,\n\t\tlocals,\n\t}: {\n\t\tinteraction: Interaction;\n\t\tmethod?: Method;\n\t\tpath: P;\n\t\tflags?: InteractionReplyOptions[\"flags\"] | undefined;\n\t\tlocals?: L | undefined;\n\t}) {\n\t\tif (interaction.isAutocomplete())\n\t\t\tthrow new Error(\"Autocomplete Interactions aren't supported\");\n\n\t\t// don't check validity because url params are considered invalid\n\t\tconst routeResponse = await this.#resolve({\n\t\t\tinteraction,\n\t\t\tmethod,\n\t\t\tpath,\n\t\t\tlocals,\n\t\t});\n\t\tif (routeResponse === false)\n\t\t\tthrow new Error(`No route found for ${pathToString(path, false)}`);\n\n\t\tif (interaction.replied || interaction.deferred) {\n\t\t\tif (flags)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"You can only set flags for interactions that haven't been replied to\",\n\t\t\t\t);\n\t\t\tif (routeResponse) await interaction.editReply(routeResponse);\n\t\t} else if (!routeResponse) {\n\t\t\tif (\"deferUpdate\" in interaction) {\n\t\t\t\tawait interaction.deferUpdate();\n\t\t\t} else {\n\t\t\t\tawait interaction.deferReply();\n\t\t\t}\n\t\t} else if (\"update\" in interaction) {\n\t\t\tif (flags)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"You can only set flags for interactions that haven't been replied to\",\n\t\t\t\t);\n\t\t\tawait interaction.update(routeResponse);\n\t\t} else {\n\t\t\tinteraction.reply({\n\t\t\t\t...(routeResponse as InteractionReplyOptions),\n\t\t\t\tflags,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Resolves a route to the associated message (DOES NOT UPDATE MESSAGE)\n\t *\n\t * @param interaction interaction to connect to\n\t * @param path path to route the interaction to\n\t * @param method method to send to route\n\t * @param locals additional info to pass in to page through state.local (optional)\n\t * @returns discord message associated with route OR false\n\t */\n\tasync #resolve<P extends Path>({\n\t\tinteraction,\n\t\tmethod = \"GET\",\n\t\tpath,\n\t\tlocals,\n\t}: {\n\t\tinteraction: Interaction;\n\t\tmethod?: Method;\n\t\tpath: P;\n\t\tlocals?: L | undefined;\n\t}): Promise<RouteResponse | false> {\n\t\t// don't check validity because url params are considered invalid\n\t\tconst url = new URL(pathToString(path, false), BASE_URL);\n\t\tfor (const route of this.#routes.get(method) ?? []) {\n\t\t\tconst result = route.matchFunction(url.pathname);\n\t\t\tif (result) {\n\t\t\t\treturn await route.handler(interaction, {\n\t\t\t\t\t...(result as MatchResult<ExtractParams<P>>),\n\t\t\t\t\tquery: url.searchParams,\n\t\t\t\t\tembedRouter: this,\n\t\t\t\t\tlocals,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n}\n","import { Method } from \"./types/routes\";\n\nexport const ID_PREFIX = \"der\";\nexport const METHOD_TO_ENCODING: Record<Method, string> = {\n\tGET: \"G\",\n\tPOST: \"P\",\n\tPUT: \"U\",\n\tPATCH: \"A\",\n\tDELETE: \"D\",\n};\nexport const ENCODING_TO_METHOD: Record<string, Method> = {\n\tG: \"GET\",\n\tP: \"POST\",\n\tU: \"PUT\",\n\tA: \"PATCH\",\n\tD: \"DELETE\",\n};\n// base url is never sent; only used for processing locally\nexport const BASE_URL = \"discord://embed.router\";\n\nexport const PUA_START = 0xe000;\nexport const PUA_END = 0xf8ff;\nexport const PUA_RANGE = PUA_END - PUA_START + 1;\n","import { parse, Path, stringify, TokenData } from \"path-to-regexp\";\n\nexport const pathToString = <P extends Path>(\n\tpath: P,\n\tcheckValidity = true,\n): string => {\n\tif (checkValidity) {\n\t\treturn stringify(path instanceof TokenData ? path : parse(path));\n\t}\n\treturn typeof path === \"string\" ? path : stringify(path);\n};\n","import { compile, Path } from \"path-to-regexp\";\nimport { AnySelectMenuInteraction, ButtonInteraction } from \"discord.js\";\nimport { BASE_URL, ENCODING_TO_METHOD } from \"../consts\";\nimport { Method } from \"../types/routes\";\n\nexport const decodePath = ({\n\tidPrefix,\n\tinteraction,\n}: {\n\tidPrefix: string;\n\tinteraction: ButtonInteraction | AnySelectMenuInteraction;\n}): { method: Method; path: Path } | false => {\n\tconst customId = interaction.customId;\n\tif (!customId.startsWith(idPrefix)) return false;\n\n\tif (interaction.isButton()) {\n\t\treturn parseMethodAndPath(customId.slice(idPrefix.length));\n\t} else if (interaction.isAnySelectMenu()) {\n\t\tif (interaction.values.length === 0) return false;\n\t\tconst res = parseMethodAndPath(customId.slice(idPrefix.length));\n\t\tif (!res) return false;\n\n\t\tconst { method, path } = res;\n\t\treturn {\n\t\t\tmethod,\n\t\t\tpath: fillParams(path, {\n\t\t\t\t[interaction.isStringSelectMenu()\n\t\t\t\t\t? \"to\"\n\t\t\t\t\t: interaction.isChannelSelectMenu()\n\t\t\t\t\t\t? \"channelId\"\n\t\t\t\t\t\t: interaction.isRoleSelectMenu()\n\t\t\t\t\t\t\t? \"roleId\"\n\t\t\t\t\t\t\t: \"userId\"]: interaction.values[0]!.split(\"/\").slice(1),\n\t\t\t}),\n\t\t};\n\t}\n\n\treturn false;\n};\n\nexport const parseMethodAndPath = (\n\tpathWithMethod: string,\n): { method: Method; path: string } | false => {\n\t// path always start with \"/\"\n\tconst firstSlash = pathWithMethod.indexOf(\"/\");\n\t// invalid customId\n\tif (firstSlash <= 0) return false;\n\n\tconst method = ENCODING_TO_METHOD[pathWithMethod.slice(0, firstSlash)];\n\tif (method === undefined) return false;\n\treturn {\n\t\tmethod,\n\t\tpath: pathWithMethod.slice(firstSlash),\n\t};\n};\n\nconst fillParams = (\n\tpath: string,\n\tparams: Partial<Record<string, string | string[]>> = {},\n): string => {\n\tconst url = new URL(path, BASE_URL);\n\tconst toPath = compile(url.pathname);\n\n\turl.pathname = toPath(params);\n\tfor (const [key, value] of url.searchParams) {\n\t\tif (value.startsWith(\":\") && key.slice(1) in params) {\n\t\t\tconst paramValue = params?.[key.slice(1)];\n\t\t\tif (paramValue) {\n\t\t\t\turl.searchParams.set(\n\t\t\t\t\tkey,\n\t\t\t\t\tArray.isArray(paramValue) ? paramValue.join(\"/\") : paramValue,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\turl.searchParams.delete(key);\n\t\t\t}\n\t\t}\n\t}\n\treturn `${url.pathname}${url.search}`;\n};\n","import { APIButtonComponent, ButtonBuilder } from \"discord.js\";\nimport { Path } from \"path-to-regexp\";\nimport { EmbedRouter } from \"../EmbedRouter\";\nimport { encodePath } from \"../helpers/encodePath\";\nimport { isSetOptions, SetOptions } from \"../types/componentBuilders\";\n\nexport class RouteButtonBuilder<L> extends ButtonBuilder {\n\t#embedRouter: EmbedRouter<L>;\n\n\t/**\n\t *\n\t * @param embedRouter the router you want to route with\n\t * @param data the data to construct a component out of\n\t */\n\tconstructor(\n\t\tembedRouter: EmbedRouter<L>,\n\t\tdata?: Omit<Partial<APIButtonComponent>, \"custom_id\" | \"url\"> | undefined,\n\t) {\n\t\tsuper(data);\n\n\t\tthis.#embedRouter = embedRouter;\n\t}\n\n\t/**\n\t * Not supported for RouteButtonBuilder\n\t *\n\t * @remarks\n\t * @param\n\t */\n\toverride setURL(): this {\n\t\tthrow new Error(\"setURL is not supported on RouteButtonBuilder\");\n\t}\n\n\t/**\n\t * Not supported for RouteButtonBuilder (use setTo)\n\t *\n\t * @remarks\n\t * @param\n\t */\n\toverride setCustomId(): this {\n\t\tthrow new Error(\"setCustomId is not supported on RouteButtonBuilder\");\n\t}\n\n\t/**\n\t * Sets the path to route to when clicked\n\t *\n\t * @param path the path to route to\n\t * @param query any query parameters you want to add\n\t * @param method method to send to route\n\t */\n\tpublic setTo<P extends Path>({ method, path, query }: SetOptions<P>): this;\n\t/**\n\t * Sets the path to route to when clicked\n\t *\n\t * @param path the path to route to\n\t */\n\tpublic setTo<P extends Path>(path: P): this;\n\n\tpublic setTo<P extends Path>(arg: P | SetOptions<P>) {\n\t\tconst {\n\t\t\tmethod = \"GET\",\n\t\t\tpath,\n\t\t\tquery,\n\t\t} = isSetOptions(arg) ? arg : { path: arg };\n\n\t\tsuper.setCustomId(\n\t\t\tencodePath({\n\t\t\t\tidPrefix: this.#embedRouter.getIdPrefix(),\n\t\t\t\tmethod,\n\t\t\t\tpath,\n\t\t\t\tquery,\n\t\t\t}),\n\t\t);\n\n\t\treturn this;\n\t}\n}\n","import { Path } from \"path-to-regexp\";\nimport { BASE_URL, METHOD_TO_ENCODING } from \"../consts\";\nimport { pathToString } from \"./pathToString\";\nimport { Method } from \"../types/routes\";\n\nexport const encodePath = ({\n\tidPrefix,\n\tmethod,\n\tpath,\n\tquery,\n}: {\n\tidPrefix: string;\n\tmethod: Method;\n\tpath: Path;\n\tquery?: ConstructorParameters<typeof URLSearchParams>[0] | undefined;\n}) => {\n\tconst url = new URL(pathToString(path), BASE_URL);\n\tif (query) {\n\t\tfor (const [key, value] of new URLSearchParams(query)) {\n\t\t\turl.searchParams.set(key, value);\n\t\t}\n\t}\n\treturn `${idPrefix}${METHOD_TO_ENCODING[method]}${url.pathname}${url.search}`;\n};\n","import { Path } from \"path-to-regexp\";\nimport { Method } from \"./routes\";\n\nexport type SetOptions<P extends Path> = {\n\tmethod?: Method;\n\tpath: P;\n\tquery?: ConstructorParameters<typeof URLSearchParams>[0] | undefined;\n};\n\nexport const isSetOptions = <P extends Path>(\n\tu: unknown,\n): u is SetOptions<P> => {\n\treturn (\n\t\ttypeof u === \"object\" &&\n\t\tu !== null &&\n\t\t(!(\"method\" in u) ||\n\t\t\t(\"method\" in u && typeof u.method === \"string\") ||\n\t\t\tu.method === undefined) &&\n\t\t\"path\" in u &&\n\t\ttypeof u.path === \"string\" &&\n\t\t(!(\"query\" in u) ||\n\t\t\t(\"query\" in u && [\"object\", \"string\"].includes(typeof u.query)) ||\n\t\t\tu.query === undefined)\n\t);\n};\n","import {\n\tAPIStringSelectComponent,\n\tnormalizeArray,\n\tRestOrArray,\n\tStringSelectMenuBuilder,\n\tStringSelectMenuComponentData,\n} from \"discord.js\";\nimport { Path } from \"path-to-regexp\";\nimport { RouteStringSelectMenuOptionBuilder } from \"./RouteStringMenuOptionBuilder\";\nimport { EmbedRouter } from \"../EmbedRouter\";\nimport { encodePath } from \"../helpers/encodePath\";\nimport { isSetOptions, SetOptions } from \"../types/componentBuilders\";\n\nexport class RouteStringSelectMenuBuilder<L> extends StringSelectMenuBuilder {\n\t#embedRouter: EmbedRouter<L>;\n\n\t/**\n\t *\n\t * @param embedRouter the router you want to route with\n\t * @param path the path to redirect to, :to or *to in path will be replaced with the selected user's id\n\t * @param query any query parameters you want to add, :to will be replaced with the selected user's id\n\t * @param data the data to construct a component out of\n\t */\n\tconstructor(\n\t\tembedRouter: EmbedRouter<L>,\n\t\tdata?:\n\t\t\t| Partial<StringSelectMenuComponentData | APIStringSelectComponent>\n\t\t\t| undefined,\n\t) {\n\t\tsuper(data);\n\n\t\tthis.#embedRouter = embedRouter;\n\n\t\tsuper.setCustomId(\n\t\t\tencodePath({\n\t\t\t\tidPrefix: this.#embedRouter.getIdPrefix(),\n\t\t\t\tmethod: \"GET\",\n\t\t\t\tpath: \"/*to\",\n\t\t\t}),\n\t\t);\n\t}\n\n\t/**\n\t * Not supported for RouteStringSelectMenuBuilder (customId set from embedRouter)\n\t *\n\t * @remarks\n\t * @param\n\t */\n\toverride setCustomId(): this {\n\t\tthrow new Error(\n\t\t\t\"setCustomId is not supported on RouteStringSelectMenuBuilder\",\n\t\t);\n\t}\n\n\t/**\n\t * Not supported for RouteStringSelectMenuBuilder (use addTos)\n\t *\n\t * @remarks\n\t * @param\n\t */\n\toverride addOptions(): this {\n\t\tthrow new Error(\n\t\t\t\"addOptions is not supported on RouteStringSelectMenuBuilder\",\n\t\t);\n\t}\n\n\t/**\n\t * Not supported for RouteStringSelectMenuBuilder (use setTos)\n\t *\n\t * @remarks\n\t * @param\n\t */\n\toverride setOptions(): this {\n\t\tthrow new Error(\n\t\t\t\"setOptions is not supported on RouteStringSelectMenuBuilder\",\n\t\t);\n\t}\n\n\t/**\n\t * Adds route select menu options to builder\n\t *\n\t * @param tos the list of route select menu options\n\t */\n\tpublic addTos(\n\t\t...tos: RestOrArray<\n\t\t\t| RouteStringSelectMenuOptionBuilder\n\t\t\t| ConstructorParameters<typeof RouteStringSelectMenuOptionBuilder>[0]\n\t\t>\n\t): this {\n\t\tconst resolved = normalizeArray(tos);\n\t\tsuper.addOptions(\n\t\t\tresolved.map((o) =>\n\t\t\t\to instanceof RouteStringSelectMenuOptionBuilder\n\t\t\t\t\t? o\n\t\t\t\t\t: new RouteStringSelectMenuOptionBuilder(o),\n\t\t\t),\n\t\t);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets route select menu options to builder\n\t *\n\t * @param tos the list of route select menu options\n\t */\n\tpublic setTos(\n\t\t...tos: RestOrArray<\n\t\t\t| RouteStringSelectMenuOptionBuilder\n\t\t\t| ConstructorParameters<typeof RouteStringSelectMenuOptionBuilder>[0]\n\t\t>\n\t): this {\n\t\tconst resolved = normalizeArray(tos);\n\t\tsuper.setOptions(\n\t\t\tresolved.map((o) =>\n\t\t\t\to instanceof RouteStringSelectMenuOptionBuilder\n\t\t\t\t\t? o\n\t\t\t\t\t: new RouteStringSelectMenuOptionBuilder(o),\n\t\t\t),\n\t\t);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the pattern to redirect to (Required)\n\t *\n\t * @param path the path to redirect to, :to or *to in path will be replaced with the selected user's id\n\t * @param query any query parameters you want to add, :to will be replaced with the selected user's id\n\t * @param method method to send to route\n\t */\n\tpublic setPattern<P extends Path>({\n\t\tmethod,\n\t\tpath,\n\t\tquery,\n\t}: SetOptions<P>): this;\n\t/**\n\t * Sets the path to route to when clicked\n\t *\n\t * @param path the path to route to\n\t */\n\tpublic setPattern<P extends Path>(path: P): this;\n\n\tpublic setPattern<P extends Path>(arg: P | SetOptions<P>) {\n\t\tconst {\n\t\t\tmethod = \"GET\",\n\t\t\tpath,\n\t\t\tquery,\n\t\t} = isSetOptions(arg) ? arg : { path: arg };\n\t\tsuper.setCustomId(\n\t\t\tencodePath({\n\t\t\t\tidPrefix: this.#embedRouter.getIdPrefix(),\n\t\t\t\tmethod,\n\t\t\t\tpath,\n\t\t\t\tquery,\n\t\t\t}),\n\t\t);\n\n\t\treturn this;\n\t}\n}\n","import { StringSelectMenuOptionBuilder } from \"discord.js\";\nimport { Path } from \"path-to-regexp\";\nimport { encodePath } from \"../helpers/encodePath\";\nimport { isSetOptions, SetOptions } from \"../types/componentBuilders\";\n\nexport class RouteStringSelectMenuOptionBuilder extends StringSelectMenuOptionBuilder {\n\t/**\n\t * Not supported for RouteStringSelectMenuOptionBuilder (use setTo)\n\t *\n\t * @remarks\n\t * @param\n\t */\n\toverride setValue(): this {\n\t\tthrow new Error(\n\t\t\t\"setValue is not supported on RouteStringSelectMenuOptionBuilder\",\n\t\t);\n\t}\n\n\t/**\n\t * Sets the path to route to when clicked\n\t *\n\t * @param path the path to route to\n\t * @param query any query parameters you want to add\n\t * @param method method to send to route\n\t */\n\tpublic setTo<P extends Path>({ method, path, query }: SetOptions<P>): this;\n\t/**\n\t * Sets the path to route to when clicked\n\t *\n\t * @param path the path to route to\n\t */\n\tpublic setTo<P extends Path>(path: P): this;\n\n\tpublic setTo<P extends Path>(arg: P | SetOptions<P>) {\n\t\tconst {\n\t\t\tmethod = \"GET\",\n\t\t\tpath,\n\t\t\tquery,\n\t\t} = isSetOptions(arg) ? arg : { path: arg };\n\t\tsuper.setValue(\n\t\t\tencodePath({\n\t\t\t\tidPrefix: \"\",\n\t\t\t\tmethod,\n\t\t\t\tpath,\n\t\t\t\tquery,\n\t\t\t}),\n\t\t);\n\n\t\treturn this;\n\t}\n}\n","import {\n\tAPIChannelSelectComponent,\n\tChannelSelectMenuBuilder,\n\tChannelSelectMenuComponentData,\n} from \"discord.js\";\nimport { EmbedRouter } from \"../EmbedRouter\";\nimport { Path } from \"path-to-regexp\";\nimport { encodePath } from \"../helpers/encodePath\";\nimport { isSetOptions, SetOptions } from \"../types/componentBuilders\";\n\nexport class RouteChannelSelectMenuBuilder<L> extends ChannelSelectMenuBuilder {\n\t#embedRouter: EmbedRouter<L>;\n\n\t/**\n\t *\n\t * @param embedRouter the router you want to route with\n\t * @param data the data to construct a component out of\n\t */\n\tconstructor(\n\t\tembedRouter: EmbedRouter<L>,\n\t\tdata?:\n\t\t\t| Partial<ChannelSelectMenuComponentData | APIChannelSelectComponent>\n\t\t\t| undefined,\n\t) {\n\t\tsuper(data);\n\n\t\tthis.#embedRouter = embedRouter;\n\t}\n\n\t/**\n\t * Not supported for RouteChannelSelectMenuBuilder (customId set from embedRouter)\n\t *\n\t * @remarks\n\t * @param\n\t */\n\toverride setCustomId(): this {\n\t\tthrow new Error(\n\t\t\t\"setCustomId is not supported on RouteChannelSelectMenuBuilder\",\n\t\t);\n\t}\n\n\t/**\n\t * Sets the pattern to redirect to (Required)\n\t *\n\t * @param path the path to redirect to, :channelId in path will be replaced with the selected user's id\n\t * @param query any query parameters you want to add, :channelId will be replaced with the selected user's id\n\t * @param method method to send to route\n\t */\n\tpublic setPattern<P extends Path>({\n\t\tmethod,\n\t\tpath,\n\t\tquery,\n\t}: SetOptions<P>): this;\n\t/**\n\t * Sets the path to route to when clicked\n\t *\n\t * @param path the path to route to\n\t */\n\tpublic setPattern<P extends Path>(path: P): this;\n\n\tpublic setPattern<P extends Path>(arg: P | SetOptions<P>) {\n\t\tconst {\n\t\t\tmethod = \"GET\",\n\t\t\tpath,\n\t\t\tquery,\n\t\t} = isSetOptions(arg) ? arg : { path: arg };\n\t\tsuper.setCustomId(\n\t\t\tencodePath({\n\t\t\t\tidPrefix: this.#embedRouter.getIdPrefix(),\n\t\t\t\tmethod,\n\t\t\t\tpath,\n\t\t\t\tquery,\n\t\t\t}),\n\t\t);\n\n\t\treturn this;\n\t}\n}\n","import {\n\tAPIRoleSelectComponent,\n\tRoleSelectMenuBuilder,\n\tRoleSelectMenuComponentData,\n} from \"discord.js\";\nimport { EmbedRouter } from \"../EmbedRouter\";\nimport { Path } from \"path-to-regexp\";\nimport { encodePath } from \"../helpers/encodePath\";\nimport { isSetOptions, SetOptions } from \"../types/componentBuilders\";\n\nexport class RouteRoleSelectMenuBuilder<L> extends RoleSelectMenuBuilder {\n\t#embedRouter: EmbedRouter<L>;\n\n\t/**\n\t *\n\t * @param embedRouter the router you want to route with\n\t * @param data the data to construct a component out of\n\t */\n\tconstructor(\n\t\tembedRouter: EmbedRouter<L>,\n\t\tdata?:\n\t\t\tPartial<RoleSelectMenuComponentData | APIRoleSelectComponent> | undefined,\n\t) {\n\t\tsuper(data);\n\n\t\tthis.#embedRouter = embedRouter;\n\t}\n\n\t/**\n\t * Not supported for RouteRoleSelectMenuBuilder (customId set from embedRouter)\n\t *\n\t * @remarks\n\t * @param\n\t */\n\toverride setCustomId(): this {\n\t\tthrow new Error(\n\t\t\t\"setCustomId is not supported on RouteRoleSelectMenuBuilder\",\n\t\t);\n\t}\n\n\t/**\n\t * Sets the pattern to redirect to (Required)\n\t *\n\t * @param path the path to redirect to, :roleId in path will be replaced with the selected user's id\n\t * @param query any query parameters you want to add, :roleId will be replaced with the selected user's id\n\t * @param method method to send to route\n\t */\n\tpublic setPattern<P extends Path>({\n\t\tmethod,\n\t\tpath,\n\t\tquery,\n\t}: SetOptions<P>): this;\n\t/**\n\t * Sets the path to route to when clicked\n\t *\n\t * @param path the path to route to\n\t */\n\tpublic setPattern<P extends Path>(path: P): this;\n\n\tpublic setPattern<P extends Path>(arg: P | SetOptions<P>) {\n\t\tconst {\n\t\t\tmethod = \"GET\",\n\t\t\tpath,\n\t\t\tquery,\n\t\t} = isSetOptions(arg) ? arg : { path: arg };\n\t\tsuper.setCustomId(\n\t\t\tencodePath({\n\t\t\t\tidPrefix: this.#embedRouter.getIdPrefix(),\n\t\t\t\tmethod,\n\t\t\t\tpath,\n\t\t\t\tquery,\n\t\t\t}),\n\t\t);\n\n\t\treturn this;\n\t}\n}\n","import {\n\tAPIUserSelectComponent,\n\tUserSelectMenuBuilder,\n\tUserSelectMenuComponentData,\n} from \"discord.js\";\nimport { EmbedRouter } from \"../EmbedRouter\";\nimport { Path } from \"path-to-regexp\";\nimport { encodePath } from \"../helpers/encodePath\";\nimport { isSetOptions, SetOptions } from \"../types/componentBuilders\";\n\nexport class RouteUserSelectMenuBuilder<L> extends UserSelectMenuBuilder {\n\t#embedRouter: EmbedRouter<L>;\n\n\t/**\n\t *\n\t * @param embedRouter the router you want to route with\n\t * @param data the data to construct a component out of\n\t */\n\tconstructor(\n\t\tembedRouter: EmbedRouter<L>,\n\t\tdata?:\n\t\t\tPartial<UserSelectMenuComponentData | APIUserSelectComponent> | undefined,\n\t) {\n\t\tsuper(data);\n\n\t\tthis.#embedRouter = embedRouter;\n\t}\n\n\t/**\n\t * Not supported for RouteUserSelectMenuBuilder (customId set from embedRouter)\n\t *\n\t * @remarks\n\t * @param\n\t */\n\toverride setCustomId(): this {\n\t\tthrow new Error(\n\t\t\t\"setCustomId is not supported on RouteUserSelectMenuBuilder\",\n\t\t);\n\t}\n\n\t/**\n\t * Sets the pattern to redirect to (Required)\n\t *\n\t * @param path the path to redirect to, :userId in path will be replaced with the selected user's id\n\t * @param query any query parameters you want to add, :userId will be replaced with the selected user's id\n\t * @param method method to send to route\n\t */\n\tpublic setPattern<P extends Path>({\n\t\tmethod,\n\t\tpath,\n\t\tquery,\n\t}: SetOptions<P>): this;\n\t/**\n\t * Sets the path to route to when clicked\n\t *\n\t * @param path the path to route to\n\t */\n\tpublic setPattern<P extends Path>(path: P): this;\n\n\tpublic setPattern<P extends Path>(arg: P | SetOptions<P>) {\n\t\tconst {\n\t\t\tmethod = \"GET\",\n\t\t\tpath,\n\t\t\tquery,\n\t\t} = isSetOptions(arg) ? arg : { path: arg };\n\t\tsuper.setCustomId(\n\t\t\tencodePath({\n\t\t\t\tidPrefix: this.#embedRouter.getIdPrefix(),\n\t\t\t\tmethod,\n\t\t\t\tpath,\n\t\t\t\tquery,\n\t\t\t}),\n\t\t);\n\n\t\treturn this;\n\t}\n}\n"],"mappings":"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","names":["import_path_to_regexp","path","import_path_to_regexp","path","path","path","path","import_discord","import_discord","path","path","import_discord","path","import_discord","path","import_discord","path"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/EmbedRouter.ts","../src/consts.ts","../src/helpers/pathToString.ts","../src/helpers/decodePath.ts","../src/componentBuilders/RouteButtonBuilder.ts","../src/helpers/encodePath.ts","../src/componentBuilders/RouteStringSelectMenuBuilder.ts","../src/componentBuilders/RouteStringSelectMenuOptionBuilder.ts","../src/componentBuilders/RouteChannelSelectMenuBuilder.ts","../src/componentBuilders/RouteRoleSelectMenuBuilder.ts","../src/componentBuilders/RouteUserSelectMenuBuilder.ts"],"sourcesContent":["export { EmbedRouter } from \"./EmbedRouter\";\n\nexport { RouteButtonBuilder } from \"./componentBuilders/RouteButtonBuilder\";\nexport { RouteStringSelectMenuBuilder } from \"./componentBuilders/RouteStringSelectMenuBuilder\";\nexport { RouteStringSelectMenuOptionBuilder } from \"./componentBuilders/RouteStringSelectMenuOptionBuilder\";\nexport { RouteChannelSelectMenuBuilder } from \"./componentBuilders/RouteChannelSelectMenuBuilder\";\nexport { RouteRoleSelectMenuBuilder } from \"./componentBuilders/RouteRoleSelectMenuBuilder\";\nexport { RouteUserSelectMenuBuilder } from \"./componentBuilders/RouteUserSelectMenuBuilder\";\n\nexport type * from \"./types/routes\";\n","import path from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport { match, MatchResult, Path } from \"path-to-regexp\";\nimport type {\n\tApplyHandler,\n\tCompiledRoute,\n\tMethod,\n\tRouteHandler,\n\tRouteResponse,\n} from \"./types/routes\";\nimport type { ExtractParams } from \"./types/ExtractParams\";\nimport {\n\tAnySelectMenuInteraction,\n\tButtonInteraction,\n\tInteraction,\n\tInteractionReplyOptions,\n\tMessageFlags,\n\tSnowflake,\n} from \"discord.js\";\nimport { BASE_URL, ID_PREFIX, PUA_RANGE, PUA_START } from \"./consts\";\nimport { pathToString } from \"./helpers/pathToString\";\nimport { decodePath } from \"./helpers/decodePath\";\n\nexport class EmbedRouter<L> {\n\t// identifier -> embedRouter\n\tstatic #usedIdentifiers = new Map<string, EmbedRouter<unknown>>();\n\n\t// Name used to generate prefixes\n\t#name = \"\";\n\t// Prefix for customIds of RouteButtonBuilders\n\t#idPrefix: string;\n\t#identifier: string = \"\";\n\tpublic getIdPrefix() {\n\t\treturn `${this.#idPrefix}${this.#identifier}`;\n\t}\n\n\t// All added routes\n\t#routes: Map<Method, CompiledRoute<Method, L>[]> = new Map();\n\t// message.id -> cleanup object\n\t#cleanups: Map<\n\t\tSnowflake,\n\t\t{\n\t\t\ttimeout?: NodeJS.Timeout | undefined;\n\t\t\tcleanupFn: NonNullable<RouteResponse[\"cleanup\"]>;\n\t\t\tapplyFn: ApplyHandler;\n\t\t}\n\t> = new Map();\n\n\t/**\n\t *\n\t * @param name the name to give the router. ensures buttons stay connected across restarts\n\t * @param idPrefix the prefix for RouteButtonBuilder customIds\n\t */\n\tconstructor({\n\t\tname = \"\",\n\t\tidPrefix = ID_PREFIX,\n\t}: {\n\t\tname?: string | undefined;\n\t\tidPrefix?: string | undefined;\n\t} = {}) {\n\t\tif (EmbedRouter.#usedIdentifiers.size >= PUA_RANGE) {\n\t\t\tthrow new Error(`You can not have more than ${PUA_RANGE} routers`);\n\t\t}\n\t\tif (idPrefix.includes(\"/\")) {\n\t\t\tthrow new Error(`Prefix can't contain \"/\": ${idPrefix}`);\n\t\t}\n\t\tthis.#idPrefix = idPrefix;\n\t\tthis.#name = name;\n\t\tthis.#updateIdentifier();\n\t}\n\n\t#updateIdentifier() {\n\t\t// Private Use Area: Unicode Characters not from any language\n\t\tconst hash = createHash(\"sha256\").update(this.#name).digest();\n\t\tlet raw = hash.readUint32BE(0);\n\t\tlet char: string;\n\t\tconst nameCollisions = [];\n\t\t// find next available identifier\n\t\twhile (true) {\n\t\t\tconst codepoint = PUA_START + (raw++ % PUA_RANGE);\n\t\t\tchar = String.fromCodePoint(codepoint);\n\n\t\t\tconst collisionRouter = EmbedRouter.#usedIdentifiers.get(char);\n\t\t\tif (collisionRouter === undefined) break; // no collisions\n\n\t\t\tif (this.#name.length > 0 && collisionRouter.#name.length === 0) {\n\t\t\t\t// evict old name; usedIdentifier is still taken\n\t\t\t\tcollisionRouter.#updateIdentifier();\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tnameCollisions.push(collisionRouter);\n\t\t}\n\t\tEmbedRouter.#usedIdentifiers.set(char, this as EmbedRouter<unknown>);\n\n\t\tif (nameCollisions.length > 0 && this.#name.length > 0) {\n\t\t\tprocess.emitWarning(\n\t\t\t\t`EmbedRouter identifier collision for name \"${this.#name}\" with ${nameCollisions.map((c) => `\"${c.#name}\"`).join(\", \")}`,\n\t\t\t\t\"EmbedRouterWarning\",\n\t\t\t);\n\t\t}\n\t\tthis.#identifier = char;\n\t}\n\n\t#addRoute<M extends Method, P extends Path = Path>(\n\t\tmethod: M,\n\t\troutePath: P | P[],\n\t\thandler: RouteHandler<M, L, ExtractParams<P>>,\n\t) {\n\t\tconst methodRoutes = this.#routes.get(method) ?? [];\n\t\tmethodRoutes.push({\n\t\t\tmethod,\n\t\t\tpath: Array.isArray(routePath) ? routePath : [routePath],\n\t\t\tmatchFunction: match(routePath),\n\t\t\thandler: handler as RouteHandler<M, L>,\n\t\t});\n\t\tthis.#routes.set(method, methodRoutes);\n\t}\n\n\t/**\n\t * Registers a path with the router\n\t *\n\t * @param routePath path to match with\n\t * @param handler function that generates the message when a path is matched\n\t */\n\tpublic get<P extends Path = Path>(\n\t\troutePath: P | P[],\n\t\thandler: RouteHandler<\"GET\", L, ExtractParams<P>>,\n\t) {\n\t\tthis.#addRoute(\"GET\", routePath, handler);\n\t}\n\n\t/**\n\t * Registers a path with the router\n\t *\n\t * @param routePath path to match with\n\t * @param handler function that generates the message when a path is matched\n\t */\n\tpublic post<P extends Path = Path>(\n\t\troutePath: P | P[],\n\t\thandler: RouteHandler<\"POST\", L, ExtractParams<P>>,\n\t) {\n\t\tthis.#addRoute(\"POST\", routePath, handler);\n\t}\n\n\t/**\n\t * Registers a path with the router\n\t *\n\t * @param routePath path to match with\n\t * @param handler function that generates the message when a path is matched\n\t */\n\tpublic put<P extends Path = Path>(\n\t\troutePath: P | P[],\n\t\thandler: RouteHandler<\"PUT\", L, ExtractParams<P>>,\n\t) {\n\t\tthis.#addRoute(\"PUT\", routePath, handler);\n\t}\n\n\t/**\n\t * Registers a path with the router\n\t *\n\t * @param routePath path to match with\n\t * @param handler function that generates the message when a path is matched\n\t */\n\tpublic patch<P extends Path = Path>(\n\t\troutePath: P | P[],\n\t\thandler: RouteHandler<\"PATCH\", L, ExtractParams<P>>,\n\t) {\n\t\tthis.#addRoute(\"PATCH\", routePath, handler);\n\t}\n\n\t/**\n\t * Registers a path with the router\n\t *\n\t * @param routePath path to match with\n\t * @param handler function that generates the message when a path is matched\n\t */\n\tpublic delete<P extends Path = Path>(\n\t\troutePath: P | P[],\n\t\thandler: RouteHandler<\"DELETE\", L, ExtractParams<P>>,\n\t) {\n\t\tthis.#addRoute(\"DELETE\", routePath, handler);\n\t}\n\n\t/**\n\t * Adds a subrouter to the router\n\t *\n\t * @param routePath path of the router\n\t * @param embedRouter router to add at the path\n\t */\n\tpublic use<P extends Path = Path>(\n\t\troutePath: P,\n\t\tembedRouter: EmbedRouter<Partial<L>>,\n\t) {\n\t\tconst pathString = pathToString(routePath);\n\t\tfor (const [method, routes] of embedRouter.#routes) {\n\t\t\tfor (const route of routes) {\n\t\t\t\tthis.#addRoute(\n\t\t\t\t\tmethod,\n\t\t\t\t\troute.path.map((p) => path.posix.join(pathString, pathToString(p))),\n\t\t\t\t\troute.handler,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Must be attached to \"interactionCreate\" event for RouteButtonBuilder to work\n\t *\n\t * @param interaction interactions from \"interactionCreate\" (filter for ButtonInteractions)\n\t */\n\tpublic async listener(\n\t\tinteraction: ButtonInteraction | AnySelectMenuInteraction,\n\t\tlocals?: L | undefined,\n\t) {\n\t\tif (interaction.isAutocomplete())\n\t\t\tthrow new Error(\"Autocomplete Interactions aren't supported\");\n\n\t\tthis.#runCleanup(interaction.message.id, false);\n\n\t\tconst res = decodePath({ idPrefix: this.getIdPrefix(), interaction });\n\t\tif (!res)\n\t\t\tthrow new Error(`Invalid component found: id ${interaction.customId}`);\n\n\t\tthis.dispatch(interaction, res.path, { method: res.method, locals });\n\t}\n\n\t/**\n\t * Replies to or editReplies to an interaction based on the route output\n\t *\n\t * @param interaction interaction to connect to\n\t * @param path path to route the interaction to\n\t * @param method method to send to route\n\t * @param flags discord flags to send with message (optional, only allowed on first reply)\n\t * @param locals additional info to pass in to page through state.local (optional)\n\t */\n\tpublic async dispatch<P extends Path = Path>(\n\t\tinteraction: Interaction,\n\t\tpath: P,\n\t\t{\n\t\t\tmethod = \"GET\",\n\t\t\tflags,\n\t\t\tlocals,\n\t\t}: {\n\t\t\tmethod?: Method;\n\t\t\tflags?: InteractionReplyOptions[\"flags\"] | undefined;\n\t\t\tlocals?: L | undefined;\n\t\t} = {},\n\t) {\n\t\tif (interaction.isAutocomplete())\n\t\t\tthrow new Error(\"Autocomplete Interactions aren't supported\");\n\n\t\t// don't check validity because url params are considered invalid\n\t\tconst routeResponse = await this.#resolve(path, {\n\t\t\tinteraction,\n\t\t\tmethod,\n\t\t\tlocals,\n\t\t});\n\t\tif (routeResponse === false)\n\t\t\tthrow new Error(`No route found for ${pathToString(path, false)}`);\n\n\t\tif (interaction.replied || interaction.deferred) {\n\t\t\tif (flags)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"You can only set flags for interactions that haven't been replied to\",\n\t\t\t\t);\n\t\t\tif (routeResponse) await interaction.editReply(routeResponse);\n\t\t} else if (!routeResponse) {\n\t\t\tif (\"deferUpdate\" in interaction) {\n\t\t\t\tawait interaction.deferUpdate();\n\t\t\t} else {\n\t\t\t\tawait interaction.deferReply();\n\t\t\t}\n\t\t} else if (\"update\" in interaction) {\n\t\t\tif (flags)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"You can only set flags for interactions that haven't been replied to\",\n\t\t\t\t);\n\t\t\tawait interaction.update(routeResponse);\n\t\t} else {\n\t\t\tawait interaction.reply({\n\t\t\t\t...(routeResponse as InteractionReplyOptions),\n\t\t\t\tflags,\n\t\t\t});\n\t\t}\n\n\t\t// Apply cleanup if needed\n\t\tif (!routeResponse?.cleanup) return;\n\n\t\tconst message = await interaction.fetchReply();\n\t\tconst channel = interaction.channel;\n\t\tconst applyFn: ApplyHandler | undefined = message.flags.has(\n\t\t\tMessageFlags.Ephemeral,\n\t\t)\n\t\t\t? interaction.editReply.bind(interaction)\n\t\t\t: channel\n\t\t\t\t? (options) => channel.messages.edit(message.id, options)\n\t\t\t\t: undefined;\n\t\tif (!applyFn)\n\t\t\treturn process.emitWarning(\n\t\t\t\t`Could not derive applyFunction for ${pathToString(path, false)}. Cleanup return results will not be applied to message.`,\n\t\t\t\t\"EmbedRouterWarning\",\n\t\t\t);\n\n\t\tthis.#addCleanup(\n\t\t\tmessage.id,\n\t\t\trouteResponse.cleanup.bind(routeResponse),\n\t\t\tapplyFn,\n\t\t\trouteResponse?.timeout,\n\t\t);\n\t}\n\n\t/**\n\t * Resolves a route to the associated message (DOES NOT UPDATE MESSAGE)\n\t *\n\t * @param interaction interaction to connect to\n\t * @param path path to route the interaction to\n\t * @param method method to send to route\n\t * @param locals additional info to pass in to page through state.local (optional)\n\t * @returns discord message associated with route OR false\n\t */\n\tasync #resolve<P extends Path>(\n\t\tpath: P,\n\t\t{\n\t\t\tinteraction,\n\t\t\tmethod = \"GET\",\n\t\t\tlocals,\n\t\t}: {\n\t\t\tinteraction: Interaction;\n\t\t\tmethod?: Method;\n\t\t\tlocals?: L | undefined;\n\t\t},\n\t): Promise<RouteResponse | undefined | false> {\n\t\t// don't check validity because url params are considered invalid\n\t\tconst url = new URL(pathToString(path, false), BASE_URL);\n\t\tfor (const route of this.#routes.get(method) ?? []) {\n\t\t\tconst result = route.matchFunction(url.pathname);\n\t\t\tif (result) {\n\t\t\t\treturn await route.handler(interaction, {\n\t\t\t\t\t...(result as MatchResult<ExtractParams<P>>),\n\t\t\t\t\tquery: url.searchParams,\n\t\t\t\t\tembedRouter: this,\n\t\t\t\t\tlocals,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t// Helpers for using and storing cleanup functions\n\t#addCleanup(\n\t\tmessageId: Snowflake,\n\t\tcleanupFn: NonNullable<RouteResponse[\"cleanup\"]>,\n\t\tapplyFn: ApplyHandler,\n\t\ttimeout: number,\n\t) {\n\t\tthis.#removeCleanup(messageId);\n\t\tthis.#cleanups.set(messageId, {\n\t\t\tcleanupFn,\n\t\t\tapplyFn,\n\t\t\ttimeout: isFinite(timeout)\n\t\t\t\t? setTimeout(() => this.#runCleanup(messageId, true), timeout)\n\t\t\t\t: undefined,\n\t\t});\n\t}\n\n\t#removeCleanup(messageId: Snowflake) {\n\t\tconst cleanup = this.#cleanups.get(messageId);\n\t\tif (!cleanup) return;\n\n\t\tclearTimeout(cleanup.timeout);\n\t\tthis.#cleanups.delete(messageId);\n\t}\n\n\tasync #runCleanup(messageId: Snowflake, applyResult: boolean) {\n\t\tconst cleanup = this.#cleanups.get(messageId);\n\t\tif (!cleanup) return;\n\n\t\tthis.#removeCleanup(messageId);\n\t\tconst result = await cleanup?.cleanupFn();\n\t\tif (applyResult && result) {\n\t\t\tawait cleanup.applyFn(result).catch(console.error);\n\t\t}\n\t}\n}\n","import { Method } from \"./types/routes\";\n\nexport const ID_PREFIX = \"der\";\nexport const METHOD_TO_ENCODING: Record<Method, string> = {\n\tGET: \"G\",\n\tPOST: \"P\",\n\tPUT: \"U\",\n\tPATCH: \"A\",\n\tDELETE: \"D\",\n};\nexport const ENCODING_TO_METHOD: Record<string, Method> = {\n\tG: \"GET\",\n\tP: \"POST\",\n\tU: \"PUT\",\n\tA: \"PATCH\",\n\tD: \"DELETE\",\n};\n// base url is never sent; only used for processing locally\nexport const BASE_URL = \"discord://embed.router\";\n\nexport const PUA_START = 0xe000;\nexport const PUA_END = 0xf8ff;\nexport const PUA_RANGE = PUA_END - PUA_START + 1;\n","import { parse, Path, stringify, TokenData } from \"path-to-regexp\";\n\nexport const pathToString = <P extends Path>(\n\tpath: P,\n\tcheckValidity = true,\n): string => {\n\tif (checkValidity) {\n\t\treturn stringify(path instanceof TokenData ? path : parse(path));\n\t}\n\treturn typeof path === \"string\" ? path : stringify(path);\n};\n","import { compile, Path } from \"path-to-regexp\";\nimport { AnySelectMenuInteraction, ButtonInteraction } from \"discord.js\";\nimport { BASE_URL, ENCODING_TO_METHOD } from \"../consts\";\nimport { Method } from \"../types/routes\";\n\nexport const decodePath = ({\n\tidPrefix,\n\tinteraction,\n}: {\n\tidPrefix: string;\n\tinteraction: ButtonInteraction | AnySelectMenuInteraction;\n}): { method: Method; path: Path } | false => {\n\tconst customId = interaction.customId;\n\tif (!customId.startsWith(idPrefix)) return false;\n\n\tconst res = parseMethodAndPath(customId.slice(idPrefix.length));\n\tif (!res) return false;\n\tconst { method, path } = res;\n\n\tif (interaction.isButton()) {\n\t\treturn {\n\t\t\tmethod,\n\t\t\tpath: urlToPathString(\n\t\t\t\tfillParams(path, {\n\t\t\t\t\tts: interaction.createdTimestamp.toString(),\n\t\t\t\t}),\n\t\t\t),\n\t\t};\n\t} else if (interaction.isAnySelectMenu()) {\n\t\tif (interaction.values.length === 0) return false;\n\n\t\tif (interaction.isStringSelectMenu()) {\n\t\t\t// also fill in variables for to's\n\t\t\tconst toRes = parseOptionalMethodAndPath(interaction.values[0]!);\n\t\t\tconst toURL = toRes\n\t\t\t\t? fillParams(toRes.path, {\n\t\t\t\t\t\tts: interaction.createdTimestamp.toString(),\n\t\t\t\t\t})\n\t\t\t\t: undefined;\n\t\t\tconst pathURL = fillParams(path, {\n\t\t\t\tts: interaction.createdTimestamp.toString(),\n\t\t\t\tto: toURL ? toURL.pathname.split(\"/\").slice(1) : \"\",\n\t\t\t});\n\t\t\t// merge query params\n\t\t\tfor (const [key, value] of toURL?.searchParams ?? []) {\n\t\t\t\tpathURL.searchParams.append(key, value);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tmethod,\n\t\t\t\tpath: urlToPathString(pathURL),\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tmethod,\n\t\t\tpath: urlToPathString(\n\t\t\t\tfillParams(path, {\n\t\t\t\t\tts: interaction.createdTimestamp.toString(),\n\t\t\t\t\t[interaction.isChannelSelectMenu()\n\t\t\t\t\t\t? \"channelId\"\n\t\t\t\t\t\t: interaction.isRoleSelectMenu()\n\t\t\t\t\t\t\t? \"roleId\"\n\t\t\t\t\t\t\t: \"userId\"]: interaction.values[0]!.split(\"/\").slice(1),\n\t\t\t\t}),\n\t\t\t),\n\t\t};\n\t}\n\n\treturn false;\n};\n\nconst parseMethodAndPath = (\n\tpathWithMethod: string,\n): { method: Method; path: string } | false => {\n\t// path always start with \"/\"\n\tconst firstSlash = pathWithMethod.indexOf(\"/\");\n\t// invalid customId\n\tif (firstSlash < 0) return false;\n\n\tconst method = ENCODING_TO_METHOD[pathWithMethod.slice(0, firstSlash)];\n\tif (method === undefined) return false;\n\treturn {\n\t\tmethod,\n\t\tpath: pathWithMethod.slice(firstSlash),\n\t};\n};\n\nconst parseOptionalMethodAndPath = (\n\tpathWithMethod: string,\n): { method: Method | \"\"; path: string } | false => {\n\t// path always start with \"/\"\n\tconst firstSlash = pathWithMethod.indexOf(\"/\");\n\t// invalid customId\n\tif (firstSlash < 0) return false;\n\n\tconst method = ENCODING_TO_METHOD[pathWithMethod.slice(0, firstSlash)];\n\treturn {\n\t\tmethod: method ?? \"\",\n\t\tpath: pathWithMethod.slice(firstSlash),\n\t};\n};\n\nconst fillParams = (\n\tpath: string,\n\tparams: Partial<Record<string, string | string[]>> = {},\n): URL => {\n\tconst url = new URL(path, BASE_URL);\n\tconst toPath = compile(url.pathname);\n\n\turl.pathname = toPath(params);\n\tfor (const [key, value] of url.searchParams) {\n\t\tif (value.startsWith(\":\") && value.slice(1) in params) {\n\t\t\tconst paramValue = params?.[value.slice(1)];\n\t\t\tif (paramValue) {\n\t\t\t\turl.searchParams.set(\n\t\t\t\t\tkey,\n\t\t\t\t\tArray.isArray(paramValue) ? paramValue.join(\"/\") : paramValue,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\turl.searchParams.delete(key);\n\t\t\t}\n\t\t}\n\t}\n\treturn url;\n};\n\nconst urlToPathString = (url: URL): string => {\n\treturn `${url.pathname}${url.search}`;\n};\n","import { APIButtonComponent, ButtonBuilder } from \"discord.js\";\nimport { Path } from \"path-to-regexp\";\nimport { EmbedRouter } from \"../EmbedRouter\";\nimport { encodePath } from \"../helpers/encodePath\";\nimport { RouteOptions } from \"../types/componentBuilders\";\n\nexport class RouteButtonBuilder<L> extends ButtonBuilder {\n\t#embedRouter: EmbedRouter<L>;\n\n\t/**\n\t *\n\t * @param embedRouter the router you want to route with\n\t * @param data the data to construct a component out of\n\t */\n\tconstructor(\n\t\tembedRouter: EmbedRouter<L>,\n\t\tdata?: Omit<Partial<APIButtonComponent>, \"custom_id\" | \"url\"> | undefined,\n\t) {\n\t\tsuper(data);\n\n\t\tthis.#embedRouter = embedRouter;\n\t}\n\n\t/**\n\t * Not supported for RouteButtonBuilder\n\t *\n\t * @remarks\n\t * @param\n\t */\n\toverride setURL(): this {\n\t\tthrow new Error(\"setURL is not supported on RouteButtonBuilder\");\n\t}\n\n\t/**\n\t * Not supported for RouteButtonBuilder (use setTo)\n\t *\n\t * @remarks\n\t * @param\n\t */\n\toverride setCustomId(): this {\n\t\tthrow new Error(\"setCustomId is not supported on RouteButtonBuilder\");\n\t}\n\n\t/**\n\t * Sets the path to route to when clicked\n\t *\n\t * @param path the path to route to, can include :ts\n\t * @param query any query parameters you want to add, can include :ts\n\t * @param method method to send to route\n\t */\n\tpublic setTo<P extends Path>(\n\t\tpath: P,\n\t\t{ method = \"GET\", query }: RouteOptions = {},\n\t): this {\n\t\tsuper.setCustomId(\n\t\t\tencodePath({\n\t\t\t\tidPrefix: this.#embedRouter.getIdPrefix(),\n\t\t\t\tmethod,\n\t\t\t\tpath,\n\t\t\t\tquery,\n\t\t\t}),\n\t\t);\n\n\t\treturn this;\n\t}\n}\n","import { Path } from \"path-to-regexp\";\nimport { BASE_URL, METHOD_TO_ENCODING } from \"../consts\";\nimport { pathToString } from \"./pathToString\";\nimport { Method } from \"../types/routes\";\n\nexport const encodePath = <AllowEmptyMethod extends boolean = false>({\n\tidPrefix,\n\tmethod,\n\tpath,\n\tquery,\n}: {\n\tidPrefix: string;\n\tmethod: AllowEmptyMethod extends false ? Method : Method | \"\";\n\tpath: Path;\n\tquery?: ConstructorParameters<typeof URLSearchParams>[0] | undefined;\n}) => {\n\tconst url = new URL(pathToString(path), BASE_URL);\n\tif (query) {\n\t\tfor (const [key, value] of new URLSearchParams(query)) {\n\t\t\turl.searchParams.set(key, value);\n\t\t}\n\t}\n\treturn `${idPrefix}${method === \"\" ? \"\" : METHOD_TO_ENCODING[method as Method]}${url.pathname}${url.search}`;\n};\n","import {\n\tAPIStringSelectComponent,\n\tnormalizeArray,\n\tRestOrArray,\n\tStringSelectMenuBuilder,\n\tStringSelectMenuComponentData,\n} from \"discord.js\";\nimport { Path } from \"path-to-regexp\";\nimport { RouteStringSelectMenuOptionBuilder } from \"./RouteStringSelectMenuOptionBuilder\";\nimport { EmbedRouter } from \"../EmbedRouter\";\nimport { encodePath } from \"../helpers/encodePath\";\nimport { RouteOptions } from \"../types/componentBuilders\";\n\nexport class RouteStringSelectMenuBuilder<L> extends StringSelectMenuBuilder {\n\t#embedRouter: EmbedRouter<L>;\n\n\t/**\n\t *\n\t * @param embedRouter the router you want to route with\n\t * @param path the path to redirect to, :to or *to in path will be replaced with the selected user's id\n\t * @param query any query parameters you want to add, :to will be replaced with the selected user's id\n\t * @param data the data to construct a component out of\n\t */\n\tconstructor(\n\t\tembedRouter: EmbedRouter<L>,\n\t\tdata?:\n\t\t\t| Partial<StringSelectMenuComponentData | APIStringSelectComponent>\n\t\t\t| undefined,\n\t) {\n\t\tsuper(data);\n\n\t\tthis.#embedRouter = embedRouter;\n\n\t\tsuper.setCustomId(\n\t\t\tencodePath({\n\t\t\t\tidPrefix: this.#embedRouter.getIdPrefix(),\n\t\t\t\tmethod: \"GET\",\n\t\t\t\tpath: \"/*to\",\n\t\t\t}),\n\t\t);\n\t}\n\n\t/**\n\t * Not supported for RouteStringSelectMenuBuilder (customId set from embedRouter)\n\t *\n\t * @remarks\n\t * @param\n\t */\n\toverride setCustomId(): this {\n\t\tthrow new Error(\n\t\t\t\"setCustomId is not supported on RouteStringSelectMenuBuilder\",\n\t\t);\n\t}\n\n\t/**\n\t * Not supported for RouteStringSelectMenuBuilder (use addTos)\n\t *\n\t * @remarks\n\t * @param\n\t */\n\toverride addOptions(): this {\n\t\tthrow new Error(\n\t\t\t\"addOptions is not supported on RouteStringSelectMenuBuilder\",\n\t\t);\n\t}\n\n\t/**\n\t * Not supported for RouteStringSelectMenuBuilder (use setTos)\n\t *\n\t * @remarks\n\t * @param\n\t */\n\toverride setOptions(): this {\n\t\tthrow new Error(\n\t\t\t\"setOptions is not supported on RouteStringSelectMenuBuilder\",\n\t\t);\n\t}\n\n\t/**\n\t * Adds route select menu options to builder\n\t *\n\t * @param tos the list of route select menu options\n\t */\n\tpublic addTos(\n\t\t...tos: RestOrArray<\n\t\t\t| RouteStringSelectMenuOptionBuilder\n\t\t\t| ConstructorParameters<typeof RouteStringSelectMenuOptionBuilder>[0]\n\t\t>\n\t): this {\n\t\tconst resolved = normalizeArray(tos);\n\t\tsuper.addOptions(\n\t\t\tresolved.map((o) =>\n\t\t\t\to instanceof RouteStringSelectMenuOptionBuilder\n\t\t\t\t\t? o\n\t\t\t\t\t: new RouteStringSelectMenuOptionBuilder(o),\n\t\t\t),\n\t\t);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets route select menu options to builder\n\t *\n\t * @param tos the list of route select menu options\n\t */\n\tpublic setTos(\n\t\t...tos: RestOrArray<\n\t\t\t| RouteStringSelectMenuOptionBuilder\n\t\t\t| ConstructorParameters<typeof RouteStringSelectMenuOptionBuilder>[0]\n\t\t>\n\t): this {\n\t\tconst resolved = normalizeArray(tos);\n\t\tsuper.setOptions(\n\t\t\tresolved.map((o) =>\n\t\t\t\to instanceof RouteStringSelectMenuOptionBuilder\n\t\t\t\t\t? o\n\t\t\t\t\t: new RouteStringSelectMenuOptionBuilder(o),\n\t\t\t),\n\t\t);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the pattern to redirect to (Required)\n\t *\n\t * @param path the path to redirect to, can include :ts :to *to\n\t * @param query any query parameters you want to add, can include :ts :to *to\n\t * @param method method to send to route\n\t */\n\tpublic setPattern<P extends Path>(\n\t\tpath: P,\n\t\t{ method = \"GET\", query }: RouteOptions = {},\n\t) {\n\t\tsuper.setCustomId(\n\t\t\tencodePath({\n\t\t\t\tidPrefix: this.#embedRouter.getIdPrefix(),\n\t\t\t\tmethod,\n\t\t\t\tpath,\n\t\t\t\tquery,\n\t\t\t}),\n\t\t);\n\n\t\treturn this;\n\t}\n}\n","import { StringSelectMenuOptionBuilder } from \"discord.js\";\nimport { Path } from \"path-to-regexp\";\nimport { encodePath } from \"../helpers/encodePath\";\nimport { RouteOptions } from \"../types/componentBuilders\";\n\nexport class RouteStringSelectMenuOptionBuilder extends StringSelectMenuOptionBuilder {\n\t/**\n\t * Not supported for RouteStringSelectMenuOptionBuilder (use setTo)\n\t *\n\t * @remarks\n\t * @param\n\t */\n\toverride setValue(): this {\n\t\tthrow new Error(\n\t\t\t\"setValue is not supported on RouteStringSelectMenuOptionBuilder\",\n\t\t);\n\t}\n\n\t/**\n\t * Sets the path to route to when selected\n\t *\n\t * @param path the path to route to, can include :ts\n\t * @param query any query parameters you want to add, can include :ts\n\t * @param method method to send to route\n\t */\n\tpublic setTo<P extends Path>(\n\t\tpath: P,\n\t\t{ method = \"\", query }: RouteOptions<true> = {},\n\t): this {\n\t\tsuper.setValue(\n\t\t\tencodePath<true>({\n\t\t\t\tidPrefix: \"\",\n\t\t\t\tmethod,\n\t\t\t\tpath,\n\t\t\t\tquery,\n\t\t\t}),\n\t\t);\n\n\t\treturn this;\n\t}\n}\n","import {\n\tAPIChannelSelectComponent,\n\tChannelSelectMenuBuilder,\n\tChannelSelectMenuComponentData,\n} from \"discord.js\";\nimport { EmbedRouter } from \"../EmbedRouter\";\nimport { Path } from \"path-to-regexp\";\nimport { encodePath } from \"../helpers/encodePath\";\nimport { RouteOptions } from \"../types/componentBuilders\";\n\nexport class RouteChannelSelectMenuBuilder<L> extends ChannelSelectMenuBuilder {\n\t#embedRouter: EmbedRouter<L>;\n\n\t/**\n\t *\n\t * @param embedRouter the router you want to route with\n\t * @param data the data to construct a component out of\n\t */\n\tconstructor(\n\t\tembedRouter: EmbedRouter<L>,\n\t\tdata?:\n\t\t\t| Partial<ChannelSelectMenuComponentData | APIChannelSelectComponent>\n\t\t\t| undefined,\n\t) {\n\t\tsuper(data);\n\n\t\tthis.#embedRouter = embedRouter;\n\t}\n\n\t/**\n\t * Not supported for RouteChannelSelectMenuBuilder (customId set from embedRouter)\n\t *\n\t * @remarks\n\t * @param\n\t */\n\toverride setCustomId(): this {\n\t\tthrow new Error(\n\t\t\t\"setCustomId is not supported on RouteChannelSelectMenuBuilder\",\n\t\t);\n\t}\n\n\t/**\n\t * Sets the pattern to redirect to (Required)\n\t *\n\t * @param path the path to redirect to, can include :ts :channelId\n\t * @param query any query parameters you want to add, can include :ts :channelId\n\t * @param method method to send to route\n\t */\n\tpublic setPattern<P extends Path>(\n\t\tpath: P,\n\t\t{ method = \"GET\", query }: RouteOptions = {},\n\t) {\n\t\tsuper.setCustomId(\n\t\t\tencodePath({\n\t\t\t\tidPrefix: this.#embedRouter.getIdPrefix(),\n\t\t\t\tmethod,\n\t\t\t\tpath,\n\t\t\t\tquery,\n\t\t\t}),\n\t\t);\n\n\t\treturn this;\n\t}\n}\n","import {\n\tAPIRoleSelectComponent,\n\tRoleSelectMenuBuilder,\n\tRoleSelectMenuComponentData,\n} from \"discord.js\";\nimport { EmbedRouter } from \"../EmbedRouter\";\nimport { Path } from \"path-to-regexp\";\nimport { encodePath } from \"../helpers/encodePath\";\nimport { RouteOptions } from \"../types/componentBuilders\";\n\nexport class RouteRoleSelectMenuBuilder<L> extends RoleSelectMenuBuilder {\n\t#embedRouter: EmbedRouter<L>;\n\n\t/**\n\t *\n\t * @param embedRouter the router you want to route with\n\t * @param data the data to construct a component out of\n\t */\n\tconstructor(\n\t\tembedRouter: EmbedRouter<L>,\n\t\tdata?:\n\t\t\tPartial<RoleSelectMenuComponentData | APIRoleSelectComponent> | undefined,\n\t) {\n\t\tsuper(data);\n\n\t\tthis.#embedRouter = embedRouter;\n\t}\n\n\t/**\n\t * Not supported for RouteRoleSelectMenuBuilder (customId set from embedRouter)\n\t *\n\t * @remarks\n\t * @param\n\t */\n\toverride setCustomId(): this {\n\t\tthrow new Error(\n\t\t\t\"setCustomId is not supported on RouteRoleSelectMenuBuilder\",\n\t\t);\n\t}\n\n\t/**\n\t * Sets the pattern to redirect to (Required)\n\t *\n\t * @param path the path to redirect to, can include :ts :roleId\n\t * @param query any query parameters you want to add, can include :ts :roleId\n\t * @param method method to send to route\n\t */\n\tpublic setPattern<P extends Path>(\n\t\tpath: P,\n\t\t{ method = \"GET\", query }: RouteOptions = {},\n\t) {\n\t\tsuper.setCustomId(\n\t\t\tencodePath({\n\t\t\t\tidPrefix: this.#embedRouter.getIdPrefix(),\n\t\t\t\tmethod,\n\t\t\t\tpath,\n\t\t\t\tquery,\n\t\t\t}),\n\t\t);\n\n\t\treturn this;\n\t}\n}\n","import {\n\tAPIUserSelectComponent,\n\tUserSelectMenuBuilder,\n\tUserSelectMenuComponentData,\n} from \"discord.js\";\nimport { EmbedRouter } from \"../EmbedRouter\";\nimport { Path } from \"path-to-regexp\";\nimport { encodePath } from \"../helpers/encodePath\";\nimport { RouteOptions } from \"../types/componentBuilders\";\n\nexport class RouteUserSelectMenuBuilder<L> extends UserSelectMenuBuilder {\n\t#embedRouter: EmbedRouter<L>;\n\n\t/**\n\t *\n\t * @param embedRouter the router you want to route with\n\t * @param data the data to construct a component out of\n\t */\n\tconstructor(\n\t\tembedRouter: EmbedRouter<L>,\n\t\tdata?:\n\t\t\tPartial<UserSelectMenuComponentData | APIUserSelectComponent> | undefined,\n\t) {\n\t\tsuper(data);\n\n\t\tthis.#embedRouter = embedRouter;\n\t}\n\n\t/**\n\t * Not supported for RouteUserSelectMenuBuilder (customId set from embedRouter)\n\t *\n\t * @remarks\n\t * @param\n\t */\n\toverride setCustomId(): this {\n\t\tthrow new Error(\n\t\t\t\"setCustomId is not supported on RouteUserSelectMenuBuilder\",\n\t\t);\n\t}\n\n\t/**\n\t * Sets the pattern to redirect to (Required)\n\t *\n\t * @param path the path to redirect to, can include :ts :userId\n\t * @param query any query parameters you want to add, can include :ts :userId\n\t * @param method method to send to route\n\t */\n\tpublic setPattern<P extends Path>(\n\t\tpath: P,\n\t\t{ method = \"GET\", query }: RouteOptions = {},\n\t) {\n\t\tsuper.setCustomId(\n\t\t\tencodePath({\n\t\t\t\tidPrefix: this.#embedRouter.getIdPrefix(),\n\t\t\t\tmethod,\n\t\t\t\tpath,\n\t\t\t\tquery,\n\t\t\t}),\n\t\t);\n\n\t\treturn this;\n\t}\n}\n"],"mappings":"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","names":["import_path_to_regexp","path","import_path_to_regexp","path","path","import_discord","path","path","import_discord","import_discord","path","path","import_discord","path","import_discord","path","import_discord","path"]}