create-discord-https 1.0.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/README.md +15 -0
- package/index.js +389 -0
- package/package.json +35 -0
- package/templates/cloudflare/README.md +32 -0
- package/templates/cloudflare/_gitignore +3 -0
- package/templates/cloudflare/package.json +26 -0
- package/templates/cloudflare/src/DevLayer.js +139 -0
- package/templates/cloudflare/src/commands/fun/joke.js +118 -0
- package/templates/cloudflare/src/commands/reply/ping.js +12 -0
- package/templates/cloudflare/src/commands/utility/help.js +73 -0
- package/templates/cloudflare/src/commands/utility/info.js +60 -0
- package/templates/cloudflare/src/commands/utility/profile.js +36 -0
- package/templates/cloudflare/src/spawner.js +17 -0
- package/templates/cloudflare/wrangler.jsonc +16 -0
- package/templates/cloudflare-ts/README.md +33 -0
- package/templates/cloudflare-ts/_gitignore +3 -0
- package/templates/cloudflare-ts/package.json +27 -0
- package/templates/cloudflare-ts/src/DevLayer.ts +140 -0
- package/templates/cloudflare-ts/src/commands/fun/joke.ts +125 -0
- package/templates/cloudflare-ts/src/commands/index.ts +14 -0
- package/templates/cloudflare-ts/src/commands/reply/ping.ts +12 -0
- package/templates/cloudflare-ts/src/commands/utility/help.ts +73 -0
- package/templates/cloudflare-ts/src/commands/utility/index.ts +14 -0
- package/templates/cloudflare-ts/src/commands/utility/info.ts +56 -0
- package/templates/cloudflare-ts/src/commands/utility/profile.ts +35 -0
- package/templates/cloudflare-ts/src/index.ts +60 -0
- package/templates/cloudflare-ts/src/spawner.js +17 -0
- package/templates/cloudflare-ts/tsconfig.json +18 -0
- package/templates/cloudflare-ts/wrangler.jsonc +19 -0
- package/templates/node/README.md +13 -0
- package/templates/node/_gitignore +3 -0
- package/templates/node/package.json +22 -0
- package/templates/node/src/DevLayer.js +135 -0
- package/templates/node/src/commands/fun/joke.js +118 -0
- package/templates/node/src/commands/reply/ping.js +12 -0
- package/templates/node/src/commands/utility/help.js +73 -0
- package/templates/node/src/commands/utility/info.js +60 -0
- package/templates/node/src/commands/utility/profile.js +36 -0
- package/templates/node-ts/README.md +10 -0
- package/templates/node-ts/_gitignore +3 -0
- package/templates/node-ts/package.json +24 -0
- package/templates/node-ts/src/DevLayer.ts +135 -0
- package/templates/node-ts/src/commands/fun/joke.ts +125 -0
- package/templates/node-ts/src/commands/index.ts +14 -0
- package/templates/node-ts/src/commands/reply/ping.ts +12 -0
- package/templates/node-ts/src/commands/utility/help.ts +73 -0
- package/templates/node-ts/src/commands/utility/index.ts +14 -0
- package/templates/node-ts/src/commands/utility/info.ts +56 -0
- package/templates/node-ts/src/commands/utility/profile.ts +35 -0
- package/templates/node-ts/src/index.ts +50 -0
- package/templates/vercel/.vercelignore +4 -0
- package/templates/vercel/README.md +30 -0
- package/templates/vercel/_gitignore +4 -0
- package/templates/vercel/api/interactions.js +5 -0
- package/templates/vercel/index.html +235 -0
- package/templates/vercel/package.json +23 -0
- package/templates/vercel/src/DevLayer.js +135 -0
- package/templates/vercel/src/commands/fun/joke.js +118 -0
- package/templates/vercel/src/commands/reply/ping.js +12 -0
- package/templates/vercel/src/commands/utility/help.js +73 -0
- package/templates/vercel/src/commands/utility/info.js +60 -0
- package/templates/vercel/src/commands/utility/profile.js +36 -0
- package/templates/vercel/src/spawner.js +18 -0
- package/templates/vercel-ts/.vercelignore +4 -0
- package/templates/vercel-ts/README.md +32 -0
- package/templates/vercel-ts/_gitignore +4 -0
- package/templates/vercel-ts/api/interactions.js +5 -0
- package/templates/vercel-ts/index.html +235 -0
- package/templates/vercel-ts/package.json +25 -0
- package/templates/vercel-ts/src/DevLayer.ts +135 -0
- package/templates/vercel-ts/src/commands/fun/joke.ts +125 -0
- package/templates/vercel-ts/src/commands/index.ts +14 -0
- package/templates/vercel-ts/src/commands/reply/ping.ts +12 -0
- package/templates/vercel-ts/src/commands/utility/help.ts +73 -0
- package/templates/vercel-ts/src/commands/utility/index.ts +14 -0
- package/templates/vercel-ts/src/commands/utility/info.ts +56 -0
- package/templates/vercel-ts/src/commands/utility/profile.ts +35 -0
- package/templates/vercel-ts/src/index.ts +48 -0
- package/templates/vercel-ts/src/spawner.js +18 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import Client from "discord.https";
|
|
2
|
+
import NodeHttpAdapter from "@discordhttps/nodejs-adapter";
|
|
3
|
+
|
|
4
|
+
import commands from "./commands/index.js";
|
|
5
|
+
|
|
6
|
+
const adapter = new NodeHttpAdapter();
|
|
7
|
+
|
|
8
|
+
const client = new Client({
|
|
9
|
+
token: "PUT_YOUR_TOKEN_HERE",
|
|
10
|
+
publicKey: "PUT_YOUR_PUBLIC_KEY_HERE",
|
|
11
|
+
httpAdapter: adapter,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// client.middleware() creates a global middleware, which is always executed before
|
|
15
|
+
// route middleware/handlers.
|
|
16
|
+
|
|
17
|
+
// https://discordhttps.js.org/classes/index.default.html#middleware
|
|
18
|
+
client.middleware(async (interaction) => {
|
|
19
|
+
const username = interaction.inGuild()
|
|
20
|
+
? interaction.member.user.username
|
|
21
|
+
: interaction.user.username;
|
|
22
|
+
console.log("[Global Middleware]: A command has been invoked by: ", username);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Everything here is middleware. A middleware can be defined as a function that takes a parameter
|
|
26
|
+
// and transforms the output in our case.
|
|
27
|
+
|
|
28
|
+
// client.register() mounts a middleware. This means that if the client receives a request from Discord
|
|
29
|
+
// and the corresponding middleware exists, the client will pass it to the appropriate middleware
|
|
30
|
+
// one by one in the order they were registered.
|
|
31
|
+
|
|
32
|
+
// simply, .register() lets the client know that these are the handlers.
|
|
33
|
+
|
|
34
|
+
client.register(commands);
|
|
35
|
+
|
|
36
|
+
if (process.env.NODE_ENV !== "production") {
|
|
37
|
+
const { commandRegistrarLayer, tunnelLayer } = await import("./DevLayer.js");
|
|
38
|
+
// Used to tunnel stuff
|
|
39
|
+
await tunnelLayer();
|
|
40
|
+
|
|
41
|
+
// automatic command registration to discord.
|
|
42
|
+
// The first parameter is the guild ID. If a guild ID is provided, the command will be registered for that guild; otherwise, it will be registered globally.
|
|
43
|
+
await commandRegistrarLayer(client, undefined);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
client.listen("interactions", 8080, () => {
|
|
47
|
+
console.log(
|
|
48
|
+
"Listening for interactions at http://localhost:8080/interactions"
|
|
49
|
+
);
|
|
50
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
## Discord.https
|
|
2
|
+
|
|
3
|
+
Vercel’s serverless functions must be placed inside the `api` directory.
|
|
4
|
+
|
|
5
|
+
By default, the URL is: `<vercel_url>/api/interactions`
|
|
6
|
+
|
|
7
|
+
More details:
|
|
8
|
+
|
|
9
|
+
- [Vercel](https://vercel.com)
|
|
10
|
+
- [Vercel Functions Documentation](https://vercel.com/docs/functions)
|
|
11
|
+
|
|
12
|
+
### How to deploy
|
|
13
|
+
|
|
14
|
+
Run this command to deploy to production:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npx vercel --prod
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Local development
|
|
21
|
+
|
|
22
|
+
Run your project locally with:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm run dev
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**A layer of local tunnel is embedded into the code for easier development**. This means requests pass through multiple layers: Discord → local tunnel → local Vercel server on your computer → your functions. The Induced latency is usually just a few milliseconds and depends on your internet connection. **This local tunneling layer only runs on your machine during development and can be removed if desired.**
|
|
29
|
+
|
|
30
|
+
For more information, view `DevLayer.ts` or, `DevLayer.js`
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Redirecting...</title>
|
|
7
|
+
<style>
|
|
8
|
+
* {
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0;
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
body {
|
|
15
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
|
|
16
|
+
"Oxygen", "Ubuntu", "Cantarell", sans-serif;
|
|
17
|
+
background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 100%);
|
|
18
|
+
color: #ffffff;
|
|
19
|
+
min-height: 100vh;
|
|
20
|
+
display: flex;
|
|
21
|
+
align-items: center;
|
|
22
|
+
justify-content: center;
|
|
23
|
+
padding: 2rem;
|
|
24
|
+
overflow: hidden;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.container {
|
|
28
|
+
text-align: center;
|
|
29
|
+
max-width: 600px;
|
|
30
|
+
animation: fadeIn 0.6s ease-out;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@keyframes fadeIn {
|
|
34
|
+
from {
|
|
35
|
+
opacity: 0;
|
|
36
|
+
transform: translateY(20px);
|
|
37
|
+
}
|
|
38
|
+
to {
|
|
39
|
+
opacity: 1;
|
|
40
|
+
transform: translateY(0);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.icon {
|
|
45
|
+
width: 80px;
|
|
46
|
+
height: 80px;
|
|
47
|
+
margin: 0 auto 2rem;
|
|
48
|
+
background: rgba(255, 255, 255, 0.05);
|
|
49
|
+
border-radius: 50%;
|
|
50
|
+
display: flex;
|
|
51
|
+
align-items: center;
|
|
52
|
+
justify-content: center;
|
|
53
|
+
border: 2px solid rgba(255, 255, 255, 0.1);
|
|
54
|
+
animation: pulse 2s ease-in-out infinite;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@keyframes pulse {
|
|
58
|
+
0%,
|
|
59
|
+
100% {
|
|
60
|
+
transform: scale(1);
|
|
61
|
+
opacity: 1;
|
|
62
|
+
}
|
|
63
|
+
50% {
|
|
64
|
+
transform: scale(1.05);
|
|
65
|
+
opacity: 0.8;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.icon svg {
|
|
70
|
+
width: 40px;
|
|
71
|
+
height: 40px;
|
|
72
|
+
stroke: #ffffff;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
h1 {
|
|
76
|
+
font-size: 2rem;
|
|
77
|
+
font-weight: 600;
|
|
78
|
+
margin-bottom: 1rem;
|
|
79
|
+
line-height: 1.2;
|
|
80
|
+
letter-spacing: -0.02em;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.message {
|
|
84
|
+
font-size: 1.125rem;
|
|
85
|
+
color: #a0a0a0;
|
|
86
|
+
margin-bottom: 2rem;
|
|
87
|
+
line-height: 1.6;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.redirect-info {
|
|
91
|
+
display: inline-block;
|
|
92
|
+
background: rgba(255, 255, 255, 0.05);
|
|
93
|
+
padding: 1rem 1.5rem;
|
|
94
|
+
border-radius: 12px;
|
|
95
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
96
|
+
margin-bottom: 2rem;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.redirect-text {
|
|
100
|
+
font-size: 0.875rem;
|
|
101
|
+
color: #808080;
|
|
102
|
+
margin-bottom: 0.5rem;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.redirect-path {
|
|
106
|
+
font-family: "Courier New", monospace;
|
|
107
|
+
font-size: 1rem;
|
|
108
|
+
color: #ffffff;
|
|
109
|
+
font-weight: 500;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.countdown-container {
|
|
113
|
+
margin-top: 2rem;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.countdown-label {
|
|
117
|
+
font-size: 0.875rem;
|
|
118
|
+
color: #808080;
|
|
119
|
+
margin-bottom: 1rem;
|
|
120
|
+
text-transform: uppercase;
|
|
121
|
+
letter-spacing: 0.1em;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.countdown {
|
|
125
|
+
font-size: 4rem;
|
|
126
|
+
font-weight: 700;
|
|
127
|
+
color: #ffffff;
|
|
128
|
+
font-variant-numeric: tabular-nums;
|
|
129
|
+
animation: countdownPulse 1s ease-in-out infinite;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
@keyframes countdownPulse {
|
|
133
|
+
0%,
|
|
134
|
+
100% {
|
|
135
|
+
transform: scale(1);
|
|
136
|
+
}
|
|
137
|
+
50% {
|
|
138
|
+
transform: scale(1.1);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.progress-bar {
|
|
143
|
+
width: 100%;
|
|
144
|
+
height: 4px;
|
|
145
|
+
background: rgba(255, 255, 255, 0.1);
|
|
146
|
+
border-radius: 2px;
|
|
147
|
+
margin-top: 2rem;
|
|
148
|
+
overflow: hidden;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.progress-fill {
|
|
152
|
+
height: 100%;
|
|
153
|
+
background: linear-gradient(90deg, #ffffff 0%, #a0a0a0 100%);
|
|
154
|
+
border-radius: 2px;
|
|
155
|
+
animation: progress 5s linear forwards;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
@keyframes progress {
|
|
159
|
+
from {
|
|
160
|
+
width: 100%;
|
|
161
|
+
}
|
|
162
|
+
to {
|
|
163
|
+
width: 0%;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
@media (max-width: 640px) {
|
|
168
|
+
h1 {
|
|
169
|
+
font-size: 1.5rem;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.message {
|
|
173
|
+
font-size: 1rem;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.countdown {
|
|
177
|
+
font-size: 3rem;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
</style>
|
|
181
|
+
</head>
|
|
182
|
+
<body>
|
|
183
|
+
<div class="container">
|
|
184
|
+
<div class="icon">
|
|
185
|
+
<svg
|
|
186
|
+
viewBox="0 0 24 24"
|
|
187
|
+
fill="none"
|
|
188
|
+
stroke-width="2"
|
|
189
|
+
stroke-linecap="round"
|
|
190
|
+
stroke-linejoin="round"
|
|
191
|
+
>
|
|
192
|
+
<circle cx="12" cy="12" r="10"></circle>
|
|
193
|
+
<line x1="12" y1="8" x2="12" y2="12"></line>
|
|
194
|
+
<line x1="12" y1="16" x2="12.01" y2="16"></line>
|
|
195
|
+
</svg>
|
|
196
|
+
</div>
|
|
197
|
+
|
|
198
|
+
<h1>The path you visited is incorrect</h1>
|
|
199
|
+
|
|
200
|
+
<p class="message">
|
|
201
|
+
Don't worry, we're automatically redirecting you to the correct
|
|
202
|
+
location.
|
|
203
|
+
</p>
|
|
204
|
+
|
|
205
|
+
<div class="redirect-info">
|
|
206
|
+
<div class="redirect-text">Redirecting to</div>
|
|
207
|
+
<div class="redirect-path">/api/interactions</div>
|
|
208
|
+
</div>
|
|
209
|
+
|
|
210
|
+
<div class="countdown-container">
|
|
211
|
+
<div class="countdown-label">Redirecting in</div>
|
|
212
|
+
<div class="countdown" id="countdown">5</div>
|
|
213
|
+
</div>
|
|
214
|
+
|
|
215
|
+
<div class="progress-bar">
|
|
216
|
+
<div class="progress-fill"></div>
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
<script>
|
|
221
|
+
let count = 5;
|
|
222
|
+
const countdownElement = document.getElementById("countdown");
|
|
223
|
+
|
|
224
|
+
const timer = setInterval(() => {
|
|
225
|
+
count--;
|
|
226
|
+
countdownElement.textContent = count;
|
|
227
|
+
|
|
228
|
+
if (count === 0) {
|
|
229
|
+
clearInterval(timer);
|
|
230
|
+
window.location.href = "/api/interactions";
|
|
231
|
+
}
|
|
232
|
+
}, 1000);
|
|
233
|
+
</script>
|
|
234
|
+
</body>
|
|
235
|
+
</html>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vercel",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Discord HTTPS interaction callback bot powered by discord.https",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "node src/spawner.js",
|
|
8
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"author": "",
|
|
12
|
+
"license": "ISC",
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@discordhttps/vercel-adapter": "^1.0.4",
|
|
15
|
+
"@vercel/functions": "^3.1.1",
|
|
16
|
+
"chalk": "^5.6.2",
|
|
17
|
+
"discord.https": "^3.0.15"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"fast-deep-equal": "^3.1.3",
|
|
21
|
+
"localtunnel": "^2.0.2"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/*
|
|
2
|
+
|
|
3
|
+
------------It is recommended not to modify this layer of code without proper knowledge------------
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
For Info:
|
|
7
|
+
|
|
8
|
+
Summary: This code is a development layer designed to ease development, with automation features such as auto local tunnel and automatic command registration.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
1. Automatic command registration
|
|
12
|
+
|
|
13
|
+
This layer provides support for automatic command registration by storing the last run command definitions in a file.
|
|
14
|
+
Later, these definitions are read and compared with the current command definitions.
|
|
15
|
+
If they are the same, there is no need to re-register, as nothing has changed.
|
|
16
|
+
If they are different, the command definitions have changed and require re-registration.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
2.Local Tunnel
|
|
20
|
+
|
|
21
|
+
Local tunnels establish secure pathways between your localhost and the Internet, making it possible to expose web applications for access from anywhere.
|
|
22
|
+
|
|
23
|
+
What LocalTunnel does:
|
|
24
|
+
|
|
25
|
+
- Imagine you’re running a website on your computer at http://localhost:3000.
|
|
26
|
+
- Normally, only you can see it because it’s “local” — it is only on your computer.
|
|
27
|
+
- LocalTunnel gives it a public URL, like https://awesome-name.domain.com, so discord can send a request to your computer.
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
Why this matters for Discord:
|
|
31
|
+
|
|
32
|
+
- Normally, when you open Discord, your computer sends requests to Discord’s servers — everything works because Discord is public.
|
|
33
|
+
- But if you want Discord to **send data to your computer** (like a webhook), your computer needs a public address.
|
|
34
|
+
- LocalTunnel provides that public URL, so Discord knows where to send the requests.
|
|
35
|
+
|
|
36
|
+
Why it’s useful:
|
|
37
|
+
|
|
38
|
+
- Testing webhooks (like Discord)
|
|
39
|
+
- Debugging APIs without deploying to a server
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
export async function tunnelLayer() {
|
|
43
|
+
if (process.env.NODE_ENV !== "production") {
|
|
44
|
+
const chalk = await import("chalk");
|
|
45
|
+
const localtunnel = (await import("localtunnel")).default;
|
|
46
|
+
const tunnel = await localtunnel({
|
|
47
|
+
port: 3000,
|
|
48
|
+
subdomain: "discord-https",
|
|
49
|
+
});
|
|
50
|
+
console.log(
|
|
51
|
+
chalk.default.yellow(
|
|
52
|
+
"[DevLayer] Warning: This URL is intended only for testing and developing your bot.\n" +
|
|
53
|
+
"Never use it in production or hosting.\n" +
|
|
54
|
+
"1. It may be slower, but this is not an issue for bot development.\n" +
|
|
55
|
+
"2. This message should not appear in a production/hosting environment. If it does, your environment variables are incorrect and need to be fixed.\n" +
|
|
56
|
+
"For more information, visit https://discord.com/invite/pSgfJ4K5ej\n\n"
|
|
57
|
+
)
|
|
58
|
+
);
|
|
59
|
+
console.log(
|
|
60
|
+
chalk.default.blue(
|
|
61
|
+
`[DevLayer] Interactions Endpoint URL: ${tunnel.url}/api/interactions\n`
|
|
62
|
+
)
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
console.log(
|
|
66
|
+
chalk.default.yellow(
|
|
67
|
+
`[DevLayer] Modify your interaction url with the above\n`
|
|
68
|
+
)
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
process.on("SIGINT", async () => {
|
|
72
|
+
tunnel.close();
|
|
73
|
+
console.log("[DevLayer] Tunnel has been shut down");
|
|
74
|
+
process.exit();
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function commandRegistrarLayer(client, guildId) {
|
|
80
|
+
if (process.env.NODE_ENV !== "production") {
|
|
81
|
+
const FILENAME = "__dev_layer_cache__";
|
|
82
|
+
const chalk = (await import("chalk")).default;
|
|
83
|
+
const isEqual = (await import("fast-deep-equal")).default;
|
|
84
|
+
const { writeFile, access, readFile, constants } = await import(
|
|
85
|
+
"node:fs/promises"
|
|
86
|
+
);
|
|
87
|
+
const { join } = await import("node:path");
|
|
88
|
+
|
|
89
|
+
let localDump = [];
|
|
90
|
+
const filePath = join(import.meta.dirname, FILENAME);
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
await access(filePath, constants.F_OK);
|
|
94
|
+
const contains = await readFile(filePath, {
|
|
95
|
+
encoding: "utf-8",
|
|
96
|
+
});
|
|
97
|
+
const json = JSON.parse(contains);
|
|
98
|
+
localDump = json;
|
|
99
|
+
} catch {
|
|
100
|
+
await writeFile(filePath, "[]");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
// https://github.com/discordhttps/discord.https/blob/main/src/interactionRouter/internal.ts#L271
|
|
105
|
+
if (
|
|
106
|
+
!isEqual(
|
|
107
|
+
localDump,
|
|
108
|
+
// To remove undefined properties
|
|
109
|
+
JSON.parse(JSON.stringify(client.router.CommandDefinitions))
|
|
110
|
+
)
|
|
111
|
+
) {
|
|
112
|
+
console.log(
|
|
113
|
+
chalk.yellowBright(
|
|
114
|
+
`[DevLayer] Command change detected, re-registering with discord in ${
|
|
115
|
+
guildId ? `Guild - ${guildId}` : "Global"
|
|
116
|
+
}...`
|
|
117
|
+
)
|
|
118
|
+
);
|
|
119
|
+
const registar = await client.getRegistar();
|
|
120
|
+
|
|
121
|
+
if (guildId) {
|
|
122
|
+
await registar.localSlashRegistar(guildId);
|
|
123
|
+
} else {
|
|
124
|
+
await registar.globalSlashRegistar();
|
|
125
|
+
}
|
|
126
|
+
writeFile(filePath, JSON.stringify(client.router.CommandDefinitions));
|
|
127
|
+
console.log(
|
|
128
|
+
chalk.greenBright("[DevLayer] Commands synced successfully!")
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
} catch (err) {
|
|
132
|
+
console.error("[DevLayer] Failed to sync commands:", err);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// This code includes some upper-basic level concepts. If you are an absolute beginner, you may struggle to understand it.
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
MessageFlags,
|
|
5
|
+
MediaGalleryBuilder,
|
|
6
|
+
MediaGalleryItemBuilder,
|
|
7
|
+
TextDisplayBuilder,
|
|
8
|
+
SeparatorBuilder,
|
|
9
|
+
SeparatorSpacingSize,
|
|
10
|
+
ButtonBuilder,
|
|
11
|
+
ButtonStyle,
|
|
12
|
+
ActionRowBuilder,
|
|
13
|
+
} from "discord.https";
|
|
14
|
+
|
|
15
|
+
// https://discordhttps.js.org/classes/interactionRouter.InteractionRouter.html
|
|
16
|
+
import { InteractionRouter } from "discord.https/router";
|
|
17
|
+
|
|
18
|
+
const router = new InteractionRouter();
|
|
19
|
+
|
|
20
|
+
// https://discord.com/developers/docs/change-log/2025-04-22-components-v2
|
|
21
|
+
const header = [
|
|
22
|
+
new MediaGalleryBuilder().addItems(
|
|
23
|
+
new MediaGalleryItemBuilder().setURL(
|
|
24
|
+
"https://raw.githubusercontent.com/discordhttps/discord.https/refs/heads/main/assets/logo.png"
|
|
25
|
+
)
|
|
26
|
+
),
|
|
27
|
+
new TextDisplayBuilder().setContent(
|
|
28
|
+
"**Discord.https** is a robust, modular library for implementing Discord HTTP interactions."
|
|
29
|
+
),
|
|
30
|
+
new SeparatorBuilder()
|
|
31
|
+
.setSpacing(SeparatorSpacingSize.Large)
|
|
32
|
+
.setDivider(true),
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
const footer = [
|
|
36
|
+
new SeparatorBuilder()
|
|
37
|
+
.setSpacing(SeparatorSpacingSize.Large)
|
|
38
|
+
.setDivider(true),
|
|
39
|
+
new ActionRowBuilder().addComponents(
|
|
40
|
+
new ButtonBuilder()
|
|
41
|
+
.setStyle(ButtonStyle.Link)
|
|
42
|
+
.setLabel("Github")
|
|
43
|
+
.setEmoji({
|
|
44
|
+
name: "⭐",
|
|
45
|
+
})
|
|
46
|
+
.setURL("https://google.com"),
|
|
47
|
+
new ButtonBuilder()
|
|
48
|
+
.setStyle(ButtonStyle.Link)
|
|
49
|
+
.setLabel("Node Package")
|
|
50
|
+
.setEmoji({
|
|
51
|
+
name: "📦",
|
|
52
|
+
})
|
|
53
|
+
.setURL("https://www.npmjs.com/package/discord.https"),
|
|
54
|
+
new ButtonBuilder()
|
|
55
|
+
.setStyle(ButtonStyle.Link)
|
|
56
|
+
.setLabel("Documentation")
|
|
57
|
+
.setEmoji({
|
|
58
|
+
name: "📘",
|
|
59
|
+
})
|
|
60
|
+
.setURL("https://discordhttps.js.org/")
|
|
61
|
+
),
|
|
62
|
+
];
|
|
63
|
+
// https://discordhttps.js.org/classes/interactionRouter.InteractionRouter.html#command
|
|
64
|
+
router.command(
|
|
65
|
+
(builder) =>
|
|
66
|
+
builder
|
|
67
|
+
.setName("jokes")
|
|
68
|
+
.setDescription("Gives you random joke")
|
|
69
|
+
.addStringOption((option) =>
|
|
70
|
+
option
|
|
71
|
+
.setName("type")
|
|
72
|
+
.setDescription("Type of joke")
|
|
73
|
+
.addChoices(
|
|
74
|
+
{ name: "general", value: "general" },
|
|
75
|
+
{ name: "knock-knock", value: "knock-knock" },
|
|
76
|
+
{ name: "programming", value: "programming" },
|
|
77
|
+
{ name: "dad", value: "dad" }
|
|
78
|
+
)
|
|
79
|
+
.setRequired(true)
|
|
80
|
+
),
|
|
81
|
+
async (interaction) => {
|
|
82
|
+
// Get the value of the "type" option from the slash command.
|
|
83
|
+
// The 'true' argument makes this required; if it's missing, an error is thrown.
|
|
84
|
+
const option = interaction.options.getString("type", true);
|
|
85
|
+
|
|
86
|
+
// Fetch a joke from the API based on the type (e.g., "general", "programming", etc.)
|
|
87
|
+
// This returns a Promise, so we await it to get the response.
|
|
88
|
+
// Simplest explanation for beginners, https://www.geeksforgeeks.org/node-js/rest-api-introduction
|
|
89
|
+
const response = await fetch(
|
|
90
|
+
`https://official-joke-api.appspot.com/jokes/${option}/random`
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
// Convert the response into JSON format.
|
|
94
|
+
// This allows us to access the joke's content as JavaScript objects.
|
|
95
|
+
// This process is called deserilization,
|
|
96
|
+
|
|
97
|
+
// The received data is in the format of an array: [{ setup: "", punchline: "" }]
|
|
98
|
+
// [body] uses array destructuring. A simple equivalent would be:
|
|
99
|
+
// var body = await response.json();
|
|
100
|
+
// body = body[0];
|
|
101
|
+
|
|
102
|
+
const [body] = await response.json();
|
|
103
|
+
|
|
104
|
+
// Create a message component (or text display) with the joke content.
|
|
105
|
+
const middlePart = new TextDisplayBuilder().setContent(
|
|
106
|
+
`**Joke**: ${body.setup}\n**Punchline**: ${body.punchline}`
|
|
107
|
+
);
|
|
108
|
+
// send the joke to the user.
|
|
109
|
+
await interaction.reply({
|
|
110
|
+
// - flags: special options for the message (e.g., IsComponentsV2 indicate newer component handling)
|
|
111
|
+
flags: MessageFlags.IsComponentsV2,
|
|
112
|
+
// Here we spread the arrays with `...` to flatten them into a single array.
|
|
113
|
+
components: [...header, middlePart, ...footer],
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
export default router;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// https://discordhttps.js.org/classes/interactionRouter.InteractionRouter.html
|
|
2
|
+
import { InteractionRouter } from "discord.https/router";
|
|
3
|
+
|
|
4
|
+
const router = new InteractionRouter();
|
|
5
|
+
|
|
6
|
+
// https://discordhttps.js.org/classes/interactionRouter.InteractionRouter.html#command
|
|
7
|
+
router.command(
|
|
8
|
+
(builder) => builder.setName("ping").setDescription("says pong!"),
|
|
9
|
+
async (interaction) => await interaction.reply("Pong! 🏓")
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
export default router;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MessageFlags,
|
|
3
|
+
MediaGalleryBuilder,
|
|
4
|
+
MediaGalleryItemBuilder,
|
|
5
|
+
TextDisplayBuilder,
|
|
6
|
+
SeparatorBuilder,
|
|
7
|
+
SeparatorSpacingSize,
|
|
8
|
+
ButtonBuilder,
|
|
9
|
+
ButtonStyle,
|
|
10
|
+
ActionRowBuilder,
|
|
11
|
+
} from "discord.https";
|
|
12
|
+
|
|
13
|
+
// https://discordhttps.js.org/classes/interactionRouter.InteractionRouter.html
|
|
14
|
+
import { InteractionRouter } from "discord.https/router";
|
|
15
|
+
|
|
16
|
+
const router = new InteractionRouter();
|
|
17
|
+
|
|
18
|
+
// https://discord.com/developers/docs/change-log/2025-04-22-components-v2
|
|
19
|
+
const components = [
|
|
20
|
+
new MediaGalleryBuilder().addItems(
|
|
21
|
+
new MediaGalleryItemBuilder().setURL(
|
|
22
|
+
"https://raw.githubusercontent.com/discordhttps/discord.https/refs/heads/main/assets/logo.png"
|
|
23
|
+
)
|
|
24
|
+
),
|
|
25
|
+
new TextDisplayBuilder().setContent(
|
|
26
|
+
"**Discord.https** is a robust, modular library for implementing Discord HTTP interactions."
|
|
27
|
+
),
|
|
28
|
+
new SeparatorBuilder()
|
|
29
|
+
.setSpacing(SeparatorSpacingSize.Large)
|
|
30
|
+
.setDivider(true),
|
|
31
|
+
new TextDisplayBuilder().setContent(
|
|
32
|
+
"## Commands Available in This Template\n- /help\n- /index\n- /info\n- Context User Command: Profile (right-click a user and select Apps > Profile)"
|
|
33
|
+
),
|
|
34
|
+
new TextDisplayBuilder().setContent("Related Links"),
|
|
35
|
+
new ActionRowBuilder().addComponents(
|
|
36
|
+
new ButtonBuilder()
|
|
37
|
+
.setStyle(ButtonStyle.Link)
|
|
38
|
+
.setLabel("Github")
|
|
39
|
+
.setEmoji({
|
|
40
|
+
name: "⭐",
|
|
41
|
+
})
|
|
42
|
+
.setURL("https://google.com"),
|
|
43
|
+
new ButtonBuilder()
|
|
44
|
+
.setStyle(ButtonStyle.Link)
|
|
45
|
+
.setLabel("Node Package")
|
|
46
|
+
.setEmoji({
|
|
47
|
+
name: "📦",
|
|
48
|
+
})
|
|
49
|
+
.setURL("https://www.npmjs.com/package/discord.https"),
|
|
50
|
+
new ButtonBuilder()
|
|
51
|
+
.setStyle(ButtonStyle.Link)
|
|
52
|
+
.setLabel("Documentation")
|
|
53
|
+
.setEmoji({
|
|
54
|
+
name: "📘",
|
|
55
|
+
})
|
|
56
|
+
.setURL("https://discordhttps.js.org/")
|
|
57
|
+
),
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
// https://discordhttps.js.org/classes/interactionRouter.InteractionRouter.html#command
|
|
61
|
+
router.command(
|
|
62
|
+
(builder) =>
|
|
63
|
+
builder
|
|
64
|
+
.setName("help")
|
|
65
|
+
.setDescription("Gives you information about discord.https"),
|
|
66
|
+
async (interaction) =>
|
|
67
|
+
await interaction.reply({
|
|
68
|
+
flags: MessageFlags.IsComponentsV2,
|
|
69
|
+
components: components,
|
|
70
|
+
})
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
export default router;
|