@seedcord/http 0.0.1 → 0.1.0-next.1
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/RouteManifest-BHdAeyLG.d.mts +60 -0
- package/dist/edge.index-BAgNb6TV.mjs +1046 -0
- package/dist/edge.index-BAgNb6TV.mjs.map +1 -0
- package/dist/edge.index-CTOyjsO4.d.mts +501 -0
- package/dist/edge.index-D-60VfMn.cjs +1175 -0
- package/dist/edge.index-D-60VfMn.cjs.map +1 -0
- package/dist/edge.index.cjs +22 -0
- package/dist/edge.index.d.cts +1 -0
- package/dist/edge.index.d.mts +4 -0
- package/dist/edge.index.mjs +5 -0
- package/dist/index.cjs +413 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +63 -4
- package/dist/index.mjs +397 -3
- package/dist/index.mjs.map +1 -1
- package/dist/manifest.index.cjs +16 -0
- package/dist/manifest.index.cjs.map +1 -0
- package/dist/manifest.index.d.cts +1 -0
- package/dist/manifest.index.d.mts +11 -0
- package/dist/manifest.index.mjs +15 -0
- package/dist/manifest.index.mjs.map +1 -0
- package/dist/rolldown-runtime-BUUfjzRC.mjs +36 -0
- package/package.json +95 -58
package/dist/index.cjs
CHANGED
|
@@ -1,9 +1,419 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_edge_index = require('./edge.index-D-60VfMn.cjs');
|
|
3
|
+
let _seedcord_errors_internal = require("@seedcord/errors/internal");
|
|
4
|
+
let envapt = require("envapt");
|
|
5
|
+
let _discordjs_rest = require("@discordjs/rest");
|
|
6
|
+
let _seedcord_core_internal = require("@seedcord/core/internal");
|
|
7
|
+
let _seedcord_logger = require("@seedcord/logger");
|
|
8
|
+
let _seedcord_rate_limiter = require("@seedcord/rate-limiter");
|
|
9
|
+
let discord_api_types_v10 = require("discord-api-types/v10");
|
|
10
|
+
let _seedcord_errors = require("@seedcord/errors");
|
|
11
|
+
let node_events = require("node:events");
|
|
12
|
+
let node_http = require("node:http");
|
|
13
|
+
let _seedcord_core_node_internal = require("@seedcord/core/node/internal");
|
|
14
|
+
let _seedcord_logger_node = require("@seedcord/logger/node");
|
|
15
|
+
let _seedcord_types_internal = require("@seedcord/types/internal");
|
|
16
|
+
let _seedcord_core_hmr = require("@seedcord/core/hmr");
|
|
17
|
+
let _seedcord_utils = require("@seedcord/utils");
|
|
18
|
+
let _seedcord_utils_node = require("@seedcord/utils/node");
|
|
2
19
|
|
|
20
|
+
//#region src/manifest/RouteManifest.ts
|
|
21
|
+
/** @internal */
|
|
22
|
+
const EMPTY_MANIFEST = {
|
|
23
|
+
commands: [],
|
|
24
|
+
components: [],
|
|
25
|
+
autocomplete: [],
|
|
26
|
+
subscribers: []
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/node/InteractionDispatcher.ts
|
|
31
|
+
/**
|
|
32
|
+
* Discovers interaction handlers from the filesystem into the engine's live route maps.
|
|
33
|
+
*
|
|
34
|
+
* The node host runs it at startup and dev HMR swaps map entries in place. The engine's `resolve`
|
|
35
|
+
* reads `maps` per request. The edge path builds its maps from the generated manifest.
|
|
36
|
+
*/
|
|
37
|
+
var InteractionDispatcher = class {
|
|
38
|
+
handlersDir;
|
|
39
|
+
maps;
|
|
40
|
+
targets;
|
|
41
|
+
/** @internal */
|
|
42
|
+
logger = new _seedcord_logger.Logger("Interactions");
|
|
43
|
+
isInitialized = false;
|
|
44
|
+
hmrHandler;
|
|
45
|
+
rowOwners = /* @__PURE__ */ new Map();
|
|
46
|
+
loading = false;
|
|
47
|
+
loadedHandlers = [];
|
|
48
|
+
constructor(handlersDir) {
|
|
49
|
+
this.handlersDir = handlersDir;
|
|
50
|
+
this.maps = require_edge_index.buildRouteMaps(EMPTY_MANIFEST);
|
|
51
|
+
this.targets = this.buildTargets();
|
|
52
|
+
if (!envapt.Envapter.isDevelopment && !envapt.Envapter.isTest) return;
|
|
53
|
+
this.hmrHandler = new _seedcord_core_hmr.HmrModuleHandler({
|
|
54
|
+
handlersDir,
|
|
55
|
+
isHandler: this.isHandler.bind(this),
|
|
56
|
+
registerHandler: this.registerHandler.bind(this),
|
|
57
|
+
unregisterHandler: this.unregisterHandler.bind(this),
|
|
58
|
+
getArtifacts: this.getArtifacts.bind(this),
|
|
59
|
+
logger: this.logger
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/** @internal */
|
|
63
|
+
async init() {
|
|
64
|
+
if (this.isInitialized) return;
|
|
65
|
+
this.isInitialized = true;
|
|
66
|
+
this.loading = true;
|
|
67
|
+
this.loadedHandlers.length = 0;
|
|
68
|
+
try {
|
|
69
|
+
await (0, _seedcord_utils_node.traverseDirectory)(this.handlersDir, (fullPath, relativePath, imported) => {
|
|
70
|
+
for (const value of Object.values(imported)) {
|
|
71
|
+
if (!this.isHandler(value)) continue;
|
|
72
|
+
this.registerHandler(value, relativePath);
|
|
73
|
+
this.hmrHandler?.trackHandler(fullPath, value);
|
|
74
|
+
}
|
|
75
|
+
}, this.logger);
|
|
76
|
+
} finally {
|
|
77
|
+
this.loading = false;
|
|
78
|
+
}
|
|
79
|
+
this.logger.utils.block("Loaded handlers", [...this.logger.utils.entries(this.loadedHandlers), ...this.logger.utils.counts({ routes: this.rowOwners.size })]);
|
|
80
|
+
}
|
|
81
|
+
/** @internal */
|
|
82
|
+
async onHmr(event) {
|
|
83
|
+
await this.hmrHandler?.handle(event);
|
|
84
|
+
}
|
|
85
|
+
isHandler(value) {
|
|
86
|
+
if (typeof value !== "function") return false;
|
|
87
|
+
return (value.prototype instanceof require_edge_index.InteractionHandler || value.prototype instanceof require_edge_index.AutocompleteHandler) && Reflect.hasMetadata(_seedcord_core_internal.InteractionMetadataKey, value);
|
|
88
|
+
}
|
|
89
|
+
getArtifacts(ctor) {
|
|
90
|
+
const routeIds = [];
|
|
91
|
+
for (const [routeId, owner] of this.rowOwners) if (owner.ctor === ctor) routeIds.push(routeId);
|
|
92
|
+
return routeIds;
|
|
93
|
+
}
|
|
94
|
+
targetFor(route) {
|
|
95
|
+
return this.targets[route];
|
|
96
|
+
}
|
|
97
|
+
buildTargets() {
|
|
98
|
+
return {
|
|
99
|
+
[_seedcord_core_internal.InteractionRoutes.Slash]: {
|
|
100
|
+
map: this.maps.slash,
|
|
101
|
+
kind: "slash"
|
|
102
|
+
},
|
|
103
|
+
[_seedcord_core_internal.InteractionRoutes.UserContextMenu]: {
|
|
104
|
+
map: this.maps.userContextMenu,
|
|
105
|
+
kind: "userContextMenu"
|
|
106
|
+
},
|
|
107
|
+
[_seedcord_core_internal.InteractionRoutes.MessageContextMenu]: {
|
|
108
|
+
map: this.maps.messageContextMenu,
|
|
109
|
+
kind: "messageContextMenu"
|
|
110
|
+
},
|
|
111
|
+
[_seedcord_core_internal.InteractionRoutes.Autocomplete]: {
|
|
112
|
+
map: this.maps.autocomplete,
|
|
113
|
+
kind: "autocomplete"
|
|
114
|
+
},
|
|
115
|
+
[_seedcord_core_internal.InteractionRoutes.Button]: {
|
|
116
|
+
map: this.maps.components.button,
|
|
117
|
+
kind: "button"
|
|
118
|
+
},
|
|
119
|
+
[_seedcord_core_internal.InteractionRoutes.StringMenu]: {
|
|
120
|
+
map: this.maps.components.stringSelect,
|
|
121
|
+
kind: "stringMenu"
|
|
122
|
+
},
|
|
123
|
+
[_seedcord_core_internal.InteractionRoutes.UserMenu]: {
|
|
124
|
+
map: this.maps.components.userSelect,
|
|
125
|
+
kind: "userMenu"
|
|
126
|
+
},
|
|
127
|
+
[_seedcord_core_internal.InteractionRoutes.RoleMenu]: {
|
|
128
|
+
map: this.maps.components.roleSelect,
|
|
129
|
+
kind: "roleMenu"
|
|
130
|
+
},
|
|
131
|
+
[_seedcord_core_internal.InteractionRoutes.ChannelMenu]: {
|
|
132
|
+
map: this.maps.components.channelSelect,
|
|
133
|
+
kind: "channelMenu"
|
|
134
|
+
},
|
|
135
|
+
[_seedcord_core_internal.InteractionRoutes.MentionableMenu]: {
|
|
136
|
+
map: this.maps.components.mentionableSelect,
|
|
137
|
+
kind: "mentionableMenu"
|
|
138
|
+
},
|
|
139
|
+
[_seedcord_core_internal.InteractionRoutes.Modal]: {
|
|
140
|
+
map: this.maps.components.modal,
|
|
141
|
+
kind: "modal"
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
registerHandler(ctor, relativePath) {
|
|
146
|
+
const writes = [];
|
|
147
|
+
for (const [route, keys] of (0, _seedcord_core_internal.interactionRoutesOf)(ctor)) {
|
|
148
|
+
const target = this.targetFor(route);
|
|
149
|
+
for (const key of keys) {
|
|
150
|
+
const existing = this.rowOwners.get(`${target.kind}:${key}`);
|
|
151
|
+
if (existing && existing.ctor !== ctor) throw new _seedcord_errors_internal.SeedcordError(_seedcord_errors.SeedcordErrorCode.InteractionDuplicateRoute, [
|
|
152
|
+
key,
|
|
153
|
+
existing.ctor.name,
|
|
154
|
+
ctor.name
|
|
155
|
+
]);
|
|
156
|
+
writes.push([target, key]);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (writes.length === 0) return;
|
|
160
|
+
for (const [target, key] of writes) {
|
|
161
|
+
const routeId = `${target.kind}:${key}`;
|
|
162
|
+
target.map.set(key, {
|
|
163
|
+
kind: target.kind,
|
|
164
|
+
routeId,
|
|
165
|
+
load: () => Promise.resolve({ [ctor.name]: ctor })
|
|
166
|
+
});
|
|
167
|
+
this.rowOwners.set(routeId, {
|
|
168
|
+
ctor,
|
|
169
|
+
target,
|
|
170
|
+
key
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
const from = (0, _seedcord_utils.formatFilePath)(relativePath);
|
|
174
|
+
if (this.loading) this.loadedHandlers.push({
|
|
175
|
+
name: ctor.name,
|
|
176
|
+
from
|
|
177
|
+
});
|
|
178
|
+
else this.logger.utils.registration(ctor.name, from);
|
|
179
|
+
}
|
|
180
|
+
unregisterHandler(ctor, artifacts) {
|
|
181
|
+
const routeIds = artifacts ?? this.getArtifacts(ctor);
|
|
182
|
+
for (const routeId of routeIds) {
|
|
183
|
+
const owner = this.rowOwners.get(routeId);
|
|
184
|
+
if (owner?.ctor !== ctor) continue;
|
|
185
|
+
this.rowOwners.delete(routeId);
|
|
186
|
+
owner.target.map.delete(owner.key);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
//#endregion
|
|
192
|
+
//#region src/node/webBridge.ts
|
|
193
|
+
function toHeaders(raw) {
|
|
194
|
+
const headers = new Headers();
|
|
195
|
+
for (const [name, value] of Object.entries(raw)) {
|
|
196
|
+
if (value === void 0) continue;
|
|
197
|
+
if (Array.isArray(value)) for (const item of value) headers.append(name, item);
|
|
198
|
+
else headers.set(name, value);
|
|
199
|
+
}
|
|
200
|
+
return headers;
|
|
201
|
+
}
|
|
202
|
+
async function toWebRequest(request) {
|
|
203
|
+
const chunks = [];
|
|
204
|
+
for await (const chunk of request) chunks.push(chunk);
|
|
205
|
+
const method = request.method ?? "GET";
|
|
206
|
+
const body = method === "GET" || method === "HEAD" ? void 0 : new Uint8Array(Buffer.concat(chunks));
|
|
207
|
+
return new Request(`http://${request.headers.host ?? "localhost"}${request.url ?? "/"}`, {
|
|
208
|
+
method,
|
|
209
|
+
headers: toHeaders(request.headers),
|
|
210
|
+
...body !== void 0 && { body }
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
async function writeWebResponse(response, out) {
|
|
214
|
+
const headers = Object.fromEntries(response.headers);
|
|
215
|
+
const cookies = response.headers.getSetCookie();
|
|
216
|
+
if (cookies.length > 0) headers["set-cookie"] = cookies;
|
|
217
|
+
out.writeHead(response.status, headers);
|
|
218
|
+
out.end(response.body === null ? void 0 : Buffer.from(await response.arrayBuffer()));
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
//#endregion
|
|
222
|
+
//#region src/node/Seedcord.ts
|
|
223
|
+
const DEFAULT_PORT = 3e3;
|
|
224
|
+
const SERVER_SHUTDOWN_TIMEOUT_MS = 5e3;
|
|
225
|
+
const DRAIN_TIMEOUT_MS = 1e4;
|
|
226
|
+
/**
|
|
227
|
+
* The HTTP-interactions bot host, a long-running node server around the engine.
|
|
228
|
+
*
|
|
229
|
+
* Discovers handlers from `config.bot.interactions.path`, verifies and dispatches interactions on
|
|
230
|
+
* `start(port)`, and runs coordinated shutdown with an in-flight drain. The edge deploy path calls
|
|
231
|
+
* `createSeedcord` from a generated entry.
|
|
232
|
+
*/
|
|
233
|
+
var Seedcord = class Seedcord extends _seedcord_core_node_internal.Pluggable {
|
|
234
|
+
config;
|
|
235
|
+
/** @internal */
|
|
236
|
+
[_seedcord_types_internal.SeedcordBrand] = true;
|
|
237
|
+
/** @internal */
|
|
238
|
+
augmentTarget = "@seedcord/http";
|
|
239
|
+
/** @internal */
|
|
240
|
+
version = require_edge_index.version;
|
|
241
|
+
/** Workerd-compatible Discord REST client. `start()` sets the token. */
|
|
242
|
+
rest = new _discordjs_rest.REST();
|
|
243
|
+
/** @see {@link IRateLimiter} */
|
|
244
|
+
rateLimiter;
|
|
245
|
+
/** @see {@link CoordinatedShutdown} */
|
|
246
|
+
shutdown;
|
|
247
|
+
/** @see {@link CoordinatedStartup} */
|
|
248
|
+
startup;
|
|
249
|
+
interactions;
|
|
250
|
+
healthCheck;
|
|
251
|
+
hmrManager;
|
|
252
|
+
logger = new _seedcord_logger.Logger("Server");
|
|
253
|
+
server;
|
|
254
|
+
boundPort;
|
|
255
|
+
requestedPort = DEFAULT_PORT;
|
|
256
|
+
fetchedUsername;
|
|
257
|
+
constructor(config) {
|
|
258
|
+
const shutdown = new _seedcord_core_node_internal.CoordinatedShutdown();
|
|
259
|
+
const startup = new _seedcord_core_node_internal.CoordinatedStartup();
|
|
260
|
+
super(shutdown, startup);
|
|
261
|
+
this.config = config;
|
|
262
|
+
(0, _seedcord_logger_node.installNodeDefaults)(config.logger);
|
|
263
|
+
(0, _seedcord_core_internal.setBotColor)(config.botColor);
|
|
264
|
+
this.shutdown = shutdown;
|
|
265
|
+
this.startup = startup;
|
|
266
|
+
this.hmrManager = new _seedcord_core_internal.HmrManager();
|
|
267
|
+
this.hmrManager.init();
|
|
268
|
+
if (this.config.bot.interactions.path) this.interactions = new InteractionDispatcher(this.config.bot.interactions.path);
|
|
269
|
+
this.rateLimiter = config.store ?? new _seedcord_rate_limiter.MemoryRateLimiter();
|
|
270
|
+
this.healthCheck = config.runtime === "edge" ? void 0 : _seedcord_core_node_internal.HealthCheck.fromOption(this.shutdown, config.healthCheck);
|
|
271
|
+
this.registerStartupTasks();
|
|
272
|
+
}
|
|
273
|
+
/** The bot's discord username, populated by the ready fetch. */
|
|
274
|
+
get username() {
|
|
275
|
+
return this.fetchedUsername;
|
|
276
|
+
}
|
|
277
|
+
/** The bound server port, populated once `start()` is listening. */
|
|
278
|
+
get port() {
|
|
279
|
+
return this.boundPort;
|
|
280
|
+
}
|
|
281
|
+
pluginCapabilities() {
|
|
282
|
+
const token = envapt.Envapter.get("DISCORD_BOT_TOKEN");
|
|
283
|
+
return {
|
|
284
|
+
rest: this.rest,
|
|
285
|
+
...token !== void 0 && { token }
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Starts the host and runs the startup tasks.
|
|
290
|
+
*
|
|
291
|
+
* @param port - The port the interaction server binds. {@default `3000`}
|
|
292
|
+
*/
|
|
293
|
+
async start(port = DEFAULT_PORT) {
|
|
294
|
+
this.requestedPort = port;
|
|
295
|
+
try {
|
|
296
|
+
await super.init();
|
|
297
|
+
} catch (caught) {
|
|
298
|
+
await this.shutdown.run(1, false);
|
|
299
|
+
Seedcord.reset();
|
|
300
|
+
throw caught;
|
|
301
|
+
}
|
|
302
|
+
return this;
|
|
303
|
+
}
|
|
304
|
+
static reset() {
|
|
305
|
+
super.reset();
|
|
306
|
+
_seedcord_logger.LoggerChannelRegistry.instance.reset();
|
|
307
|
+
}
|
|
308
|
+
registerStartupTasks() {
|
|
309
|
+
if (envapt.Envapter.isDevelopment || envapt.Envapter.isTest) this.registerHmrAwareModules();
|
|
310
|
+
const { interactions } = this;
|
|
311
|
+
if (interactions) this.startup.addTask(_seedcord_core_node_internal.StartupPhase.Configuration, "Interactions Initialization", async () => {
|
|
312
|
+
interactions.logger.utils.initialization("Interactions", "start");
|
|
313
|
+
await interactions.init();
|
|
314
|
+
interactions.logger.utils.initialization("Interactions", "end");
|
|
315
|
+
});
|
|
316
|
+
this.startup.addTask(_seedcord_core_node_internal.StartupPhase.Ready, "Http Server", () => this.listen());
|
|
317
|
+
if (!envapt.Envapter.isTest) this.startup.addTask(_seedcord_core_node_internal.StartupPhase.Ready, "Identity", () => this.fetchUsername());
|
|
318
|
+
const { healthCheck } = this;
|
|
319
|
+
if (healthCheck) this.startup.addTask(_seedcord_core_node_internal.StartupPhase.Ready, "Health Check", async () => {
|
|
320
|
+
healthCheck.logger.utils.initialization("HealthCheck", "start");
|
|
321
|
+
await healthCheck.init();
|
|
322
|
+
healthCheck.logger.utils.initialization("HealthCheck", "end");
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
registerHmrAwareModules() {
|
|
326
|
+
this.startup.addTask(_seedcord_core_node_internal.StartupPhase.Configuration, "HMR Registration", async () => {
|
|
327
|
+
if (this.interactions) this.hmrManager.register(this.interactions);
|
|
328
|
+
for (const plugin of this.plugins) this.hmrManager.register(plugin);
|
|
329
|
+
await Promise.resolve();
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
async listen() {
|
|
333
|
+
const token = (0, _seedcord_errors_internal.validateDiscordToken)(envapt.Envapter.get("DISCORD_BOT_TOKEN"));
|
|
334
|
+
this.rest.setToken(token);
|
|
335
|
+
const maps = this.interactions?.maps ?? require_edge_index.buildRouteMaps(EMPTY_MANIFEST);
|
|
336
|
+
const { handle, inFlight } = require_edge_index.buildEngine(this, maps);
|
|
337
|
+
const server = (0, node_http.createServer)((incoming, outgoing) => {
|
|
338
|
+
(async () => {
|
|
339
|
+
await writeWebResponse(await handle(await toWebRequest(incoming)), outgoing);
|
|
340
|
+
})().catch((error) => {
|
|
341
|
+
outgoing.destroy(Error.isError(error) ? error : new Error(String(error)));
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
this.server = server;
|
|
345
|
+
server.listen(this.requestedPort);
|
|
346
|
+
await (0, node_events.once)(server, "listening");
|
|
347
|
+
this.boundPort = server.address().port;
|
|
348
|
+
this.logger.info(`Interactions server listening on port ${_seedcord_logger.paint.sky.bold(String(this.boundPort))}`);
|
|
349
|
+
this.shutdown.addTask(_seedcord_core_node_internal.ShutdownPhase.Unbind, "stop-http-server", () => this.stopServer(), SERVER_SHUTDOWN_TIMEOUT_MS);
|
|
350
|
+
this.shutdown.addTask(_seedcord_core_node_internal.ShutdownPhase.Drain, "drain-inflight", async () => {
|
|
351
|
+
await Promise.allSettled(inFlight);
|
|
352
|
+
}, DRAIN_TIMEOUT_MS);
|
|
353
|
+
}
|
|
354
|
+
async fetchUsername() {
|
|
355
|
+
try {
|
|
356
|
+
const me = await this.rest.get(discord_api_types_v10.Routes.user("@me"));
|
|
357
|
+
this.fetchedUsername = me.username;
|
|
358
|
+
} catch (caught) {
|
|
359
|
+
this.logger.warn("could not fetch the bot identity", caught);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
stopServer() {
|
|
363
|
+
const server = this.server;
|
|
364
|
+
if (!server?.listening) return Promise.resolve();
|
|
365
|
+
return new Promise((resolveClose, rejectClose) => {
|
|
366
|
+
server.close((err) => {
|
|
367
|
+
if (err) {
|
|
368
|
+
rejectClose(err);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
this.logger.info(_seedcord_logger.paint.coral.bold("Interactions server stopped"));
|
|
372
|
+
resolveClose();
|
|
373
|
+
});
|
|
374
|
+
server.closeIdleConnections();
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
//#endregion
|
|
3
380
|
//#region src/index.ts
|
|
4
|
-
|
|
5
|
-
|
|
381
|
+
var src_exports = /* @__PURE__ */ require_edge_index.__exportAll({
|
|
382
|
+
AutocompleteHandler: () => require_edge_index.AutocompleteHandler,
|
|
383
|
+
ButtonHandler: () => require_edge_index.ButtonHandler,
|
|
384
|
+
ComponentHandler: () => require_edge_index.ComponentHandler,
|
|
385
|
+
ContextMenuHandler: () => require_edge_index.ContextMenuHandler,
|
|
386
|
+
Gated: () => require_edge_index.Gated,
|
|
387
|
+
InteractionHandler: () => require_edge_index.InteractionHandler,
|
|
388
|
+
ModalHandler: () => require_edge_index.ModalHandler,
|
|
389
|
+
RepliableHandler: () => require_edge_index.RepliableHandler,
|
|
390
|
+
Seedcord: () => Seedcord,
|
|
391
|
+
SelectMenuHandler: () => require_edge_index.SelectMenuHandler,
|
|
392
|
+
SlashHandler: () => require_edge_index.SlashHandler,
|
|
393
|
+
createSeedcord: () => require_edge_index.createSeedcord,
|
|
394
|
+
version: () => require_edge_index.version
|
|
395
|
+
});
|
|
6
396
|
|
|
7
397
|
//#endregion
|
|
8
|
-
exports.
|
|
398
|
+
exports.AutocompleteHandler = require_edge_index.AutocompleteHandler;
|
|
399
|
+
exports.ButtonHandler = require_edge_index.ButtonHandler;
|
|
400
|
+
exports.ComponentHandler = require_edge_index.ComponentHandler;
|
|
401
|
+
exports.ContextMenuHandler = require_edge_index.ContextMenuHandler;
|
|
402
|
+
exports.Gated = require_edge_index.Gated;
|
|
403
|
+
exports.InteractionHandler = require_edge_index.InteractionHandler;
|
|
404
|
+
exports.ModalHandler = require_edge_index.ModalHandler;
|
|
405
|
+
exports.RepliableHandler = require_edge_index.RepliableHandler;
|
|
406
|
+
exports.Seedcord = Seedcord;
|
|
407
|
+
exports.SelectMenuHandler = require_edge_index.SelectMenuHandler;
|
|
408
|
+
exports.SlashHandler = require_edge_index.SlashHandler;
|
|
409
|
+
exports.createSeedcord = require_edge_index.createSeedcord;
|
|
410
|
+
exports.version = require_edge_index.version;
|
|
411
|
+
var _seedcord_core = require("@seedcord/core");
|
|
412
|
+
Object.keys(_seedcord_core).forEach(function (k) {
|
|
413
|
+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
414
|
+
enumerable: true,
|
|
415
|
+
get: function () { return _seedcord_core[k]; }
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
|
|
9
419
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["/** Package version */\nexport const version = process.env.PACKAGE_VERSION ?? '0.0.0';\n"],"mappings":";;;;AACA,MAAa"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["Logger","buildRouteMaps","Envapter","HmrModuleHandler","InteractionHandler","AutocompleteHandler","InteractionMetadataKey","InteractionRoutes","SeedcordError","SeedcordErrorCode","Pluggable","SeedcordBrand","packageVersion","REST","Logger","CoordinatedShutdown","CoordinatedStartup","HmrManager","MemoryRateLimiter","HealthCheck","Envapter","StartupPhase","buildRouteMaps","buildEngine","paint","ShutdownPhase","Routes"],"sources":["../src/manifest/RouteManifest.ts","../src/node/InteractionDispatcher.ts","../src/node/webBridge.ts","../src/node/Seedcord.ts","../src/index.ts"],"sourcesContent":["import type { SelectMenuKind } from '@seedcord/core';\nimport type { ApplicationCommandType } from 'discord-api-types/v10';\n\n/** The command kinds a manifest row registers, the wire enum's other members have no handler base. */\ntype RegistrableCommandType =\n | ApplicationCommandType.ChatInput\n | ApplicationCommandType.User\n | ApplicationCommandType.Message;\n\n/**\n * A slash or context-menu command row. `type` picks the per-kind map, `name` is the lookup key. For a\n * chat-input command with subcommands, `name` is the full route path (`'config/set'`), the same key\n * `@SlashRoute` registers.\n */\ninterface CommandRoute {\n readonly name: string;\n readonly type: RegistrableCommandType;\n /** Lazy import of the handler module, evaluated on first hit. */\n readonly load: () => Promise<unknown>;\n}\n\n/**\n * A button, select, or modal row. `kind` picks the per-kind map, `prefix` is the stable customId prefix\n * the receiver routes by (the routeKey minus its layout hash).\n */\nexport interface ComponentRoute {\n readonly kind: 'button' | `${SelectMenuKind}Select` | 'modal';\n readonly prefix: string;\n /** Lazy import of the handler module, evaluated on first hit. */\n readonly load: () => Promise<unknown>;\n}\n\n/**\n * An autocomplete row, its own route keyed by the command's route path, separate from the slash row.\n */\ninterface AutocompleteRoute {\n readonly name: string;\n /** Lazy import of the handler module, evaluated on first hit. */\n readonly load: () => Promise<unknown>;\n}\n\n/**\n * A bus subscriber row. The Bus routes off it without importing the subscriber module. The HTTP engine\n * ignores these rows until the Bus ships on this transport.\n */\ninterface SubscriberRoute {\n /** The subscription keys this subscriber registers for. */\n readonly keys: readonly string[];\n /** Mirrors the `@Subscribe` frequency metadata. */\n readonly frequency: 'on' | 'once';\n /** Lazy import of the subscriber module. */\n readonly load: () => Promise<unknown>;\n}\n\n/**\n * The static route table the HTTP engine dispatches through, replacing the filesystem handler scan that\n * cannot run in a bundled isolate. `seedcord build` emits it, the mount path authors it by hand.\n */\nexport interface RouteManifest {\n readonly commands: readonly CommandRoute[];\n readonly components: readonly ComponentRoute[];\n readonly autocomplete: readonly AutocompleteRoute[];\n readonly subscribers: readonly SubscriberRoute[];\n}\n\n/** @internal */\nexport const EMPTY_MANIFEST: RouteManifest = { commands: [], components: [], autocomplete: [], subscribers: [] };\n","import { HmrModuleHandler } from '@seedcord/core/hmr';\nimport { interactionRoutesOf, InteractionMetadataKey, InteractionRoutes } from '@seedcord/core/internal';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\nimport { Logger } from '@seedcord/logger';\nimport { formatFilePath } from '@seedcord/utils';\nimport { traverseDirectory } from '@seedcord/utils/node';\nimport { Envapter } from 'envapt';\n\nimport { AutocompleteHandler } from '@handlers/interaction/AutocompleteHandler';\nimport { InteractionHandler } from '@handlers/interaction/InteractionHandler';\nimport { buildRouteMaps } from '@src/dispatch/resolve';\nimport { EMPTY_MANIFEST } from '@src/manifest/RouteManifest';\n\nimport type { HandlerConstructor } from '@handlers/constructors';\nimport type { Initializeable } from '@seedcord/core';\nimport type { HmrAware, HmrUpdateEvent } from '@seedcord/types';\nimport type { ResolvedRoute, RouteMap, RouteMaps } from '@src/dispatch/resolve';\n\ninterface RouteTarget {\n readonly map: RouteMap;\n readonly kind: ResolvedRoute['kind'];\n}\n\n/**\n * Discovers interaction handlers from the filesystem into the engine's live route maps.\n *\n * The node host runs it at startup and dev HMR swaps map entries in place. The engine's `resolve`\n * reads `maps` per request. The edge path builds its maps from the generated manifest.\n */\nexport class InteractionDispatcher implements Initializeable, HmrAware {\n public readonly maps: RouteMaps;\n private readonly targets: Record<InteractionRoutes, RouteTarget>;\n\n /** @internal */\n public readonly logger = new Logger('Interactions');\n\n private isInitialized = false;\n private readonly hmrHandler?: HmrModuleHandler<HandlerConstructor, void, string[]>;\n // routeId -> owner row, the duplicate guard and the hmr unregister index\n private readonly rowOwners = new Map<string, { ctor: HandlerConstructor; target: RouteTarget; key: string }>();\n\n private loading = false;\n private readonly loadedHandlers: { name: string; from: string }[] = [];\n\n constructor(private readonly handlersDir: string) {\n this.maps = buildRouteMaps(EMPTY_MANIFEST);\n this.targets = this.buildTargets();\n\n if (!Envapter.isDevelopment && !Envapter.isTest) return;\n this.hmrHandler = new HmrModuleHandler({\n handlersDir,\n isHandler: this.isHandler.bind(this),\n registerHandler: this.registerHandler.bind(this),\n unregisterHandler: this.unregisterHandler.bind(this),\n getArtifacts: this.getArtifacts.bind(this),\n logger: this.logger\n });\n }\n\n /** @internal */\n public async init(): Promise<void> {\n if (this.isInitialized) return;\n this.isInitialized = true;\n\n this.loading = true;\n this.loadedHandlers.length = 0;\n try {\n await traverseDirectory(\n this.handlersDir,\n (fullPath, relativePath, imported) => {\n for (const value of Object.values(imported)) {\n if (!this.isHandler(value)) continue;\n this.registerHandler(value, relativePath);\n this.hmrHandler?.trackHandler(fullPath, value);\n }\n },\n this.logger\n );\n } finally {\n this.loading = false;\n }\n\n this.logger.utils.block('Loaded handlers', [\n ...this.logger.utils.entries(this.loadedHandlers),\n ...this.logger.utils.counts({ routes: this.rowOwners.size })\n ]);\n }\n\n /** @internal */\n public async onHmr(event: HmrUpdateEvent): Promise<void> {\n await this.hmrHandler?.handle(event);\n }\n\n private isHandler(value: unknown): value is HandlerConstructor {\n if (typeof value !== 'function') return false;\n // this package's own family bases. A gateway handler in the same dir stays unregistered\n return (\n (value.prototype instanceof InteractionHandler || value.prototype instanceof AutocompleteHandler) &&\n Reflect.hasMetadata(InteractionMetadataKey, value)\n );\n }\n\n private getArtifacts(ctor: HandlerConstructor): string[] {\n const routeIds: string[] = [];\n for (const [routeId, owner] of this.rowOwners) {\n if (owner.ctor === ctor) routeIds.push(routeId);\n }\n return routeIds;\n }\n\n private targetFor(route: InteractionRoutes): RouteTarget {\n return this.targets[route];\n }\n\n private buildTargets(): Record<InteractionRoutes, RouteTarget> {\n return {\n [InteractionRoutes.Slash]: { map: this.maps.slash, kind: 'slash' },\n [InteractionRoutes.UserContextMenu]: { map: this.maps.userContextMenu, kind: 'userContextMenu' },\n [InteractionRoutes.MessageContextMenu]: { map: this.maps.messageContextMenu, kind: 'messageContextMenu' },\n [InteractionRoutes.Autocomplete]: { map: this.maps.autocomplete, kind: 'autocomplete' },\n [InteractionRoutes.Button]: { map: this.maps.components.button, kind: 'button' },\n [InteractionRoutes.StringMenu]: { map: this.maps.components.stringSelect, kind: 'stringMenu' },\n [InteractionRoutes.UserMenu]: { map: this.maps.components.userSelect, kind: 'userMenu' },\n [InteractionRoutes.RoleMenu]: { map: this.maps.components.roleSelect, kind: 'roleMenu' },\n [InteractionRoutes.ChannelMenu]: { map: this.maps.components.channelSelect, kind: 'channelMenu' },\n [InteractionRoutes.MentionableMenu]: {\n map: this.maps.components.mentionableSelect,\n kind: 'mentionableMenu'\n },\n [InteractionRoutes.Modal]: { map: this.maps.components.modal, kind: 'modal' }\n };\n }\n\n private registerHandler(ctor: HandlerConstructor, relativePath: string): void {\n // a partial registration would orphan routes and break hmr rollback\n const writes: [RouteTarget, string][] = [];\n\n for (const [route, keys] of interactionRoutesOf(ctor)) {\n const target = this.targetFor(route);\n for (const key of keys) {\n const existing = this.rowOwners.get(`${target.kind}:${key}`);\n // a different class on the same route would silently shadow (last write wins), so this throws\n if (existing && existing.ctor !== ctor) {\n throw new SeedcordError(SeedcordErrorCode.InteractionDuplicateRoute, [\n key,\n existing.ctor.name,\n ctor.name\n ]);\n }\n writes.push([target, key]);\n }\n }\n\n if (writes.length === 0) return;\n for (const [target, key] of writes) {\n const routeId = `${target.kind}:${key}`;\n // a one-export module, the dispatch first-handler scan resolves exactly this row's class\n target.map.set(key, { kind: target.kind, routeId, load: () => Promise.resolve({ [ctor.name]: ctor }) });\n this.rowOwners.set(routeId, { ctor, target, key });\n }\n\n const from = formatFilePath(relativePath);\n if (this.loading) this.loadedHandlers.push({ name: ctor.name, from });\n else this.logger.utils.registration(ctor.name, from);\n }\n\n private unregisterHandler(ctor: HandlerConstructor, artifacts?: string[]): void {\n const routeIds = artifacts ?? this.getArtifacts(ctor);\n for (const routeId of routeIds) {\n const owner = this.rowOwners.get(routeId);\n if (owner?.ctor !== ctor) continue;\n this.rowOwners.delete(routeId);\n owner.target.map.delete(owner.key);\n }\n }\n}\n","import type { IncomingHttpHeaders, IncomingMessage, ServerResponse } from 'node:http';\n\nfunction toHeaders(raw: IncomingHttpHeaders): Headers {\n const headers = new Headers();\n for (const [name, value] of Object.entries(raw)) {\n if (value === undefined) continue;\n if (Array.isArray(value)) {\n for (const item of value) headers.append(name, item);\n } else {\n headers.set(name, value);\n }\n }\n return headers;\n}\n\n// buffers the raw body before any parse so ed25519 verifies the exact signed bytes\nexport async function toWebRequest(request: IncomingMessage): Promise<Request> {\n const chunks: Buffer[] = [];\n // justified: the async iterator is typed any and IncomingMessage yields Buffer chunks\n for await (const chunk of request) chunks.push(chunk as Buffer);\n\n const method = request.method ?? 'GET';\n const body = method === 'GET' || method === 'HEAD' ? undefined : new Uint8Array(Buffer.concat(chunks));\n\n return new Request(`http://${request.headers.host ?? 'localhost'}${request.url ?? '/'}`, {\n method,\n headers: toHeaders(request.headers),\n ...(body !== undefined && { body })\n });\n}\n\nexport async function writeWebResponse(response: Response, out: ServerResponse): Promise<void> {\n const headers: Record<string, string | string[]> = Object.fromEntries(response.headers);\n // iterating Headers comma-joins same-name values, which corrupts Set-Cookie (a per-cookie header)\n const cookies = response.headers.getSetCookie();\n if (cookies.length > 0) headers['set-cookie'] = cookies;\n\n out.writeHead(response.status, headers);\n out.end(response.body === null ? undefined : Buffer.from(await response.arrayBuffer()));\n}\n","import { once } from 'node:events';\nimport { createServer } from 'node:http';\n\nimport { REST } from '@discordjs/rest';\nimport { HmrManager, setBotColor } from '@seedcord/core/internal';\nimport {\n CoordinatedShutdown,\n CoordinatedStartup,\n HealthCheck,\n Pluggable,\n ShutdownPhase,\n StartupPhase\n} from '@seedcord/core/node/internal';\nimport { validateDiscordToken } from '@seedcord/errors/internal';\nimport { Logger, LoggerChannelRegistry, paint } from '@seedcord/logger';\nimport { installNodeDefaults } from '@seedcord/logger/node';\nimport { MemoryRateLimiter } from '@seedcord/rate-limiter';\nimport { SeedcordBrand } from '@seedcord/types/internal';\nimport { Routes } from 'discord-api-types/v10';\nimport { Envapter } from 'envapt';\n\nimport { buildRouteMaps } from '@src/dispatch/resolve';\nimport { buildEngine } from '@src/engine';\nimport { EMPTY_MANIFEST } from '@src/manifest/RouteManifest';\n\nimport { InteractionDispatcher } from './InteractionDispatcher';\nimport { toWebRequest, writeWebResponse } from './webBridge';\nimport { version as packageVersion } from '../version';\n\nimport type { HttpConfig } from '@interfaces/Config';\nimport type { Core } from '@interfaces/Core';\nimport type { PluginCapabilities } from '@seedcord/core/node/internal';\nimport type { IRateLimiter } from '@seedcord/types';\nimport type { Server } from 'node:http';\nimport type { AddressInfo } from 'node:net';\n\nconst DEFAULT_PORT = 3000;\nconst SERVER_SHUTDOWN_TIMEOUT_MS = 5000;\nconst DRAIN_TIMEOUT_MS = 10_000;\n\n/**\n * The HTTP-interactions bot host, a long-running node server around the engine.\n *\n * Discovers handlers from `config.bot.interactions.path`, verifies and dispatches interactions on\n * `start(port)`, and runs coordinated shutdown with an in-flight drain. The edge deploy path calls\n * `createSeedcord` from a generated entry.\n */\nexport class Seedcord extends Pluggable implements Core {\n // the CLI reads these to detect and augment the instance\n /** @internal */\n public readonly [SeedcordBrand] = true;\n /** @internal */\n public readonly augmentTarget = '@seedcord/http';\n /** @internal */\n public readonly version: string = packageVersion;\n\n /** Workerd-compatible Discord REST client. `start()` sets the token. */\n public readonly rest = new REST();\n\n /** @see {@link IRateLimiter} */\n public readonly rateLimiter: IRateLimiter;\n\n /** @see {@link CoordinatedShutdown} */\n public override readonly shutdown: CoordinatedShutdown;\n\n /** @see {@link CoordinatedStartup} */\n public override readonly startup: CoordinatedStartup;\n\n private readonly interactions?: InteractionDispatcher;\n private readonly healthCheck?: HealthCheck | undefined;\n private readonly hmrManager: HmrManager;\n private readonly logger = new Logger('Server');\n\n private server?: Server;\n private boundPort?: number;\n private requestedPort = DEFAULT_PORT;\n private fetchedUsername?: string | undefined;\n\n constructor(public readonly config: HttpConfig) {\n const shutdown = new CoordinatedShutdown();\n const startup = new CoordinatedStartup();\n\n super(shutdown, startup);\n\n installNodeDefaults(config.logger);\n setBotColor(config.botColor);\n\n this.shutdown = shutdown;\n this.startup = startup;\n\n this.hmrManager = new HmrManager();\n this.hmrManager.init();\n\n if (this.config.bot.interactions.path) {\n this.interactions = new InteractionDispatcher(this.config.bot.interactions.path);\n }\n\n this.rateLimiter = config.store ?? new MemoryRateLimiter();\n // the edge arm types healthCheck never, and a dev run of an edge config needs no health server\n this.healthCheck =\n config.runtime === 'edge' ? undefined : HealthCheck.fromOption(this.shutdown, config.healthCheck);\n\n this.registerStartupTasks();\n }\n\n /** The bot's discord username, populated by the ready fetch. */\n public get username(): string | undefined {\n return this.fetchedUsername;\n }\n\n /** The bound server port, populated once `start()` is listening. */\n public get port(): number | undefined {\n return this.boundPort;\n }\n\n protected override pluginCapabilities(): PluginCapabilities {\n const token = Envapter.get('DISCORD_BOT_TOKEN');\n return { rest: this.rest, ...(token !== undefined && { token }) };\n }\n\n /**\n * Starts the host and runs the startup tasks.\n *\n * @param port - The port the interaction server binds. {@default `3000`}\n */\n public async start(port = DEFAULT_PORT): Promise<this> {\n this.requestedPort = port;\n try {\n await super.init();\n } catch (caught) {\n // shutdown releases any resource opened before the failure, then rethrow\n await this.shutdown.run(1, false);\n Seedcord.reset();\n throw caught;\n }\n return this;\n }\n\n protected static override reset(): void {\n super.reset();\n LoggerChannelRegistry.instance.reset();\n }\n\n private registerStartupTasks(): void {\n if (Envapter.isDevelopment || Envapter.isTest) this.registerHmrAwareModules();\n\n const { interactions } = this;\n if (interactions) {\n this.startup.addTask(StartupPhase.Configuration, 'Interactions Initialization', async () => {\n interactions.logger.utils.initialization('Interactions', 'start');\n await interactions.init();\n interactions.logger.utils.initialization('Interactions', 'end');\n });\n }\n\n this.startup.addTask(StartupPhase.Ready, 'Http Server', () => this.listen());\n\n if (!Envapter.isTest) {\n this.startup.addTask(StartupPhase.Ready, 'Identity', () => this.fetchUsername());\n }\n\n const { healthCheck } = this;\n if (healthCheck) {\n this.startup.addTask(StartupPhase.Ready, 'Health Check', async () => {\n healthCheck.logger.utils.initialization('HealthCheck', 'start');\n await healthCheck.init();\n healthCheck.logger.utils.initialization('HealthCheck', 'end');\n });\n }\n }\n\n private registerHmrAwareModules(): void {\n this.startup.addTask(StartupPhase.Configuration, 'HMR Registration', async () => {\n if (this.interactions) this.hmrManager.register(this.interactions);\n for (const plugin of this.plugins) {\n this.hmrManager.register(plugin);\n }\n await Promise.resolve();\n });\n }\n\n private async listen(): Promise<void> {\n const token = validateDiscordToken(Envapter.get('DISCORD_BOT_TOKEN'));\n this.rest.setToken(token);\n\n const maps = this.interactions?.maps ?? buildRouteMaps(EMPTY_MANIFEST);\n const { handle, inFlight } = buildEngine(this, maps);\n\n const server = createServer((incoming, outgoing) => {\n void (async () => {\n const response = await handle(await toWebRequest(incoming));\n await writeWebResponse(response, outgoing);\n })().catch((error: unknown) => {\n // a swallowed throw would hang the client request with no cause\n outgoing.destroy(Error.isError(error) ? error : new Error(String(error)));\n });\n });\n this.server = server;\n\n server.listen(this.requestedPort);\n await once(server, 'listening');\n // justified: address() is AddressInfo once a TCP server is listening\n this.boundPort = (server.address() as AddressInfo).port;\n this.logger.info(`Interactions server listening on port ${paint.sky.bold(String(this.boundPort))}`);\n\n this.shutdown.addTask(\n ShutdownPhase.Unbind,\n 'stop-http-server',\n () => this.stopServer(),\n SERVER_SHUTDOWN_TIMEOUT_MS\n );\n // Unbind already ran, so every accepted request is in the in-flight set here\n this.shutdown.addTask(\n ShutdownPhase.Drain,\n 'drain-inflight',\n async () => {\n await Promise.allSettled(inFlight);\n },\n DRAIN_TIMEOUT_MS\n );\n }\n\n private async fetchUsername(): Promise<void> {\n try {\n // justified: the @me payload carries username per the discord api contract\n const me = (await this.rest.get(Routes.user('@me'))) as { username?: string };\n this.fetchedUsername = me.username;\n } catch (caught) {\n // a bad token errors on the first real send. The identity fetch stays non-fatal\n this.logger.warn('could not fetch the bot identity', caught);\n }\n }\n\n private stopServer(): Promise<void> {\n const server = this.server;\n if (!server?.listening) return Promise.resolve();\n\n return new Promise((resolveClose, rejectClose) => {\n server.close((err) => {\n if (err) {\n rejectClose(err);\n return;\n }\n this.logger.info(paint.coral.bold('Interactions server stopped'));\n resolveClose();\n });\n // idle keep-alive sockets would stall close() past the task timeout. Active responses\n // still flush, and the task timeout bounds a hung one\n server.closeIdleConnections();\n });\n }\n}\n","export * from './edge.index';\nexport { Seedcord } from '@src/node/Seedcord';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAkEA,MAAa,iBAAgC;CAAE,UAAU,CAAC;CAAG,YAAY,CAAC;CAAG,cAAc,CAAC;CAAG,aAAa,CAAC;AAAE;;;;;;;;;;ACpC/G,IAAa,wBAAb,MAAuE;CAetC;CAd7B,AAAgB;CAChB,AAAiB;;CAGjB,AAAgB,SAAS,IAAIA,wBAAO,cAAc;CAElD,AAAQ,gBAAgB;CACxB,AAAiB;CAEjB,AAAiB,4BAAY,IAAI,IAA4E;CAE7G,AAAQ,UAAU;CAClB,AAAiB,iBAAmD,CAAC;CAErE,YAAY,AAAiB,aAAqB;EAArB;EACzB,KAAK,OAAOC,kCAAe,cAAc;EACzC,KAAK,UAAU,KAAK,aAAa;EAEjC,IAAI,CAACC,gBAAS,iBAAiB,CAACA,gBAAS,QAAQ;EACjD,KAAK,aAAa,IAAIC,oCAAiB;GACnC;GACA,WAAW,KAAK,UAAU,KAAK,IAAI;GACnC,iBAAiB,KAAK,gBAAgB,KAAK,IAAI;GAC/C,mBAAmB,KAAK,kBAAkB,KAAK,IAAI;GACnD,cAAc,KAAK,aAAa,KAAK,IAAI;GACzC,QAAQ,KAAK;EACjB,CAAC;CACL;;CAGA,MAAa,OAAsB;EAC/B,IAAI,KAAK,eAAe;EACxB,KAAK,gBAAgB;EAErB,KAAK,UAAU;EACf,KAAK,eAAe,SAAS;EAC7B,IAAI;GACA,kDACI,KAAK,cACJ,UAAU,cAAc,aAAa;IAClC,KAAK,MAAM,SAAS,OAAO,OAAO,QAAQ,GAAG;KACzC,IAAI,CAAC,KAAK,UAAU,KAAK,GAAG;KAC5B,KAAK,gBAAgB,OAAO,YAAY;KACxC,KAAK,YAAY,aAAa,UAAU,KAAK;IACjD;GACJ,GACA,KAAK,MACT;EACJ,UAAU;GACN,KAAK,UAAU;EACnB;EAEA,KAAK,OAAO,MAAM,MAAM,mBAAmB,CACvC,GAAG,KAAK,OAAO,MAAM,QAAQ,KAAK,cAAc,GAChD,GAAG,KAAK,OAAO,MAAM,OAAO,EAAE,QAAQ,KAAK,UAAU,KAAK,CAAC,CAC/D,CAAC;CACL;;CAGA,MAAa,MAAM,OAAsC;EACrD,MAAM,KAAK,YAAY,OAAO,KAAK;CACvC;CAEA,AAAQ,UAAU,OAA6C;EAC3D,IAAI,OAAO,UAAU,YAAY,OAAO;EAExC,QACK,MAAM,qBAAqBC,yCAAsB,MAAM,qBAAqBC,2CAC7E,QAAQ,YAAYC,gDAAwB,KAAK;CAEzD;CAEA,AAAQ,aAAa,MAAoC;EACrD,MAAM,WAAqB,CAAC;EAC5B,KAAK,MAAM,CAAC,SAAS,UAAU,KAAK,WAChC,IAAI,MAAM,SAAS,MAAM,SAAS,KAAK,OAAO;EAElD,OAAO;CACX;CAEA,AAAQ,UAAU,OAAuC;EACrD,OAAO,KAAK,QAAQ;CACxB;CAEA,AAAQ,eAAuD;EAC3D,OAAO;IACFC,0CAAkB,QAAQ;IAAE,KAAK,KAAK,KAAK;IAAO,MAAM;GAAQ;IAChEA,0CAAkB,kBAAkB;IAAE,KAAK,KAAK,KAAK;IAAiB,MAAM;GAAkB;IAC9FA,0CAAkB,qBAAqB;IAAE,KAAK,KAAK,KAAK;IAAoB,MAAM;GAAqB;IACvGA,0CAAkB,eAAe;IAAE,KAAK,KAAK,KAAK;IAAc,MAAM;GAAe;IACrFA,0CAAkB,SAAS;IAAE,KAAK,KAAK,KAAK,WAAW;IAAQ,MAAM;GAAS;IAC9EA,0CAAkB,aAAa;IAAE,KAAK,KAAK,KAAK,WAAW;IAAc,MAAM;GAAa;IAC5FA,0CAAkB,WAAW;IAAE,KAAK,KAAK,KAAK,WAAW;IAAY,MAAM;GAAW;IACtFA,0CAAkB,WAAW;IAAE,KAAK,KAAK,KAAK,WAAW;IAAY,MAAM;GAAW;IACtFA,0CAAkB,cAAc;IAAE,KAAK,KAAK,KAAK,WAAW;IAAe,MAAM;GAAc;IAC/FA,0CAAkB,kBAAkB;IACjC,KAAK,KAAK,KAAK,WAAW;IAC1B,MAAM;GACV;IACCA,0CAAkB,QAAQ;IAAE,KAAK,KAAK,KAAK,WAAW;IAAO,MAAM;GAAQ;EAChF;CACJ;CAEA,AAAQ,gBAAgB,MAA0B,cAA4B;EAE1E,MAAM,SAAkC,CAAC;EAEzC,KAAK,MAAM,CAAC,OAAO,0DAA6B,IAAI,GAAG;GACnD,MAAM,SAAS,KAAK,UAAU,KAAK;GACnC,KAAK,MAAM,OAAO,MAAM;IACpB,MAAM,WAAW,KAAK,UAAU,IAAI,GAAG,OAAO,KAAK,GAAG,KAAK;IAE3D,IAAI,YAAY,SAAS,SAAS,MAC9B,MAAM,IAAIC,wCAAcC,mCAAkB,2BAA2B;KACjE;KACA,SAAS,KAAK;KACd,KAAK;IACT,CAAC;IAEL,OAAO,KAAK,CAAC,QAAQ,GAAG,CAAC;GAC7B;EACJ;EAEA,IAAI,OAAO,WAAW,GAAG;EACzB,KAAK,MAAM,CAAC,QAAQ,QAAQ,QAAQ;GAChC,MAAM,UAAU,GAAG,OAAO,KAAK,GAAG;GAElC,OAAO,IAAI,IAAI,KAAK;IAAE,MAAM,OAAO;IAAM;IAAS,YAAY,QAAQ,QAAQ,GAAG,KAAK,OAAO,KAAK,CAAC;GAAE,CAAC;GACtG,KAAK,UAAU,IAAI,SAAS;IAAE;IAAM;IAAQ;GAAI,CAAC;EACrD;EAEA,MAAM,2CAAsB,YAAY;EACxC,IAAI,KAAK,SAAS,KAAK,eAAe,KAAK;GAAE,MAAM,KAAK;GAAM;EAAK,CAAC;OAC/D,KAAK,OAAO,MAAM,aAAa,KAAK,MAAM,IAAI;CACvD;CAEA,AAAQ,kBAAkB,MAA0B,WAA4B;EAC5E,MAAM,WAAW,aAAa,KAAK,aAAa,IAAI;EACpD,KAAK,MAAM,WAAW,UAAU;GAC5B,MAAM,QAAQ,KAAK,UAAU,IAAI,OAAO;GACxC,IAAI,OAAO,SAAS,MAAM;GAC1B,KAAK,UAAU,OAAO,OAAO;GAC7B,MAAM,OAAO,IAAI,OAAO,MAAM,GAAG;EACrC;CACJ;AACJ;;;;AC9KA,SAAS,UAAU,KAAmC;CAClD,MAAM,UAAU,IAAI,QAAQ;CAC5B,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,GAAG,GAAG;EAC7C,IAAI,UAAU,QAAW;EACzB,IAAI,MAAM,QAAQ,KAAK,GACnB,KAAK,MAAM,QAAQ,OAAO,QAAQ,OAAO,MAAM,IAAI;OAEnD,QAAQ,IAAI,MAAM,KAAK;CAE/B;CACA,OAAO;AACX;AAGA,eAAsB,aAAa,SAA4C;CAC3E,MAAM,SAAmB,CAAC;CAE1B,WAAW,MAAM,SAAS,SAAS,OAAO,KAAK,KAAe;CAE9D,MAAM,SAAS,QAAQ,UAAU;CACjC,MAAM,OAAO,WAAW,SAAS,WAAW,SAAS,SAAY,IAAI,WAAW,OAAO,OAAO,MAAM,CAAC;CAErG,OAAO,IAAI,QAAQ,UAAU,QAAQ,QAAQ,QAAQ,cAAc,QAAQ,OAAO,OAAO;EACrF;EACA,SAAS,UAAU,QAAQ,OAAO;EAClC,GAAI,SAAS,UAAa,EAAE,KAAK;CACrC,CAAC;AACL;AAEA,eAAsB,iBAAiB,UAAoB,KAAoC;CAC3F,MAAM,UAA6C,OAAO,YAAY,SAAS,OAAO;CAEtF,MAAM,UAAU,SAAS,QAAQ,aAAa;CAC9C,IAAI,QAAQ,SAAS,GAAG,QAAQ,gBAAgB;CAEhD,IAAI,UAAU,SAAS,QAAQ,OAAO;CACtC,IAAI,IAAI,SAAS,SAAS,OAAO,SAAY,OAAO,KAAK,MAAM,SAAS,YAAY,CAAC,CAAC;AAC1F;;;;ACHA,MAAM,eAAe;AACrB,MAAM,6BAA6B;AACnC,MAAM,mBAAmB;;;;;;;;AASzB,IAAa,WAAb,MAAa,iBAAiBC,uCAA0B;CA+BxB;;CA5B5B,CAAiBC,0CAAiB;;CAElC,AAAgB,gBAAgB;;CAEhC,AAAgB,UAAkBC;;CAGlC,AAAgB,OAAO,IAAIC,qBAAK;;CAGhC,AAAgB;;CAGhB,AAAyB;;CAGzB,AAAyB;CAEzB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CACjB,AAAiB,SAAS,IAAIC,wBAAO,QAAQ;CAE7C,AAAQ;CACR,AAAQ;CACR,AAAQ,gBAAgB;CACxB,AAAQ;CAER,YAAY,AAAgB,QAAoB;EAC5C,MAAM,WAAW,IAAIC,iDAAoB;EACzC,MAAM,UAAU,IAAIC,gDAAmB;EAEvC,MAAM,UAAU,OAAO;EAJC;EAMxB,+CAAoB,OAAO,MAAM;EACjC,yCAAY,OAAO,QAAQ;EAE3B,KAAK,WAAW;EAChB,KAAK,UAAU;EAEf,KAAK,aAAa,IAAIC,mCAAW;EACjC,KAAK,WAAW,KAAK;EAErB,IAAI,KAAK,OAAO,IAAI,aAAa,MAC7B,KAAK,eAAe,IAAI,sBAAsB,KAAK,OAAO,IAAI,aAAa,IAAI;EAGnF,KAAK,cAAc,OAAO,SAAS,IAAIC,yCAAkB;EAEzD,KAAK,cACD,OAAO,YAAY,SAAS,SAAYC,yCAAY,WAAW,KAAK,UAAU,OAAO,WAAW;EAEpG,KAAK,qBAAqB;CAC9B;;CAGA,IAAW,WAA+B;EACtC,OAAO,KAAK;CAChB;;CAGA,IAAW,OAA2B;EAClC,OAAO,KAAK;CAChB;CAEA,AAAmB,qBAAyC;EACxD,MAAM,QAAQC,gBAAS,IAAI,mBAAmB;EAC9C,OAAO;GAAE,MAAM,KAAK;GAAM,GAAI,UAAU,UAAa,EAAE,MAAM;EAAG;CACpE;;;;;;CAOA,MAAa,MAAM,OAAO,cAA6B;EACnD,KAAK,gBAAgB;EACrB,IAAI;GACA,MAAM,MAAM,KAAK;EACrB,SAAS,QAAQ;GAEb,MAAM,KAAK,SAAS,IAAI,GAAG,KAAK;GAChC,SAAS,MAAM;GACf,MAAM;EACV;EACA,OAAO;CACX;CAEA,OAA0B,QAAc;EACpC,MAAM,MAAM;EACZ,uCAAsB,SAAS,MAAM;CACzC;CAEA,AAAQ,uBAA6B;EACjC,IAAIA,gBAAS,iBAAiBA,gBAAS,QAAQ,KAAK,wBAAwB;EAE5E,MAAM,EAAE,iBAAiB;EACzB,IAAI,cACA,KAAK,QAAQ,QAAQC,0CAAa,eAAe,+BAA+B,YAAY;GACxF,aAAa,OAAO,MAAM,eAAe,gBAAgB,OAAO;GAChE,MAAM,aAAa,KAAK;GACxB,aAAa,OAAO,MAAM,eAAe,gBAAgB,KAAK;EAClE,CAAC;EAGL,KAAK,QAAQ,QAAQA,0CAAa,OAAO,qBAAqB,KAAK,OAAO,CAAC;EAE3E,IAAI,CAACD,gBAAS,QACV,KAAK,QAAQ,QAAQC,0CAAa,OAAO,kBAAkB,KAAK,cAAc,CAAC;EAGnF,MAAM,EAAE,gBAAgB;EACxB,IAAI,aACA,KAAK,QAAQ,QAAQA,0CAAa,OAAO,gBAAgB,YAAY;GACjE,YAAY,OAAO,MAAM,eAAe,eAAe,OAAO;GAC9D,MAAM,YAAY,KAAK;GACvB,YAAY,OAAO,MAAM,eAAe,eAAe,KAAK;EAChE,CAAC;CAET;CAEA,AAAQ,0BAAgC;EACpC,KAAK,QAAQ,QAAQA,0CAAa,eAAe,oBAAoB,YAAY;GAC7E,IAAI,KAAK,cAAc,KAAK,WAAW,SAAS,KAAK,YAAY;GACjE,KAAK,MAAM,UAAU,KAAK,SACtB,KAAK,WAAW,SAAS,MAAM;GAEnC,MAAM,QAAQ,QAAQ;EAC1B,CAAC;CACL;CAEA,MAAc,SAAwB;EAClC,MAAM,4DAA6BD,gBAAS,IAAI,mBAAmB,CAAC;EACpE,KAAK,KAAK,SAAS,KAAK;EAExB,MAAM,OAAO,KAAK,cAAc,QAAQE,kCAAe,cAAc;EACrE,MAAM,EAAE,QAAQ,aAAaC,+BAAY,MAAM,IAAI;EAEnD,MAAM,sCAAuB,UAAU,aAAa;GAChD,CAAM,YAAY;IAEd,MAAM,iBAAiB,MADA,OAAO,MAAM,aAAa,QAAQ,CAAC,GACzB,QAAQ;GAC7C,EAAC,CAAE,CAAC,CAAC,OAAO,UAAmB;IAE3B,SAAS,QAAQ,MAAM,QAAQ,KAAK,IAAI,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;GAC5E,CAAC;EACL,CAAC;EACD,KAAK,SAAS;EAEd,OAAO,OAAO,KAAK,aAAa;EAChC,4BAAW,QAAQ,WAAW;EAE9B,KAAK,YAAa,OAAO,QAAQ,CAAC,CAAiB;EACnD,KAAK,OAAO,KAAK,yCAAyCC,uBAAM,IAAI,KAAK,OAAO,KAAK,SAAS,CAAC,GAAG;EAElG,KAAK,SAAS,QACVC,2CAAc,QACd,0BACM,KAAK,WAAW,GACtB,0BACJ;EAEA,KAAK,SAAS,QACVA,2CAAc,OACd,kBACA,YAAY;GACR,MAAM,QAAQ,WAAW,QAAQ;EACrC,GACA,gBACJ;CACJ;CAEA,MAAc,gBAA+B;EACzC,IAAI;GAEA,MAAM,KAAM,MAAM,KAAK,KAAK,IAAIC,6BAAO,KAAK,KAAK,CAAC;GAClD,KAAK,kBAAkB,GAAG;EAC9B,SAAS,QAAQ;GAEb,KAAK,OAAO,KAAK,oCAAoC,MAAM;EAC/D;CACJ;CAEA,AAAQ,aAA4B;EAChC,MAAM,SAAS,KAAK;EACpB,IAAI,CAAC,QAAQ,WAAW,OAAO,QAAQ,QAAQ;EAE/C,OAAO,IAAI,SAAS,cAAc,gBAAgB;GAC9C,OAAO,OAAO,QAAQ;IAClB,IAAI,KAAK;KACL,YAAY,GAAG;KACf;IACJ;IACA,KAAK,OAAO,KAAKF,uBAAM,MAAM,KAAK,6BAA6B,CAAC;IAChE,aAAa;GACjB,CAAC;GAGD,OAAO,qBAAqB;EAChC,CAAC;CACL;AACJ"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,65 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { _ as createSeedcord, a as SelectMenuHandler, c as AutocompleteHandler, d as InteractionHandler, f as RepliableHandler, g as HttpServerConfig, h as HttpEdgeConfig, i as ModalHandler, l as ContextMenuHandler, m as HttpConfig, n as Gated, o as ButtonHandler, p as SlashOptions, r as InteractionGateContext, s as ComponentHandler, t as version, u as SlashHandler, v as EngineContext, y as Core } from "./edge.index-CTOyjsO4.mjs";
|
|
2
|
+
import { t as RouteManifest } from "./RouteManifest-BHdAeyLG.mjs";
|
|
3
|
+
import { REST } from "@discordjs/rest";
|
|
4
|
+
import { CoordinatedShutdown, CoordinatedStartup, Pluggable, PluginCapabilities } from "@seedcord/core/node/internal";
|
|
5
|
+
import { SeedcordBrand } from "@seedcord/types/internal";
|
|
6
|
+
import { IRateLimiter } from "@seedcord/types";
|
|
7
|
+
export * from "@seedcord/core";
|
|
8
|
+
|
|
9
|
+
//#region src/node/Seedcord.d.ts
|
|
10
|
+
/**
|
|
11
|
+
* The HTTP-interactions bot host, a long-running node server around the engine.
|
|
12
|
+
*
|
|
13
|
+
* Discovers handlers from `config.bot.interactions.path`, verifies and dispatches interactions on
|
|
14
|
+
* `start(port)`, and runs coordinated shutdown with an in-flight drain. The edge deploy path calls
|
|
15
|
+
* `createSeedcord` from a generated entry.
|
|
16
|
+
*/
|
|
17
|
+
declare class Seedcord extends Pluggable implements Core {
|
|
18
|
+
readonly config: HttpConfig;
|
|
19
|
+
/** @internal */
|
|
20
|
+
readonly [SeedcordBrand] = true;
|
|
21
|
+
/** @internal */
|
|
22
|
+
readonly augmentTarget = "@seedcord/http";
|
|
23
|
+
/** @internal */
|
|
24
|
+
readonly version: string;
|
|
25
|
+
/** Workerd-compatible Discord REST client. `start()` sets the token. */
|
|
26
|
+
readonly rest: REST;
|
|
27
|
+
/** @see {@link IRateLimiter} */
|
|
28
|
+
readonly rateLimiter: IRateLimiter;
|
|
29
|
+
/** @see {@link CoordinatedShutdown} */
|
|
30
|
+
readonly shutdown: CoordinatedShutdown;
|
|
31
|
+
/** @see {@link CoordinatedStartup} */
|
|
32
|
+
readonly startup: CoordinatedStartup;
|
|
33
|
+
private readonly interactions?;
|
|
34
|
+
private readonly healthCheck?;
|
|
35
|
+
private readonly hmrManager;
|
|
36
|
+
private readonly logger;
|
|
37
|
+
private server?;
|
|
38
|
+
private boundPort?;
|
|
39
|
+
private requestedPort;
|
|
40
|
+
private fetchedUsername?;
|
|
41
|
+
constructor(config: HttpConfig);
|
|
42
|
+
/** The bot's discord username, populated by the ready fetch. */
|
|
43
|
+
get username(): string | undefined;
|
|
44
|
+
/** The bound server port, populated once `start()` is listening. */
|
|
45
|
+
get port(): number | undefined;
|
|
46
|
+
protected pluginCapabilities(): PluginCapabilities;
|
|
47
|
+
/**
|
|
48
|
+
* Starts the host and runs the startup tasks.
|
|
49
|
+
*
|
|
50
|
+
* @param port - The port the interaction server binds. {@default `3000`}
|
|
51
|
+
*/
|
|
52
|
+
start(port?: number): Promise<this>;
|
|
53
|
+
protected static reset(): void;
|
|
54
|
+
private registerStartupTasks;
|
|
55
|
+
private registerHmrAwareModules;
|
|
56
|
+
private listen;
|
|
57
|
+
private fetchUsername;
|
|
58
|
+
private stopServer;
|
|
59
|
+
}
|
|
60
|
+
declare namespace index_d_exports {
|
|
61
|
+
export { AutocompleteHandler, ButtonHandler, ComponentHandler, ContextMenuHandler, Core, EngineContext, Gated, HttpConfig, HttpEdgeConfig, HttpServerConfig, InteractionGateContext, InteractionHandler, ModalHandler, RepliableHandler, RouteManifest, Seedcord, SelectMenuHandler, SlashHandler, SlashOptions, createSeedcord, version };
|
|
62
|
+
}
|
|
4
63
|
//#endregion
|
|
5
|
-
export { version };
|
|
64
|
+
export { AutocompleteHandler, ButtonHandler, ComponentHandler, ContextMenuHandler, type Core, type EngineContext, Gated, type HttpConfig, type HttpEdgeConfig, type HttpServerConfig, type InteractionGateContext, InteractionHandler, ModalHandler, RepliableHandler, type RouteManifest, Seedcord, SelectMenuHandler, SlashHandler, type SlashOptions, createSeedcord, version };
|
|
6
65
|
//# sourceMappingURL=index.d.mts.map
|