@seedcord/http 0.10.2 → 0.11.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 +55 -9
- package/dist/index.d.mts +42 -57
- package/dist/index.mjs +144 -239
- package/dist/index.mjs.map +1 -1
- package/dist/shared-vsj1uwIH.d.mts +977 -0
- package/dist/{edge.index-DCP1BD6f.mjs → username-B6enaS_x.mjs} +1634 -1519
- package/dist/username-B6enaS_x.mjs.map +1 -0
- package/dist/workerd.index.d.mts +65 -0
- package/dist/workerd.index.mjs +177 -0
- package/dist/workerd.index.mjs.map +1 -0
- package/package.json +22 -30
- package/dist/Manifest-D5MEsTmH.d.mts +0 -485
- package/dist/edge.index-DCP1BD6f.mjs.map +0 -1
- package/dist/edge.index-DFszgCJp.d.mts +0 -502
- package/dist/edge.index.d.mts +0 -10
- package/dist/edge.index.mjs +0 -15
- package/dist/manifest.index.d.mts +0 -10
- package/dist/manifest.index.mjs +0 -26
- package/dist/manifest.index.mjs.map +0 -1
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { A as Emojis, C as MessageContextMenuHandler, D as InteractionHandler, E as InteractionMiddleware, M as ModalFields, N as Plugin, O as RepliableHandler, S as AutocompleteHandler, T as SlashHandler, _ as StringMenuHandler, a as HmrModuleHandler, b as ButtonHandler, c as ArraySource, d as Subscriber, f as WebhookLog, g as SelectMenuHandler, h as RoleMenuHandler, i as HttpStartupTasks, j as installEmojis, k as ReplySender, l as CursorSource, m as MentionableMenuHandler, n as InteractionsService, o as version, p as ChannelMenuHandler, r as rejectNonPost, s as Gated, t as usernameOf, u as Paginator, v as UserMenuHandler, w as UserContextMenuHandler, x as ComponentHandler, y as ModalHandler } from "./username-B6enaS_x.mjs";
|
|
2
|
+
import { BAKED_IDS_KEY, CoordinatedStartup, HmrManager, PluginLifecycle, attachmentsOf, bindBotColor, connectDevChannel, forwardLogsToCli, installLinks, sealAttachments, toWireError } from "@seedcord/core/internal";
|
|
3
|
+
import { PluginHost } from "@seedcord/core/plugin";
|
|
4
|
+
import { SeedcordErrorCode } from "@seedcord/errors";
|
|
5
|
+
import { SeedcordError, setColorLevel } from "@seedcord/errors/internal";
|
|
6
|
+
import { Logger } from "@seedcord/logger";
|
|
7
|
+
import { HostAugmentTarget, HostVersion, SeedcordBrand } from "@seedcord/types/internal";
|
|
8
|
+
|
|
9
|
+
export * from "@seedcord/errors"
|
|
10
|
+
|
|
11
|
+
export * from "@seedcord/core"
|
|
12
|
+
|
|
13
|
+
export * from "@seedcord/logger"
|
|
14
|
+
|
|
15
|
+
export * from "@seedcord/event-emitter"
|
|
16
|
+
|
|
17
|
+
export * from "@seedcord/rate-limiter"
|
|
18
|
+
|
|
19
|
+
export * from "@seedcord/utils"
|
|
20
|
+
|
|
21
|
+
//#region src/edge/defaults.ts
|
|
22
|
+
const edgeShutdown = { addTask: () => {
|
|
23
|
+
throw new SeedcordError(SeedcordErrorCode.CoreLifecycleUnavailable);
|
|
24
|
+
} };
|
|
25
|
+
const EDGE_SWEEPERS = {
|
|
26
|
+
hashSweepInterval: 0,
|
|
27
|
+
handlerSweepInterval: 0
|
|
28
|
+
};
|
|
29
|
+
function edgeRestOptions(given = {}) {
|
|
30
|
+
for (const key of Object.keys(EDGE_SWEEPERS)) if (given[key] !== void 0) throw new SeedcordError(SeedcordErrorCode.ConfigEdgeRestSweeper, [key]);
|
|
31
|
+
return {
|
|
32
|
+
...given,
|
|
33
|
+
...EDGE_SWEEPERS
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/edge/Seedcord.ts
|
|
39
|
+
function bakedIds() {
|
|
40
|
+
const ids = Reflect.get(globalThis, Symbol.for(BAKED_IDS_KEY));
|
|
41
|
+
if (!ids) throw new SeedcordError(SeedcordErrorCode.CoreEdgeUnbuilt);
|
|
42
|
+
return ids;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The HTTP-interactions bot on Cloudflare Workers. Default-export it from `bot.ts`. Cloudflare
|
|
46
|
+
* calls `fetch` for every request.
|
|
47
|
+
*
|
|
48
|
+
* The constructor stores the config. The first POST in each isolate reads `DISCORD_BOT_TOKEN`
|
|
49
|
+
* and the public key, command ids, and emoji ids that `seedcord build` wrote into the worker. It
|
|
50
|
+
* loads the handler and subscriber folders, then runs the startup tasks and every plugin's `init()`
|
|
51
|
+
* and `ready()`. Requests that arrive meanwhile wait for it.
|
|
52
|
+
*
|
|
53
|
+
* Under `seedcord dev` the bot starts when the CLI starts it. It reads the public key and emoji
|
|
54
|
+
* ids from Discord and deploys your commands, the way a node bot does.
|
|
55
|
+
*/
|
|
56
|
+
var Seedcord = class Seedcord extends PluginHost {
|
|
57
|
+
/** @internal */
|
|
58
|
+
[SeedcordBrand] = true;
|
|
59
|
+
/** @internal */
|
|
60
|
+
[HostAugmentTarget] = "@seedcord/http";
|
|
61
|
+
/** @internal */
|
|
62
|
+
[HostVersion] = version;
|
|
63
|
+
/** Discord REST client built from `bot.restOptions`, with both sweepers off. */
|
|
64
|
+
rest;
|
|
65
|
+
/** @see {@link IRateLimiter} */
|
|
66
|
+
rateLimiter;
|
|
67
|
+
/** @see {@link Bus} */
|
|
68
|
+
bus;
|
|
69
|
+
/**
|
|
70
|
+
* @deprecated Cloudflare Workers don't provide a shutdown hook.
|
|
71
|
+
* @throws A **SeedcordError** with `CoreLifecycleUnavailable` every time you call `addTask`.
|
|
72
|
+
*/
|
|
73
|
+
shutdown = edgeShutdown;
|
|
74
|
+
/** Add a task that runs during startup, on the first POST. */
|
|
75
|
+
startup;
|
|
76
|
+
config;
|
|
77
|
+
#service;
|
|
78
|
+
#startup = new CoordinatedStartup();
|
|
79
|
+
#plugins = new PluginLifecycle(this.#startup, { addTask: () => void 0 });
|
|
80
|
+
#hmr = new HmrManager();
|
|
81
|
+
#logger = new Logger("Server", { channel: "bot" });
|
|
82
|
+
#readsBakedIds;
|
|
83
|
+
#prepared;
|
|
84
|
+
#started;
|
|
85
|
+
static #isInstantiated = false;
|
|
86
|
+
constructor(config) {
|
|
87
|
+
super("http", "edge");
|
|
88
|
+
if (Seedcord.#isInstantiated) throw new SeedcordError(SeedcordErrorCode.CoreSingletonViolation);
|
|
89
|
+
Seedcord.#isInstantiated = true;
|
|
90
|
+
this.config = config;
|
|
91
|
+
this.startup = { addTask: this.#startup.addTask.bind(this.#startup) };
|
|
92
|
+
bindBotColor(() => this.config.botColor);
|
|
93
|
+
this.#service = new InteractionsService(this, config, edgeRestOptions(config.bot.restOptions));
|
|
94
|
+
this.rest = this.#service.rest;
|
|
95
|
+
this.rateLimiter = this.#service.rateLimiter;
|
|
96
|
+
this.bus = this.#service.bus;
|
|
97
|
+
const cli = connectDevChannel();
|
|
98
|
+
this.#readsBakedIds = !cli;
|
|
99
|
+
if (cli) {
|
|
100
|
+
forwardLogsToCli();
|
|
101
|
+
this.#startWhenAsked(cli);
|
|
102
|
+
}
|
|
103
|
+
this.#hmr.init(cli);
|
|
104
|
+
}
|
|
105
|
+
#startWhenAsked(cli) {
|
|
106
|
+
const tasks = new HttpStartupTasks(this, this.#service);
|
|
107
|
+
tasks.registerHmr(this.#hmr);
|
|
108
|
+
tasks.addDiscordTasks();
|
|
109
|
+
cli.on("seedcord:start", ({ colorLevel }) => {
|
|
110
|
+
setColorLevel(colorLevel);
|
|
111
|
+
this.#startForCli(cli);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
async #startForCli(cli) {
|
|
115
|
+
try {
|
|
116
|
+
await this.#start();
|
|
117
|
+
} catch (error) {
|
|
118
|
+
cli.send("seedcord:start-failed", { error: toWireError(error) });
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
cli.send("seedcord:started", { username: await usernameOf(this.rest, this.#logger) });
|
|
122
|
+
}
|
|
123
|
+
/** The bot's Discord application id. Throws if you read it before the bot starts. */
|
|
124
|
+
get applicationId() {
|
|
125
|
+
return this.#service.applicationId;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Answers one request to the interactions endpoint. Cloudflare passes `env` and `ctx`, but this
|
|
129
|
+
* method reads only `ctx`. Import your bindings as `env` from `cloudflare:workers`.
|
|
130
|
+
* `cf workers types` writes their types. Work that continues after the 202 response runs under `ctx.waitUntil`. Any request
|
|
131
|
+
* besides a POST gets a 405 before the bot starts.
|
|
132
|
+
*/
|
|
133
|
+
async fetch(request, _env, ctx) {
|
|
134
|
+
const notPost = rejectNonPost(request);
|
|
135
|
+
if (notPost) return notPost;
|
|
136
|
+
await this.#start();
|
|
137
|
+
return this.#service.engine(request, ctx);
|
|
138
|
+
}
|
|
139
|
+
async #start() {
|
|
140
|
+
this.#prepared ??= this.#prepare();
|
|
141
|
+
await this.#prepared;
|
|
142
|
+
this.#started ??= this.#runStartup();
|
|
143
|
+
await this.#started;
|
|
144
|
+
}
|
|
145
|
+
async #prepare() {
|
|
146
|
+
Logger.configure(this.config.logger ?? {});
|
|
147
|
+
const ids = this.#readsBakedIds ? bakedIds() : void 0;
|
|
148
|
+
this.#service.authenticate();
|
|
149
|
+
await this.#service.subscribers.init();
|
|
150
|
+
await this.#service.interactions?.init();
|
|
151
|
+
if (!ids) return;
|
|
152
|
+
installLinks(ids);
|
|
153
|
+
installEmojis(ids.emojis);
|
|
154
|
+
this.#service.prepareEngine(ids.publicKey);
|
|
155
|
+
}
|
|
156
|
+
async #runStartup() {
|
|
157
|
+
sealAttachments(this);
|
|
158
|
+
this.#plugins.register(attachmentsOf(this));
|
|
159
|
+
try {
|
|
160
|
+
await this.#startup.run();
|
|
161
|
+
} catch (caught) {
|
|
162
|
+
await this.#plugins.rollback();
|
|
163
|
+
this.#plugins.afterTimedOutInits(() => {
|
|
164
|
+
this.#started = void 0;
|
|
165
|
+
});
|
|
166
|
+
throw caught;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/** @internal */
|
|
170
|
+
static reset() {
|
|
171
|
+
Seedcord.#isInstantiated = false;
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
//#endregion
|
|
176
|
+
export { ArraySource, AutocompleteHandler, ButtonHandler, ChannelMenuHandler, ComponentHandler, CursorSource, Emojis, Gated, HmrModuleHandler, InteractionHandler, InteractionMiddleware, MentionableMenuHandler, MessageContextMenuHandler, ModalFields, ModalHandler, Paginator, Plugin, RepliableHandler, ReplySender, RoleMenuHandler, Seedcord, SelectMenuHandler, SlashHandler, StringMenuHandler, Subscriber, UserContextMenuHandler, UserMenuHandler, WebhookLog, version };
|
|
177
|
+
//# sourceMappingURL=workerd.index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workerd.index.mjs","names":["packageVersion"],"sources":["../src/edge/defaults.ts","../src/edge/Seedcord.ts"],"sourcesContent":["import { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError } from '@seedcord/errors/internal';\n\nimport type { EdgeSweeperKey } from '#interfaces/Config';\nimport type { RESTOptions } from '@discordjs/rest';\nimport type { CoordinatedShutdown } from '@seedcord/core/node';\n\nexport const edgeShutdown: Pick<CoordinatedShutdown, 'addTask'> = {\n addTask: () => {\n throw new SeedcordError(SeedcordErrorCode.CoreLifecycleUnavailable);\n }\n};\n\n// @discordjs/rest skips a sweeper set to 0\nconst EDGE_SWEEPERS: Record<EdgeSweeperKey, 0> = { hashSweepInterval: 0, handlerSweepInterval: 0 };\n\nexport function edgeRestOptions(given: Partial<RESTOptions> = {}): Partial<RESTOptions> {\n for (const key of Object.keys(EDGE_SWEEPERS) as EdgeSweeperKey[]) {\n if (given[key] !== undefined) throw new SeedcordError(SeedcordErrorCode.ConfigEdgeRestSweeper, [key]);\n }\n return { ...given, ...EDGE_SWEEPERS };\n}\n","import {\n attachmentsOf,\n BAKED_IDS_KEY,\n bindBotColor,\n connectDevChannel,\n CoordinatedStartup,\n forwardLogsToCli,\n HmrManager,\n installLinks,\n PluginLifecycle,\n sealAttachments,\n toWireError\n} from '@seedcord/core/internal';\nimport { PluginHost } from '@seedcord/core/plugin';\nimport { SeedcordErrorCode } from '@seedcord/errors';\nimport { SeedcordError, setColorLevel } from '@seedcord/errors/internal';\nimport { Logger } from '@seedcord/logger';\nimport { HostAugmentTarget, HostVersion, SeedcordBrand } from '@seedcord/types/internal';\n\nimport { installEmojis } from '#src/emojis/EmojiInjector';\nimport { rejectNonPost } from '#src/engine';\nimport { HttpStartupTasks } from '#src/HttpStartupTasks';\nimport { InteractionsService } from '#src/InteractionsService';\nimport { usernameOf } from '#src/username';\nimport { version as packageVersion } from '#src/version';\n\nimport { edgeRestOptions, edgeShutdown } from './defaults';\n\nimport type { HttpEdgeConfig } from '#interfaces/Config';\nimport type { EngineContext } from '#src/engine';\nimport type { REST } from '@discordjs/rest';\nimport type { Bus } from '@seedcord/core';\nimport type { BakedIds } from '@seedcord/core/internal';\nimport type { IRateLimiter } from '@seedcord/types';\nimport type { DevChannel, SeedcordCliEvents, SeedcordFrameworkEvents } from '@seedcord/types/internal';\n\n// seedcord build's worker entry writes these before bot.ts loads\nfunction bakedIds(): BakedIds {\n const ids = Reflect.get(globalThis, Symbol.for(BAKED_IDS_KEY)) as BakedIds | undefined;\n if (!ids) throw new SeedcordError(SeedcordErrorCode.CoreEdgeUnbuilt);\n return ids;\n}\n\n/**\n * The HTTP-interactions bot on Cloudflare Workers. Default-export it from `bot.ts`. Cloudflare\n * calls `fetch` for every request.\n *\n * The constructor stores the config. The first POST in each isolate reads `DISCORD_BOT_TOKEN`\n * and the public key, command ids, and emoji ids that `seedcord build` wrote into the worker. It\n * loads the handler and subscriber folders, then runs the startup tasks and every plugin's `init()`\n * and `ready()`. Requests that arrive meanwhile wait for it.\n *\n * Under `seedcord dev` the bot starts when the CLI starts it. It reads the public key and emoji\n * ids from Discord and deploys your commands, the way a node bot does.\n */\nexport class Seedcord extends PluginHost<'http', 'edge'> {\n // the CLI reads these to detect and augment the instance\n /** @internal */\n public readonly [SeedcordBrand] = true;\n /** @internal */\n public readonly [HostAugmentTarget] = '@seedcord/http';\n /** @internal */\n public readonly [HostVersion]: string = packageVersion;\n\n /** Discord REST client built from `bot.restOptions`, with both sweepers off. */\n public readonly rest: REST;\n\n /** @see {@link IRateLimiter} */\n public readonly rateLimiter: IRateLimiter;\n\n /** @see {@link Bus} */\n public readonly bus: Bus;\n\n /**\n * @deprecated Cloudflare Workers don't provide a shutdown hook.\n * @throws A **SeedcordError** with `CoreLifecycleUnavailable` every time you call `addTask`.\n */\n public readonly shutdown = edgeShutdown;\n\n /** Add a task that runs during startup, on the first POST. */\n public readonly startup: Pick<CoordinatedStartup, 'addTask'>;\n\n public readonly config: HttpEdgeConfig;\n\n readonly #service: InteractionsService;\n readonly #startup = new CoordinatedStartup();\n // workerd gives a worker no shutdown hook. dispose() runs only in a rollback.\n readonly #plugins = new PluginLifecycle(this.#startup, { addTask: () => undefined });\n\n readonly #hmr = new HmrManager();\n readonly #logger = new Logger('Server', { channel: 'bot' });\n // seedcord dev reads them from Discord in its startup tasks\n readonly #readsBakedIds: boolean;\n\n #prepared?: Promise<void>;\n #started?: Promise<void> | undefined;\n\n static #isInstantiated = false;\n\n constructor(config: HttpEdgeConfig) {\n super('http', 'edge');\n if (Seedcord.#isInstantiated) throw new SeedcordError(SeedcordErrorCode.CoreSingletonViolation);\n Seedcord.#isInstantiated = true;\n\n this.config = config;\n this.startup = { addTask: this.#startup.addTask.bind(this.#startup) };\n bindBotColor(() => this.config.botColor);\n\n this.#service = new InteractionsService(this, config, edgeRestOptions(config.bot.restOptions));\n this.rest = this.#service.rest;\n this.rateLimiter = this.#service.rateLimiter;\n this.bus = this.#service.bus;\n\n const cli = connectDevChannel();\n this.#readsBakedIds = !cli;\n if (cli) {\n forwardLogsToCli();\n this.#startWhenAsked(cli);\n }\n this.#hmr.init(cli);\n }\n\n #startWhenAsked(cli: DevChannel<SeedcordFrameworkEvents, SeedcordCliEvents>): void {\n const tasks = new HttpStartupTasks(this, this.#service);\n tasks.registerHmr(this.#hmr);\n tasks.addDiscordTasks();\n cli.on('seedcord:start', ({ colorLevel }) => {\n setColorLevel(colorLevel);\n void this.#startForCli(cli);\n });\n }\n\n async #startForCli(cli: DevChannel<SeedcordFrameworkEvents, SeedcordCliEvents>): Promise<void> {\n try {\n await this.#start();\n } catch (error) {\n cli.send('seedcord:start-failed', { error: toWireError(error) });\n return;\n }\n cli.send('seedcord:started', { username: await usernameOf(this.rest, this.#logger) });\n }\n\n /** The bot's Discord application id. Throws if you read it before the bot starts. */\n public get applicationId(): string {\n return this.#service.applicationId;\n }\n\n /**\n * Answers one request to the interactions endpoint. Cloudflare passes `env` and `ctx`, but this\n * method reads only `ctx`. Import your bindings as `env` from `cloudflare:workers`.\n * `cf workers types` writes their types. Work that continues after the 202 response runs under `ctx.waitUntil`. Any request\n * besides a POST gets a 405 before the bot starts.\n */\n public async fetch(request: Request, _env?: unknown, ctx?: EngineContext): Promise<Response> {\n const notPost = rejectNonPost(request);\n if (notPost) return notPost;\n\n await this.#start();\n return this.#service.engine(request, ctx);\n }\n\n async #start(): Promise<void> {\n this.#prepared ??= this.#prepare();\n await this.#prepared;\n\n this.#started ??= this.#runStartup();\n await this.#started;\n }\n\n // once per isolate. Running the loaders again would register every subscriber twice\n async #prepare(): Promise<void> {\n // seedcord dev's codegen copy constructs this bot inside the CLI and never starts it\n Logger.configure(this.config.logger ?? {});\n const ids = this.#readsBakedIds ? bakedIds() : undefined;\n this.#service.authenticate();\n await this.#service.subscribers.init();\n await this.#service.interactions?.init();\n if (!ids) return;\n installLinks(ids);\n installEmojis(ids.emojis);\n this.#service.prepareEngine(ids.publicKey);\n }\n\n async #runStartup(): Promise<void> {\n sealAttachments(this);\n this.#plugins.register(attachmentsOf(this));\n try {\n await this.#startup.run();\n } catch (caught) {\n await this.#plugins.rollback();\n this.#plugins.afterTimedOutInits(() => {\n this.#started = undefined;\n });\n throw caught;\n }\n }\n\n /** @internal */\n protected static reset(): void {\n Seedcord.#isInstantiated = false;\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seedcord/http",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.11.0",
|
|
5
5
|
"description": "HTTP interactions transport for seedcord bots",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"discord",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"typescript"
|
|
13
13
|
],
|
|
14
14
|
"engines": {
|
|
15
|
-
"node": "
|
|
15
|
+
"node": "^24.22.1 || >=26.12.1",
|
|
16
16
|
"bun": ">=1.4.2"
|
|
17
17
|
},
|
|
18
18
|
"repository": {
|
|
@@ -28,22 +28,14 @@
|
|
|
28
28
|
"types": "./dist/index.d.mts",
|
|
29
29
|
"exports": {
|
|
30
30
|
".": {
|
|
31
|
+
"workerd": {
|
|
32
|
+
"types": "./dist/workerd.index.d.mts",
|
|
33
|
+
"default": "./dist/workerd.index.mjs"
|
|
34
|
+
},
|
|
31
35
|
"import": {
|
|
32
36
|
"types": "./dist/index.d.mts",
|
|
33
37
|
"default": "./dist/index.mjs"
|
|
34
38
|
}
|
|
35
|
-
},
|
|
36
|
-
"./edge": {
|
|
37
|
-
"import": {
|
|
38
|
-
"types": "./dist/edge.index.d.mts",
|
|
39
|
-
"default": "./dist/edge.index.mjs"
|
|
40
|
-
}
|
|
41
|
-
},
|
|
42
|
-
"./manifest": {
|
|
43
|
-
"import": {
|
|
44
|
-
"types": "./dist/manifest.index.d.mts",
|
|
45
|
-
"default": "./dist/manifest.index.mjs"
|
|
46
|
-
}
|
|
47
39
|
}
|
|
48
40
|
},
|
|
49
41
|
"files": [
|
|
@@ -56,33 +48,33 @@
|
|
|
56
48
|
"@discordjs/collection": "^2.1.1",
|
|
57
49
|
"@discordjs/core": "^2.6.0",
|
|
58
50
|
"@discordjs/rest": "^2.6.3",
|
|
59
|
-
"@seedcord/core": "^0.
|
|
60
|
-
"@seedcord/custom-id": "^0.
|
|
61
|
-
"@seedcord/errors": "^0.
|
|
62
|
-
"@seedcord/event-emitter": "^0.
|
|
63
|
-
"@seedcord/logger": "^0.
|
|
64
|
-
"@seedcord/rate-limiter": "^0.
|
|
65
|
-
"@seedcord/types": "^0.
|
|
66
|
-
"@seedcord/utils": "^0.
|
|
51
|
+
"@seedcord/core": "^0.11.0",
|
|
52
|
+
"@seedcord/custom-id": "^0.3.0",
|
|
53
|
+
"@seedcord/errors": "^0.14.0",
|
|
54
|
+
"@seedcord/event-emitter": "^0.2.0",
|
|
55
|
+
"@seedcord/logger": "^0.5.0",
|
|
56
|
+
"@seedcord/rate-limiter": "^0.2.0",
|
|
57
|
+
"@seedcord/types": "^0.15.0",
|
|
58
|
+
"@seedcord/utils": "^0.9.0",
|
|
67
59
|
"discord-api-types": "^0.38.52",
|
|
68
60
|
"reflect-metadata": "^0.2.2",
|
|
69
|
-
"type-fest": "^5.
|
|
61
|
+
"type-fest": "^5.9.0"
|
|
70
62
|
},
|
|
71
63
|
"peerDependencies": {
|
|
72
|
-
"envapt": "^
|
|
64
|
+
"envapt": "^9.2.0",
|
|
73
65
|
"typescript": "^5.9.3 || ^6.0.0 || ^7.0.0"
|
|
74
66
|
},
|
|
75
67
|
"devDependencies": {
|
|
76
68
|
"@cloudflare/vitest-pool-workers": "^0.22.0",
|
|
77
69
|
"@discordjs/builders": "^1.14.1",
|
|
78
|
-
"@seedcord/eslint-config": "^
|
|
79
|
-
"@seedcord/tsconfig": "^
|
|
70
|
+
"@seedcord/eslint-config": "^3.0.0",
|
|
71
|
+
"@seedcord/tsconfig": "^3.0.0",
|
|
80
72
|
"@seedcord/tsdown-config": "^2.0.1",
|
|
81
73
|
"@seedcord/vitest-config": "^0.0.1",
|
|
82
|
-
"@vitest/coverage-istanbul": "^4.1.
|
|
83
|
-
"envapt": "^
|
|
74
|
+
"@vitest/coverage-istanbul": "^4.1.12",
|
|
75
|
+
"envapt": "^9.2.0",
|
|
84
76
|
"esbuild": "^0.28.1",
|
|
85
|
-
"vitest": "^4.1.
|
|
77
|
+
"vitest": "^4.1.12"
|
|
86
78
|
},
|
|
87
79
|
"publishConfig": {
|
|
88
80
|
"access": "public",
|
|
@@ -100,5 +92,5 @@
|
|
|
100
92
|
"test:watch": "vitest dev",
|
|
101
93
|
"coverage": "vitest run --coverage"
|
|
102
94
|
},
|
|
103
|
-
"readme": "<div align=\"center\">\n <picture>\n <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://cdn.seedcord.org/assets/wordmark-dark.webp\" />\n <img src=\"https://cdn.seedcord.org/assets/wordmark-light.webp\" alt=\"seedcord\" width=\"440\" />\n </picture>\n</div>\n\n<div align=\"center\">\n <h3>The whole Discord bot, typed end to end</h3>\n <a href=\"https://seedcord.org\">Website</a> ·\n <a href=\"https://seedcord.org/guide\">Guide</a> ·\n <a href=\"https://seedcord.org/docs\">Reference</a> ·\n <a href=\"https://
|
|
95
|
+
"readme": "<div align=\"center\">\n <picture>\n <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://cdn.seedcord.org/assets/wordmark-dark.webp\" />\n <img src=\"https://cdn.seedcord.org/assets/wordmark-light.webp\" alt=\"seedcord\" width=\"440\" />\n </picture>\n</div>\n\n<div align=\"center\">\n <h3>The whole Discord bot, typed end to end</h3>\n <a href=\"https://seedcord.org\">Website</a> ·\n <a href=\"https://seedcord.org/guide\">Guide</a> ·\n <a href=\"https://seedcord.org/docs\">Reference</a> ·\n <a href=\"https://seedcord.org/chat/\">Discord</a>\n</div>\n\n<br />\n\n<div align=\"center\">\n\n[](https://www.npmjs.com/package/@seedcord/http) [](https://nodejs.org) [](https://bun.com) [](LICENSE)\n\n</div>\n\n## About\n\n`@seedcord/http` is the transport for an http bot. Discord posts each interaction to your bot's URL, and the bot checks the request's Ed25519 signature before it runs your handler. It has no discord.js dependency and keeps no connection open, so it runs on your own server or on Cloudflare Workers.\n\nDiscord posts only interactions to that URL. Use [`@seedcord/gateway`](https://www.npmjs.com/package/@seedcord/gateway) when your bot reacts to messages, members, voice, or reactions.\n\nseedcord is pre-1.0, so a minor version can break your bot. Each release's changelog says what changed and how to update.\n\n## Installation\n\n`pnpm create seedcord` sets up a new bot and asks where it runs. To add seedcord to an existing project:\n\n```sh\npnpm add @seedcord/http @discordjs/builders envapt\npnpm add -D seedcord vite typescript\n```\n\n`envapt` and `typescript` are peer dependencies. `seedcord` is the CLI that runs the bot in dev and builds it. In dev, it also opens a cloudflared tunnel and sets your app's interactions URL to it.\n\n## Usage\n\n`bot.ts` creates the bot and tells it where your handlers are:\n\n```ts\nimport { Seedcord } from '@seedcord/http';\nimport { Converters, Envapter } from 'envapt';\n\nexport default new Seedcord({\n bot: {\n interactions: { path: './handlers' },\n commands: {\n path: './commands',\n guilds: Envapter.getAs('TESTING_GUILD_IDS', Converters.array(), [])\n }\n },\n subscribers: { path: null }\n});\n```\n\nRead your environment through [envapt](https://envapt.materwelon.dev), the way `TESTING_GUILD_IDS` is read above. seedcord loads your `.env` files into envapt, and binds a worker's `env` to it on Cloudflare Workers, so the same read works in dev, in a build, and on Workers. envapt also reads your shell's variables, while `process.env` misses everything in your `.env` files.\n\nHandlers read raw payloads from `discord-api-types`. Slash commands, components, checks, and plugins work the same way as on the gateway. The [guide](https://seedcord.org/guide) covers them.\n\n## Where it runs\n\n### Its own server\n\nOn Node or Bun, `Seedcord` listens on `port`, 3000 by default.\n\n### Inside your server\n\nSet `port: false`, start the bot, then pass each request to `bot.fetch()`. It takes a web `Request` and returns a `Response`, so a Hono or Next.js route can forward to it:\n\n```ts\nimport { Hono } from 'hono';\n\nimport bot from './bot';\n\nawait bot.start();\n\nconst app = new Hono();\napp.post('/interactions', (c) => bot.fetch(c.req.raw));\n```\n\n### Cloudflare Workers\n\nThe same `Seedcord` import runs on Cloudflare Workers. A `cloudflare.config.ts` beside `seedcord.config.ts` makes `seedcord build` write a worker, which you deploy with `cf deploy --prebuilt`. The [Workers guide](https://seedcord.org/guide/build/workers) covers the setup.\n"
|
|
104
96
|
}
|