discord-embed-router 0.0.2 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -674
- package/dist/index.d.mts +97 -0
- package/dist/index.d.ts +96 -2
- package/dist/index.js +194 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +181 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +17 -3
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { ParamData, Path, MatchFunction, MatchResult, TokenData } from 'path-to-regexp';
|
|
2
|
+
import { Interaction, InteractionEditReplyOptions, ButtonInteraction, InteractionReplyOptions, ButtonBuilder } from 'discord.js';
|
|
3
|
+
|
|
4
|
+
type State<P extends ParamData> = MatchResult<P> & {
|
|
5
|
+
searchParams: URLSearchParams;
|
|
6
|
+
};
|
|
7
|
+
type RouteResponse = InteractionEditReplyOptions;
|
|
8
|
+
type RouteHandler<P extends ParamData> = (interaction: Interaction, state: State<P>) => RouteResponse;
|
|
9
|
+
type CompiledRoute<P extends ParamData> = {
|
|
10
|
+
path: Path[];
|
|
11
|
+
matchFunction: MatchFunction<P>;
|
|
12
|
+
handler: RouteHandler<P>;
|
|
13
|
+
};
|
|
14
|
+
type ResolvedRoute<P extends ParamData> = {
|
|
15
|
+
state: State<P>;
|
|
16
|
+
handler: RouteHandler<P>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
type TakeIdentifier<T extends string, Name extends string = ""> = T extends `${infer Char}${infer Rest}` ? Char extends "/" | ":" | "*" | "{" | "}" ? [Name, T] : TakeIdentifier<Rest, `${Name}${Char}`> : [Name, T];
|
|
20
|
+
type TakeQuoted<T extends string, Name extends string = ""> = T extends `"${infer Rest}` ? [Name, Rest] : T extends `${infer Char}${infer Rest}` ? TakeQuoted<Rest, `${Name}${Char}`> : [Name, T];
|
|
21
|
+
type ParseName<T extends string> = T extends `"${infer Rest}` ? TakeQuoted<Rest> : TakeIdentifier<T>;
|
|
22
|
+
type ExtractParams<T extends string | TokenData, Depth extends string = ""> = T extends TokenData ? ParamData : T extends string ? T extends `${infer Char}${infer Rest}` ? Char extends ":" | "*" ? ParseName<Rest> extends [
|
|
23
|
+
infer Name extends string,
|
|
24
|
+
infer After extends string
|
|
25
|
+
] ? (Depth extends "" ? {
|
|
26
|
+
[K in Name]: string;
|
|
27
|
+
} : {
|
|
28
|
+
[K in Name]?: string;
|
|
29
|
+
}) & ExtractParams<After, Depth> : ExtractParams<Rest, Depth> : Char extends "{" ? ExtractParams<Rest, `${Depth}1`> : Char extends "}" ? ExtractParams<Rest, Depth extends `1${infer Rest2}` ? Rest2 : Depth> : ExtractParams<Rest, Depth> : object : never;
|
|
30
|
+
|
|
31
|
+
declare class EmbedRouter {
|
|
32
|
+
private static usedIdentifiers;
|
|
33
|
+
private static generateUniqueIdentifier;
|
|
34
|
+
private idPrefix;
|
|
35
|
+
getIdPrefix(): string;
|
|
36
|
+
private routes;
|
|
37
|
+
/**
|
|
38
|
+
*
|
|
39
|
+
* @param idPrefix the prefix for RouteButtonBuilder customIds
|
|
40
|
+
*/
|
|
41
|
+
constructor(idPrefix?: string);
|
|
42
|
+
/**
|
|
43
|
+
* Registers a path with the router
|
|
44
|
+
*
|
|
45
|
+
* @param routePath path to match with
|
|
46
|
+
* @param handler function that generates the message when a path is matched
|
|
47
|
+
*/
|
|
48
|
+
on<P extends Path = Path>(routePath: P | P[], handler: RouteHandler<ExtractParams<P>>): void;
|
|
49
|
+
/**
|
|
50
|
+
* Adds a subrouter to the router
|
|
51
|
+
*
|
|
52
|
+
* @param routePath path of the router
|
|
53
|
+
* @param embedRouter router to add at the path
|
|
54
|
+
*/
|
|
55
|
+
use<P extends Path = Path>(routePath: P, embedRouter: EmbedRouter): void;
|
|
56
|
+
/**
|
|
57
|
+
* Must be attached to "interactionCreate" event for RouteButtonBuilder to work
|
|
58
|
+
*
|
|
59
|
+
* @param interaction interactions from "interactionCreate" (filter for ButtonInteractions)
|
|
60
|
+
*/
|
|
61
|
+
listener(interaction: ButtonInteraction): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Connect or update an interaction message to a path
|
|
64
|
+
*
|
|
65
|
+
* @param interaction interaction to connect to
|
|
66
|
+
* @param path path to route the interaction to
|
|
67
|
+
* @param flags optional discord flags to send with message (only allowed on first reply)
|
|
68
|
+
*/
|
|
69
|
+
dispatch<P extends Path = Path>(interaction: Interaction, path: P, flags?: InteractionReplyOptions["flags"]): Promise<void>;
|
|
70
|
+
private resolve;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
declare class RouteButtonBuilder extends ButtonBuilder {
|
|
74
|
+
/**
|
|
75
|
+
* Not supported for RouteButtonBuilder
|
|
76
|
+
*
|
|
77
|
+
* @remarks
|
|
78
|
+
* @param
|
|
79
|
+
*/
|
|
80
|
+
setURL(): this;
|
|
81
|
+
/**
|
|
82
|
+
* Not supported for RouteButtonBuilder (setTo uses customId)
|
|
83
|
+
*
|
|
84
|
+
* @remarks
|
|
85
|
+
* @param
|
|
86
|
+
*/
|
|
87
|
+
setCustomId(): this;
|
|
88
|
+
/**
|
|
89
|
+
* Sets the path to route to when clicked
|
|
90
|
+
*
|
|
91
|
+
* @param path the path to route to
|
|
92
|
+
* @param idPrefix the prefix to add before the custom_id
|
|
93
|
+
*/
|
|
94
|
+
setTo<P extends Path>(embedRouter: EmbedRouter, path: P): void;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export { type CompiledRoute, EmbedRouter, type ResolvedRoute, RouteButtonBuilder, type RouteHandler, type RouteResponse, type State };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,97 @@
|
|
|
1
|
-
|
|
1
|
+
import { ParamData, Path, MatchFunction, MatchResult, TokenData } from 'path-to-regexp';
|
|
2
|
+
import { Interaction, InteractionEditReplyOptions, ButtonInteraction, InteractionReplyOptions, ButtonBuilder } from 'discord.js';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
type State<P extends ParamData> = MatchResult<P> & {
|
|
5
|
+
searchParams: URLSearchParams;
|
|
6
|
+
};
|
|
7
|
+
type RouteResponse = InteractionEditReplyOptions;
|
|
8
|
+
type RouteHandler<P extends ParamData> = (interaction: Interaction, state: State<P>) => RouteResponse;
|
|
9
|
+
type CompiledRoute<P extends ParamData> = {
|
|
10
|
+
path: Path[];
|
|
11
|
+
matchFunction: MatchFunction<P>;
|
|
12
|
+
handler: RouteHandler<P>;
|
|
13
|
+
};
|
|
14
|
+
type ResolvedRoute<P extends ParamData> = {
|
|
15
|
+
state: State<P>;
|
|
16
|
+
handler: RouteHandler<P>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
type TakeIdentifier<T extends string, Name extends string = ""> = T extends `${infer Char}${infer Rest}` ? Char extends "/" | ":" | "*" | "{" | "}" ? [Name, T] : TakeIdentifier<Rest, `${Name}${Char}`> : [Name, T];
|
|
20
|
+
type TakeQuoted<T extends string, Name extends string = ""> = T extends `"${infer Rest}` ? [Name, Rest] : T extends `${infer Char}${infer Rest}` ? TakeQuoted<Rest, `${Name}${Char}`> : [Name, T];
|
|
21
|
+
type ParseName<T extends string> = T extends `"${infer Rest}` ? TakeQuoted<Rest> : TakeIdentifier<T>;
|
|
22
|
+
type ExtractParams<T extends string | TokenData, Depth extends string = ""> = T extends TokenData ? ParamData : T extends string ? T extends `${infer Char}${infer Rest}` ? Char extends ":" | "*" ? ParseName<Rest> extends [
|
|
23
|
+
infer Name extends string,
|
|
24
|
+
infer After extends string
|
|
25
|
+
] ? (Depth extends "" ? {
|
|
26
|
+
[K in Name]: string;
|
|
27
|
+
} : {
|
|
28
|
+
[K in Name]?: string;
|
|
29
|
+
}) & ExtractParams<After, Depth> : ExtractParams<Rest, Depth> : Char extends "{" ? ExtractParams<Rest, `${Depth}1`> : Char extends "}" ? ExtractParams<Rest, Depth extends `1${infer Rest2}` ? Rest2 : Depth> : ExtractParams<Rest, Depth> : object : never;
|
|
30
|
+
|
|
31
|
+
declare class EmbedRouter {
|
|
32
|
+
private static usedIdentifiers;
|
|
33
|
+
private static generateUniqueIdentifier;
|
|
34
|
+
private idPrefix;
|
|
35
|
+
getIdPrefix(): string;
|
|
36
|
+
private routes;
|
|
37
|
+
/**
|
|
38
|
+
*
|
|
39
|
+
* @param idPrefix the prefix for RouteButtonBuilder customIds
|
|
40
|
+
*/
|
|
41
|
+
constructor(idPrefix?: string);
|
|
42
|
+
/**
|
|
43
|
+
* Registers a path with the router
|
|
44
|
+
*
|
|
45
|
+
* @param routePath path to match with
|
|
46
|
+
* @param handler function that generates the message when a path is matched
|
|
47
|
+
*/
|
|
48
|
+
on<P extends Path = Path>(routePath: P | P[], handler: RouteHandler<ExtractParams<P>>): void;
|
|
49
|
+
/**
|
|
50
|
+
* Adds a subrouter to the router
|
|
51
|
+
*
|
|
52
|
+
* @param routePath path of the router
|
|
53
|
+
* @param embedRouter router to add at the path
|
|
54
|
+
*/
|
|
55
|
+
use<P extends Path = Path>(routePath: P, embedRouter: EmbedRouter): void;
|
|
56
|
+
/**
|
|
57
|
+
* Must be attached to "interactionCreate" event for RouteButtonBuilder to work
|
|
58
|
+
*
|
|
59
|
+
* @param interaction interactions from "interactionCreate" (filter for ButtonInteractions)
|
|
60
|
+
*/
|
|
61
|
+
listener(interaction: ButtonInteraction): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Connect or update an interaction message to a path
|
|
64
|
+
*
|
|
65
|
+
* @param interaction interaction to connect to
|
|
66
|
+
* @param path path to route the interaction to
|
|
67
|
+
* @param flags optional discord flags to send with message (only allowed on first reply)
|
|
68
|
+
*/
|
|
69
|
+
dispatch<P extends Path = Path>(interaction: Interaction, path: P, flags?: InteractionReplyOptions["flags"]): Promise<void>;
|
|
70
|
+
private resolve;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
declare class RouteButtonBuilder extends ButtonBuilder {
|
|
74
|
+
/**
|
|
75
|
+
* Not supported for RouteButtonBuilder
|
|
76
|
+
*
|
|
77
|
+
* @remarks
|
|
78
|
+
* @param
|
|
79
|
+
*/
|
|
80
|
+
setURL(): this;
|
|
81
|
+
/**
|
|
82
|
+
* Not supported for RouteButtonBuilder (setTo uses customId)
|
|
83
|
+
*
|
|
84
|
+
* @remarks
|
|
85
|
+
* @param
|
|
86
|
+
*/
|
|
87
|
+
setCustomId(): this;
|
|
88
|
+
/**
|
|
89
|
+
* Sets the path to route to when clicked
|
|
90
|
+
*
|
|
91
|
+
* @param path the path to route to
|
|
92
|
+
* @param idPrefix the prefix to add before the custom_id
|
|
93
|
+
*/
|
|
94
|
+
setTo<P extends Path>(embedRouter: EmbedRouter, path: P): void;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export { type CompiledRoute, EmbedRouter, type ResolvedRoute, RouteButtonBuilder, type RouteHandler, type RouteResponse, type State };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,13 +17,203 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
21
31
|
var index_exports = {};
|
|
22
32
|
__export(index_exports, {
|
|
23
|
-
|
|
33
|
+
EmbedRouter: () => EmbedRouter,
|
|
34
|
+
RouteButtonBuilder: () => RouteButtonBuilder
|
|
24
35
|
});
|
|
25
36
|
module.exports = __toCommonJS(index_exports);
|
|
26
|
-
|
|
37
|
+
|
|
38
|
+
// src/EmbedRouter.ts
|
|
39
|
+
var import_node_path = __toESM(require("path"));
|
|
40
|
+
var import_path_to_regexp2 = require("path-to-regexp");
|
|
41
|
+
|
|
42
|
+
// src/consts.ts
|
|
43
|
+
var ID_PREFIX = "der";
|
|
44
|
+
var BASE_URL = "x://x";
|
|
45
|
+
|
|
46
|
+
// src/helpers/pathToString.ts
|
|
47
|
+
var import_path_to_regexp = require("path-to-regexp");
|
|
48
|
+
var pathToString = (path2, checkValidity = true) => {
|
|
49
|
+
if (checkValidity) {
|
|
50
|
+
return (0, import_path_to_regexp.stringify)(path2 instanceof import_path_to_regexp.TokenData ? path2 : (0, import_path_to_regexp.parse)(path2));
|
|
51
|
+
}
|
|
52
|
+
return typeof path2 === "string" ? path2 : (0, import_path_to_regexp.stringify)(path2);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// src/EmbedRouter.ts
|
|
56
|
+
var EmbedRouter = class _EmbedRouter {
|
|
57
|
+
static usedIdentifiers = /* @__PURE__ */ new Set();
|
|
58
|
+
static generateUniqueIdentifier() {
|
|
59
|
+
const PUA_START = 57344;
|
|
60
|
+
const PUA_END = 63743;
|
|
61
|
+
let char;
|
|
62
|
+
do {
|
|
63
|
+
const codepoint = PUA_START + Math.floor(Math.random() * (PUA_END - PUA_START + 1));
|
|
64
|
+
char = String.fromCodePoint(codepoint);
|
|
65
|
+
} while (_EmbedRouter.usedIdentifiers.has(char));
|
|
66
|
+
_EmbedRouter.usedIdentifiers.add(char);
|
|
67
|
+
return char;
|
|
68
|
+
}
|
|
69
|
+
// Prefix for customIds of RouteButtonBuilders
|
|
70
|
+
idPrefix;
|
|
71
|
+
getIdPrefix() {
|
|
72
|
+
return this.idPrefix;
|
|
73
|
+
}
|
|
74
|
+
// All added routes
|
|
75
|
+
routes = [];
|
|
76
|
+
/**
|
|
77
|
+
*
|
|
78
|
+
* @param idPrefix the prefix for RouteButtonBuilder customIds
|
|
79
|
+
*/
|
|
80
|
+
constructor(idPrefix = ID_PREFIX) {
|
|
81
|
+
if (idPrefix.includes("/")) {
|
|
82
|
+
throw new Error(`Prefix can't contain "/": ${idPrefix}`);
|
|
83
|
+
}
|
|
84
|
+
this.idPrefix = `${idPrefix}${_EmbedRouter.generateUniqueIdentifier()}`;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Registers a path with the router
|
|
88
|
+
*
|
|
89
|
+
* @param routePath path to match with
|
|
90
|
+
* @param handler function that generates the message when a path is matched
|
|
91
|
+
*/
|
|
92
|
+
on(routePath, handler) {
|
|
93
|
+
this.routes.push({
|
|
94
|
+
path: Array.isArray(routePath) ? routePath : [routePath],
|
|
95
|
+
matchFunction: (0, import_path_to_regexp2.match)(routePath),
|
|
96
|
+
handler
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Adds a subrouter to the router
|
|
101
|
+
*
|
|
102
|
+
* @param routePath path of the router
|
|
103
|
+
* @param embedRouter router to add at the path
|
|
104
|
+
*/
|
|
105
|
+
use(routePath, embedRouter) {
|
|
106
|
+
const pathString = pathToString(routePath);
|
|
107
|
+
for (const route of embedRouter.routes) {
|
|
108
|
+
this.on(
|
|
109
|
+
route.path.map((p) => import_node_path.default.posix.join(pathString, pathToString(p))),
|
|
110
|
+
route.handler
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Must be attached to "interactionCreate" event for RouteButtonBuilder to work
|
|
116
|
+
*
|
|
117
|
+
* @param interaction interactions from "interactionCreate" (filter for ButtonInteractions)
|
|
118
|
+
*/
|
|
119
|
+
async listener(interaction) {
|
|
120
|
+
if (!interaction.isButton()) return;
|
|
121
|
+
const customId = interaction.customId;
|
|
122
|
+
if (!customId.startsWith(this.idPrefix)) return;
|
|
123
|
+
const path2 = customId.slice(this.idPrefix.length);
|
|
124
|
+
this.dispatch(interaction, path2);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Connect or update an interaction message to a path
|
|
128
|
+
*
|
|
129
|
+
* @param interaction interaction to connect to
|
|
130
|
+
* @param path path to route the interaction to
|
|
131
|
+
* @param flags optional discord flags to send with message (only allowed on first reply)
|
|
132
|
+
*/
|
|
133
|
+
async dispatch(interaction, path2, flags) {
|
|
134
|
+
if (interaction.isAutocomplete())
|
|
135
|
+
throw new Error("Autocomplete Interactions aren't supported");
|
|
136
|
+
const resolvedRoute = this.resolve(pathToString(path2, false));
|
|
137
|
+
if (!resolvedRoute)
|
|
138
|
+
throw new Error(`No route found for ${pathToString(path2, false)}`);
|
|
139
|
+
const routeResponse = resolvedRoute.handler(
|
|
140
|
+
interaction,
|
|
141
|
+
resolvedRoute.state
|
|
142
|
+
);
|
|
143
|
+
if (interaction.replied || interaction.deferred) {
|
|
144
|
+
if (flags)
|
|
145
|
+
throw new Error(
|
|
146
|
+
"You can only set flags for interactions that haven't been replied to"
|
|
147
|
+
);
|
|
148
|
+
await interaction.editReply(routeResponse);
|
|
149
|
+
} else if ("update" in interaction) {
|
|
150
|
+
if (flags)
|
|
151
|
+
throw new Error(
|
|
152
|
+
"You can only set flags for interactions that haven't been replied to"
|
|
153
|
+
);
|
|
154
|
+
await interaction.update(routeResponse);
|
|
155
|
+
} else {
|
|
156
|
+
interaction.reply({
|
|
157
|
+
...routeResponse,
|
|
158
|
+
flags
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
resolve(routePath) {
|
|
163
|
+
const url = new URL(routePath, BASE_URL);
|
|
164
|
+
for (const route of this.routes) {
|
|
165
|
+
const result = route.matchFunction(url.pathname);
|
|
166
|
+
if (result) {
|
|
167
|
+
return {
|
|
168
|
+
state: {
|
|
169
|
+
...result,
|
|
170
|
+
searchParams: url.searchParams
|
|
171
|
+
},
|
|
172
|
+
handler: route.handler
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// src/RouteButtonBuilder.ts
|
|
181
|
+
var import_discord = require("discord.js");
|
|
182
|
+
var RouteButtonBuilder = class extends import_discord.ButtonBuilder {
|
|
183
|
+
/**
|
|
184
|
+
* Not supported for RouteButtonBuilder
|
|
185
|
+
*
|
|
186
|
+
* @remarks
|
|
187
|
+
* @param
|
|
188
|
+
*/
|
|
189
|
+
setURL() {
|
|
190
|
+
throw new Error("setURL is not supported on RouteButtonBuilder");
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Not supported for RouteButtonBuilder (setTo uses customId)
|
|
194
|
+
*
|
|
195
|
+
* @remarks
|
|
196
|
+
* @param
|
|
197
|
+
*/
|
|
198
|
+
setCustomId() {
|
|
199
|
+
throw new Error("setCustomId is not supported on RouteButtonBuilder");
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Sets the path to route to when clicked
|
|
203
|
+
*
|
|
204
|
+
* @param path the path to route to
|
|
205
|
+
* @param idPrefix the prefix to add before the custom_id
|
|
206
|
+
*/
|
|
207
|
+
setTo(embedRouter, path2) {
|
|
208
|
+
const idPrefix = embedRouter.getIdPrefix();
|
|
209
|
+
const url = new URL(pathToString(path2, false), BASE_URL);
|
|
210
|
+
const customId = `${idPrefix}${url.pathname}${url.search}`;
|
|
211
|
+
super.setCustomId(customId);
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
215
|
+
0 && (module.exports = {
|
|
216
|
+
EmbedRouter,
|
|
217
|
+
RouteButtonBuilder
|
|
218
|
+
});
|
|
27
219
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/EmbedRouter.ts","../src/consts.ts","../src/helpers/pathToString.ts","../src/RouteButtonBuilder.ts"],"sourcesContent":["export { EmbedRouter } from \"./EmbedRouter\";\nexport { RouteButtonBuilder } from \"./RouteButtonBuilder\";\n\nexport type * from \"./types/routes\";\n","import path from \"node:path\";\nimport { match, ParamData, Path } from \"path-to-regexp\";\nimport {\n\tCompiledRoute,\n\tResolvedRoute,\n\tRouteHandler,\n\tState,\n} from \"./types/routes\";\nimport { ExtractParams } from \"./types/ExtractParams\";\nimport {\n\tButtonInteraction,\n\tInteraction,\n\tInteractionReplyOptions,\n} from \"discord.js\";\nimport { BASE_URL, ID_PREFIX } from \"./consts\";\nimport { pathToString } from \"./helpers/pathToString\";\n\nexport class EmbedRouter {\n\tprivate static usedIdentifiers = new Set<string>();\n\tprivate static generateUniqueIdentifier(): string {\n\t\tconst PUA_START = 0xe000;\n\t\tconst PUA_END = 0xf8ff;\n\t\tlet char: string;\n\t\tdo {\n\t\t\tconst codepoint =\n\t\t\t\tPUA_START + Math.floor(Math.random() * (PUA_END - PUA_START + 1));\n\t\t\tchar = String.fromCodePoint(codepoint);\n\t\t} while (EmbedRouter.usedIdentifiers.has(char));\n\t\tEmbedRouter.usedIdentifiers.add(char);\n\t\treturn char;\n\t}\n\n\t// Prefix for customIds of RouteButtonBuilders\n\tprivate idPrefix;\n\tgetIdPrefix() {\n\t\treturn this.idPrefix;\n\t}\n\n\t// All added routes\n\tprivate routes: CompiledRoute<ParamData>[] = [];\n\n\t/**\n\t *\n\t * @param idPrefix the prefix for RouteButtonBuilder customIds\n\t */\n\tconstructor(idPrefix = ID_PREFIX) {\n\t\tif (idPrefix.includes(\"/\")) {\n\t\t\tthrow new Error(`Prefix can't contain \"/\": ${idPrefix}`);\n\t\t}\n\t\tthis.idPrefix = `${idPrefix}${EmbedRouter.generateUniqueIdentifier()}`;\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\ton<P extends Path = Path>(\n\t\troutePath: P | P[],\n\t\thandler: RouteHandler<ExtractParams<P>>,\n\t) {\n\t\tthis.routes.push({\n\t\t\tpath: Array.isArray(routePath) ? routePath : [routePath],\n\t\t\tmatchFunction: match(routePath),\n\t\t\thandler: handler as RouteHandler<ParamData>,\n\t\t});\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\tuse<P extends Path = Path>(routePath: P, embedRouter: EmbedRouter) {\n\t\tconst pathString = pathToString(routePath);\n\t\tfor (const route of embedRouter.routes) {\n\t\t\tthis.on(\n\t\t\t\troute.path.map((p) => path.posix.join(pathString, pathToString(p))),\n\t\t\t\troute.handler,\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\tasync listener(interaction: ButtonInteraction) {\n\t\tif (!interaction.isButton()) return;\n\n\t\tconst customId = interaction.customId;\n\t\tif (!customId.startsWith(this.idPrefix)) return;\n\n\t\tconst path = customId.slice(this.idPrefix.length);\n\t\tthis.dispatch(interaction, path);\n\t}\n\n\t/**\n\t * Connect or update an interaction message to a path\n\t *\n\t * @param interaction interaction to connect to\n\t * @param path path to route the interaction to\n\t * @param flags optional discord flags to send with message (only allowed on first reply)\n\t */\n\tasync dispatch<P extends Path = Path>(\n\t\tinteraction: Interaction,\n\t\tpath: P,\n\t\tflags?: InteractionReplyOptions[\"flags\"],\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 resolvedRoute = this.resolve(pathToString(path, false));\n\t\tif (!resolvedRoute)\n\t\t\tthrow new Error(`No route found for ${pathToString(path, false)}`);\n\n\t\tconst routeResponse = resolvedRoute.handler(\n\t\t\tinteraction,\n\t\t\tresolvedRoute.state,\n\t\t);\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\tawait interaction.editReply(routeResponse);\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\tprivate resolve<P extends string>(\n\t\troutePath: P,\n\t): ResolvedRoute<ExtractParams<P>> | null {\n\t\tconst url = new URL(routePath, BASE_URL);\n\t\tfor (const route of this.routes) {\n\t\t\tconst result = route.matchFunction(url.pathname);\n\t\t\tif (result) {\n\t\t\t\treturn {\n\t\t\t\t\tstate: {\n\t\t\t\t\t\t...(result as State<ExtractParams<P>>),\n\t\t\t\t\t\tsearchParams: url.searchParams,\n\t\t\t\t\t},\n\t\t\t\t\thandler: route.handler,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n}\n","export const ID_PREFIX = \"der\";\nexport const BASE_URL = \"x://x\";\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 { ButtonBuilder } from \"discord.js\";\nimport { Path } from \"path-to-regexp\";\nimport { BASE_URL } from \"./consts\";\nimport { pathToString } from \"./helpers/pathToString\";\nimport { EmbedRouter } from \"./EmbedRouter\";\n\nexport class RouteButtonBuilder extends ButtonBuilder {\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 (setTo uses customId)\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 idPrefix the prefix to add before the custom_id\n\t */\n\tsetTo<P extends Path>(embedRouter: EmbedRouter, path: P) {\n\t\tconst idPrefix = embedRouter.getIdPrefix();\n\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\tconst customId = `${idPrefix}${url.pathname}${url.search}`;\n\n\t\tsuper.setCustomId(customId);\n\t}\n}\n"],"mappings":"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","names":["import_path_to_regexp","path","path","path"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
// src/EmbedRouter.ts
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { match } from "path-to-regexp";
|
|
4
|
+
|
|
5
|
+
// src/consts.ts
|
|
6
|
+
var ID_PREFIX = "der";
|
|
7
|
+
var BASE_URL = "x://x";
|
|
8
|
+
|
|
9
|
+
// src/helpers/pathToString.ts
|
|
10
|
+
import { parse, stringify, TokenData } from "path-to-regexp";
|
|
11
|
+
var pathToString = (path2, checkValidity = true) => {
|
|
12
|
+
if (checkValidity) {
|
|
13
|
+
return stringify(path2 instanceof TokenData ? path2 : parse(path2));
|
|
14
|
+
}
|
|
15
|
+
return typeof path2 === "string" ? path2 : stringify(path2);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// src/EmbedRouter.ts
|
|
19
|
+
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
|
+
}
|
|
32
|
+
// Prefix for customIds of RouteButtonBuilders
|
|
33
|
+
idPrefix;
|
|
34
|
+
getIdPrefix() {
|
|
35
|
+
return this.idPrefix;
|
|
36
|
+
}
|
|
37
|
+
// All added routes
|
|
38
|
+
routes = [];
|
|
39
|
+
/**
|
|
40
|
+
*
|
|
41
|
+
* @param idPrefix the prefix for RouteButtonBuilder customIds
|
|
42
|
+
*/
|
|
43
|
+
constructor(idPrefix = ID_PREFIX) {
|
|
44
|
+
if (idPrefix.includes("/")) {
|
|
45
|
+
throw new Error(`Prefix can't contain "/": ${idPrefix}`);
|
|
46
|
+
}
|
|
47
|
+
this.idPrefix = `${idPrefix}${_EmbedRouter.generateUniqueIdentifier()}`;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Registers a path with the router
|
|
51
|
+
*
|
|
52
|
+
* @param routePath path to match with
|
|
53
|
+
* @param handler function that generates the message when a path is matched
|
|
54
|
+
*/
|
|
55
|
+
on(routePath, handler) {
|
|
56
|
+
this.routes.push({
|
|
57
|
+
path: Array.isArray(routePath) ? routePath : [routePath],
|
|
58
|
+
matchFunction: match(routePath),
|
|
59
|
+
handler
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Adds a subrouter to the router
|
|
64
|
+
*
|
|
65
|
+
* @param routePath path of the router
|
|
66
|
+
* @param embedRouter router to add at the path
|
|
67
|
+
*/
|
|
68
|
+
use(routePath, embedRouter) {
|
|
69
|
+
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
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Must be attached to "interactionCreate" event for RouteButtonBuilder to work
|
|
79
|
+
*
|
|
80
|
+
* @param interaction interactions from "interactionCreate" (filter for ButtonInteractions)
|
|
81
|
+
*/
|
|
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);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Connect or update an interaction message to a path
|
|
91
|
+
*
|
|
92
|
+
* @param interaction interaction to connect to
|
|
93
|
+
* @param path path to route the interaction to
|
|
94
|
+
* @param flags optional discord flags to send with message (only allowed on first reply)
|
|
95
|
+
*/
|
|
96
|
+
async dispatch(interaction, path2, flags) {
|
|
97
|
+
if (interaction.isAutocomplete())
|
|
98
|
+
throw new Error("Autocomplete Interactions aren't supported");
|
|
99
|
+
const resolvedRoute = this.resolve(pathToString(path2, false));
|
|
100
|
+
if (!resolvedRoute)
|
|
101
|
+
throw new Error(`No route found for ${pathToString(path2, false)}`);
|
|
102
|
+
const routeResponse = resolvedRoute.handler(
|
|
103
|
+
interaction,
|
|
104
|
+
resolvedRoute.state
|
|
105
|
+
);
|
|
106
|
+
if (interaction.replied || interaction.deferred) {
|
|
107
|
+
if (flags)
|
|
108
|
+
throw new Error(
|
|
109
|
+
"You can only set flags for interactions that haven't been replied to"
|
|
110
|
+
);
|
|
111
|
+
await interaction.editReply(routeResponse);
|
|
112
|
+
} else if ("update" in interaction) {
|
|
113
|
+
if (flags)
|
|
114
|
+
throw new Error(
|
|
115
|
+
"You can only set flags for interactions that haven't been replied to"
|
|
116
|
+
);
|
|
117
|
+
await interaction.update(routeResponse);
|
|
118
|
+
} else {
|
|
119
|
+
interaction.reply({
|
|
120
|
+
...routeResponse,
|
|
121
|
+
flags
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
resolve(routePath) {
|
|
126
|
+
const url = new URL(routePath, BASE_URL);
|
|
127
|
+
for (const route of this.routes) {
|
|
128
|
+
const result = route.matchFunction(url.pathname);
|
|
129
|
+
if (result) {
|
|
130
|
+
return {
|
|
131
|
+
state: {
|
|
132
|
+
...result,
|
|
133
|
+
searchParams: url.searchParams
|
|
134
|
+
},
|
|
135
|
+
handler: route.handler
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// src/RouteButtonBuilder.ts
|
|
144
|
+
import { ButtonBuilder } from "discord.js";
|
|
145
|
+
var RouteButtonBuilder = class extends ButtonBuilder {
|
|
146
|
+
/**
|
|
147
|
+
* Not supported for RouteButtonBuilder
|
|
148
|
+
*
|
|
149
|
+
* @remarks
|
|
150
|
+
* @param
|
|
151
|
+
*/
|
|
152
|
+
setURL() {
|
|
153
|
+
throw new Error("setURL is not supported on RouteButtonBuilder");
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Not supported for RouteButtonBuilder (setTo uses customId)
|
|
157
|
+
*
|
|
158
|
+
* @remarks
|
|
159
|
+
* @param
|
|
160
|
+
*/
|
|
161
|
+
setCustomId() {
|
|
162
|
+
throw new Error("setCustomId is not supported on RouteButtonBuilder");
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Sets the path to route to when clicked
|
|
166
|
+
*
|
|
167
|
+
* @param path the path to route to
|
|
168
|
+
* @param idPrefix the prefix to add before the custom_id
|
|
169
|
+
*/
|
|
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);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
export {
|
|
178
|
+
EmbedRouter,
|
|
179
|
+
RouteButtonBuilder
|
|
180
|
+
};
|
|
181
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/EmbedRouter.ts","../src/consts.ts","../src/helpers/pathToString.ts","../src/RouteButtonBuilder.ts"],"sourcesContent":["import path from \"node:path\";\nimport { match, ParamData, Path } from \"path-to-regexp\";\nimport {\n\tCompiledRoute,\n\tResolvedRoute,\n\tRouteHandler,\n\tState,\n} from \"./types/routes\";\nimport { ExtractParams } from \"./types/ExtractParams\";\nimport {\n\tButtonInteraction,\n\tInteraction,\n\tInteractionReplyOptions,\n} from \"discord.js\";\nimport { BASE_URL, ID_PREFIX } from \"./consts\";\nimport { pathToString } from \"./helpers/pathToString\";\n\nexport class EmbedRouter {\n\tprivate static usedIdentifiers = new Set<string>();\n\tprivate static generateUniqueIdentifier(): string {\n\t\tconst PUA_START = 0xe000;\n\t\tconst PUA_END = 0xf8ff;\n\t\tlet char: string;\n\t\tdo {\n\t\t\tconst codepoint =\n\t\t\t\tPUA_START + Math.floor(Math.random() * (PUA_END - PUA_START + 1));\n\t\t\tchar = String.fromCodePoint(codepoint);\n\t\t} while (EmbedRouter.usedIdentifiers.has(char));\n\t\tEmbedRouter.usedIdentifiers.add(char);\n\t\treturn char;\n\t}\n\n\t// Prefix for customIds of RouteButtonBuilders\n\tprivate idPrefix;\n\tgetIdPrefix() {\n\t\treturn this.idPrefix;\n\t}\n\n\t// All added routes\n\tprivate routes: CompiledRoute<ParamData>[] = [];\n\n\t/**\n\t *\n\t * @param idPrefix the prefix for RouteButtonBuilder customIds\n\t */\n\tconstructor(idPrefix = ID_PREFIX) {\n\t\tif (idPrefix.includes(\"/\")) {\n\t\t\tthrow new Error(`Prefix can't contain \"/\": ${idPrefix}`);\n\t\t}\n\t\tthis.idPrefix = `${idPrefix}${EmbedRouter.generateUniqueIdentifier()}`;\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\ton<P extends Path = Path>(\n\t\troutePath: P | P[],\n\t\thandler: RouteHandler<ExtractParams<P>>,\n\t) {\n\t\tthis.routes.push({\n\t\t\tpath: Array.isArray(routePath) ? routePath : [routePath],\n\t\t\tmatchFunction: match(routePath),\n\t\t\thandler: handler as RouteHandler<ParamData>,\n\t\t});\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\tuse<P extends Path = Path>(routePath: P, embedRouter: EmbedRouter) {\n\t\tconst pathString = pathToString(routePath);\n\t\tfor (const route of embedRouter.routes) {\n\t\t\tthis.on(\n\t\t\t\troute.path.map((p) => path.posix.join(pathString, pathToString(p))),\n\t\t\t\troute.handler,\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\tasync listener(interaction: ButtonInteraction) {\n\t\tif (!interaction.isButton()) return;\n\n\t\tconst customId = interaction.customId;\n\t\tif (!customId.startsWith(this.idPrefix)) return;\n\n\t\tconst path = customId.slice(this.idPrefix.length);\n\t\tthis.dispatch(interaction, path);\n\t}\n\n\t/**\n\t * Connect or update an interaction message to a path\n\t *\n\t * @param interaction interaction to connect to\n\t * @param path path to route the interaction to\n\t * @param flags optional discord flags to send with message (only allowed on first reply)\n\t */\n\tasync dispatch<P extends Path = Path>(\n\t\tinteraction: Interaction,\n\t\tpath: P,\n\t\tflags?: InteractionReplyOptions[\"flags\"],\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 resolvedRoute = this.resolve(pathToString(path, false));\n\t\tif (!resolvedRoute)\n\t\t\tthrow new Error(`No route found for ${pathToString(path, false)}`);\n\n\t\tconst routeResponse = resolvedRoute.handler(\n\t\t\tinteraction,\n\t\t\tresolvedRoute.state,\n\t\t);\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\tawait interaction.editReply(routeResponse);\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\tprivate resolve<P extends string>(\n\t\troutePath: P,\n\t): ResolvedRoute<ExtractParams<P>> | null {\n\t\tconst url = new URL(routePath, BASE_URL);\n\t\tfor (const route of this.routes) {\n\t\t\tconst result = route.matchFunction(url.pathname);\n\t\t\tif (result) {\n\t\t\t\treturn {\n\t\t\t\t\tstate: {\n\t\t\t\t\t\t...(result as State<ExtractParams<P>>),\n\t\t\t\t\t\tsearchParams: url.searchParams,\n\t\t\t\t\t},\n\t\t\t\t\thandler: route.handler,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n}\n","export const ID_PREFIX = \"der\";\nexport const BASE_URL = \"x://x\";\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 { ButtonBuilder } from \"discord.js\";\nimport { Path } from \"path-to-regexp\";\nimport { BASE_URL } from \"./consts\";\nimport { pathToString } from \"./helpers/pathToString\";\nimport { EmbedRouter } from \"./EmbedRouter\";\n\nexport class RouteButtonBuilder extends ButtonBuilder {\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 (setTo uses customId)\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 idPrefix the prefix to add before the custom_id\n\t */\n\tsetTo<P extends Path>(embedRouter: EmbedRouter, path: P) {\n\t\tconst idPrefix = embedRouter.getIdPrefix();\n\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\tconst customId = `${idPrefix}${url.pathname}${url.search}`;\n\n\t\tsuper.setCustomId(customId);\n\t}\n}\n"],"mappings":"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","names":["path","path","path"]}
|
package/package.json
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "discord-embed-router",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "A vite inspired router for discord.js embeds and interactions",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
7
7
|
],
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
8
10
|
"exports": {
|
|
9
11
|
".": {
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
+
"import": {
|
|
13
|
+
"types": "./dist/index.d.mts",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"require": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"default": "./dist/index.js"
|
|
19
|
+
}
|
|
12
20
|
}
|
|
13
21
|
},
|
|
14
22
|
"keywords": [
|
|
@@ -43,5 +51,11 @@
|
|
|
43
51
|
"tsup": "^8.5.1",
|
|
44
52
|
"typescript": "^6.0.3",
|
|
45
53
|
"typescript-eslint": "^8.62.1"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"discord.js": "^14.26.4"
|
|
57
|
+
},
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"path-to-regexp": "^8.4.2"
|
|
46
60
|
}
|
|
47
61
|
}
|