seedcord 0.21.4 → 0.22.0-next.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 +51 -9
- package/bin/seedcord.mjs +39 -16
- package/dist/cli.mjs +6140 -2161
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +2 -109
- package/dist/index.mjs +1 -1
- package/dist/schema-UiJoop9d.d.mts +151 -0
- package/dist/{src-BfciUrzr.mjs → src-BrsznVXh.mjs} +3 -3
- package/dist/src-BrsznVXh.mjs.map +1 -0
- package/dist/workerd.index.d.mts +9 -0
- package/dist/workerd.index.mjs +11 -0
- package/dist/workerd.index.mjs.map +1 -0
- package/package.json +44 -23
- package/dist/src-BfciUrzr.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -10,31 +10,35 @@
|
|
|
10
10
|
<a href="https://seedcord.org">Website</a> ·
|
|
11
11
|
<a href="https://seedcord.org/guide">Guide</a> ·
|
|
12
12
|
<a href="https://seedcord.org/docs">Reference</a> ·
|
|
13
|
-
<a href="https://
|
|
13
|
+
<a href="https://seedcord.org/chat/">Discord</a>
|
|
14
14
|
</div>
|
|
15
15
|
|
|
16
16
|
<br />
|
|
17
17
|
|
|
18
18
|
<div align="center">
|
|
19
19
|
|
|
20
|
-
[](https://www.npmjs.com/package/seedcord) [](https://nodejs.org) [](https://bun.com) [](LICENSE)
|
|
21
21
|
|
|
22
22
|
</div>
|
|
23
23
|
|
|
24
24
|
## About
|
|
25
25
|
|
|
26
|
-
`seedcord` is the CLI a bot project runs during development and at build time. It reads `seedcord.config.ts` and gives you a dev server with hot reload, a production build, the codegen that types your commands, and a
|
|
26
|
+
`seedcord` is the CLI a bot project runs during development and at build time. It reads `seedcord.config.ts` and gives you a dev server with hot reload, a production build, the codegen that types your commands, and a way to deploy those commands to Discord.
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
It loads your bot through Vite every time, with any Vite plugin you add. Those plugins, your `.env` modes, and bundled data files you set up in dev work the same way in the build. One `seedcord build` makes a Node or Bun server, a single Bun binary, a Cloudflare Worker, or a package another app installs and starts.
|
|
29
|
+
|
|
30
|
+
seedcord is pre-1.0, so a minor version can break your bot. Each release's changelog says what changed and how to update.
|
|
29
31
|
|
|
30
32
|
## Installation
|
|
31
33
|
|
|
32
34
|
`pnpm create seedcord` adds it to a new project. To add it to an existing one:
|
|
33
35
|
|
|
34
36
|
```sh
|
|
35
|
-
pnpm add -D seedcord
|
|
37
|
+
pnpm add -D seedcord vite
|
|
36
38
|
```
|
|
37
39
|
|
|
40
|
+
Run it through your project's scripts, like `pnpm dev`. A global `seedcord` throws `CliNotProjectInstall`, because the CLI has to load the same seedcord packages your bot imports.
|
|
41
|
+
|
|
38
42
|
## Commands
|
|
39
43
|
|
|
40
44
|
<!-- prettier-ignore-start -->
|
|
@@ -42,26 +46,64 @@ pnpm add -D seedcord
|
|
|
42
46
|
| command | what it does |
|
|
43
47
|
| --- | --- |
|
|
44
48
|
| `seedcord dev` | runs the bot from the config file, reloading changed modules in place |
|
|
45
|
-
| `seedcord build` |
|
|
49
|
+
| `seedcord build` | type checks the bot and bundles it into `outDir` with Vite. An edge bot builds into a Cloudflare worker |
|
|
46
50
|
| `seedcord codegen` | writes the typed augmentations for your commands and config |
|
|
47
|
-
| `seedcord commands` |
|
|
51
|
+
| `seedcord commands` | deploys, lists and cleans up your commands on Discord |
|
|
48
52
|
|
|
49
53
|
<!-- prettier-ignore-end -->
|
|
50
54
|
|
|
51
55
|
`codegen --check` verifies the committed augmentations match your source. Run it in CI.
|
|
52
56
|
|
|
53
|
-
`commands
|
|
57
|
+
`commands` reads `DISCORD_BOT_TOKEN` from your environment or `.env`:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
seedcord commands # pick what to do from a menu
|
|
61
|
+
seedcord commands deploy # show what changes, then ask before deploying
|
|
62
|
+
seedcord commands deploy --yes # deploy without asking
|
|
63
|
+
seedcord commands deploy --force # also deploy scopes that match the last deploy
|
|
64
|
+
seedcord commands list # show the commands Discord has
|
|
65
|
+
seedcord commands list --all-guilds # include every guild the bot is in
|
|
66
|
+
seedcord commands list --json # print them as JSON
|
|
67
|
+
seedcord commands clean # pick guilds, then delete commands that duplicate a global one
|
|
68
|
+
seedcord commands clean --all-guilds # list those duplicates in every guild
|
|
69
|
+
seedcord commands clean --all-guilds --yes # delete them
|
|
70
|
+
seedcord commands purge # pick where, then delete every command there
|
|
71
|
+
seedcord commands purge --guilds 111 222 # list every command in those guilds
|
|
72
|
+
seedcord commands purge --global --yes # delete every global command
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
In CI, or anywhere without a terminal, nothing changes on Discord unless you pass `--yes`.
|
|
54
76
|
|
|
55
77
|
On the http transport, `dev` also opens a cloudflared tunnel and points Discord's interactions URL at it.
|
|
56
78
|
|
|
79
|
+
Pass `--verbose` to any command for the resolved config and full error stacks.
|
|
80
|
+
|
|
57
81
|
## Config
|
|
58
82
|
|
|
59
83
|
`defineConfig` types `seedcord.config.ts`:
|
|
60
84
|
|
|
61
85
|
```ts
|
|
86
|
+
import yaml from '@rollup/plugin-yaml';
|
|
62
87
|
import { defineConfig } from 'seedcord';
|
|
63
88
|
|
|
64
89
|
export default defineConfig({
|
|
65
|
-
|
|
90
|
+
root: './src',
|
|
91
|
+
instance: './bot.ts',
|
|
92
|
+
build: { start: './index.ts' },
|
|
93
|
+
files: ['./locales'],
|
|
94
|
+
vitePlugins: () => [yaml()]
|
|
66
95
|
});
|
|
67
96
|
```
|
|
97
|
+
|
|
98
|
+
- `instance` is the file that exports your bot.
|
|
99
|
+
- `build.start` is the file that starts it. Leave it out to build the bot as a package.
|
|
100
|
+
- `files` lists the folders of data files the build bundles. The bot reads them with `readFiles`.
|
|
101
|
+
- `vitePlugins` takes any Vite plugin, and each one runs in dev and in the build. With the YAML plugin above, a handler can import a `.yaml` file.
|
|
102
|
+
|
|
103
|
+
`ENV=staging pnpm build` builds in staging mode and loads your `.env.staging` files. [envapt](https://envapt.materwelon.dev) reads the same mode in your bot.
|
|
104
|
+
|
|
105
|
+
The [config guide](https://seedcord.org/guide/build/config) covers every key.
|
|
106
|
+
|
|
107
|
+
## Edge bots
|
|
108
|
+
|
|
109
|
+
A `cloudflare.config.ts` beside `seedcord.config.ts` turns an http bot into a Cloudflare Worker. `seedcord dev` runs it in workerd, and `seedcord build` writes a worker you deploy with `cf deploy --prebuilt`. The [Workers guide](https://seedcord.org/guide/build/workers) covers the setup.
|
package/bin/seedcord.mjs
CHANGED
|
@@ -5,28 +5,49 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
5
5
|
|
|
6
6
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
7
7
|
|
|
8
|
-
function
|
|
8
|
+
function declaredEngines() {
|
|
9
9
|
try {
|
|
10
10
|
const pkg = JSON.parse(readFileSync(resolve(here, '../package.json'), 'utf8'));
|
|
11
|
-
return pkg.engines
|
|
11
|
+
return pkg.engines ?? {};
|
|
12
12
|
} catch {
|
|
13
|
-
return
|
|
13
|
+
return {};
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
17
|
+
function parseVersion(text) {
|
|
18
|
+
const [withoutBuild = ''] = text.replace(/^v/, '').split('+');
|
|
19
|
+
const [release = '', ...prerelease] = withoutBuild.split('-');
|
|
20
|
+
const parts = release.split('.').map(Number);
|
|
21
|
+
return parts.every(Number.isInteger) ? { parts, prerelease: prerelease.length > 0 } : undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// semver ranks 1.4.2-canary.1 below 1.4.2
|
|
25
|
+
function meetsMinimum(required, running) {
|
|
26
|
+
const length = Math.max(required.parts.length, running.parts.length);
|
|
27
|
+
for (let index = 0; index < length; index++) {
|
|
28
|
+
const wanted = required.parts[index] ?? 0;
|
|
29
|
+
const got = running.parts[index] ?? 0;
|
|
30
|
+
if (got !== wanted) return got > wanted;
|
|
31
|
+
}
|
|
32
|
+
return !running.prerelease;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// importing core's assertDeclaredRuntime here would load the code this guards
|
|
36
|
+
function unsupportedRuntime() {
|
|
37
|
+
const engines = declaredEngines();
|
|
38
|
+
const { bun, node } = process.versions;
|
|
39
|
+
const runtime =
|
|
40
|
+
bun === undefined
|
|
41
|
+
? { name: 'Node', range: engines.node ?? '', running: node }
|
|
42
|
+
: { name: 'Bun', range: engines.bun ?? '', running: bun };
|
|
20
43
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
if (!required || !current) return null;
|
|
44
|
+
const range = runtime.range.replaceAll(/\s/g, '');
|
|
45
|
+
if (!range.startsWith('>=')) return undefined;
|
|
24
46
|
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return meets ? null : range;
|
|
47
|
+
const required = parseVersion(range.slice('>='.length));
|
|
48
|
+
const running = parseVersion(runtime.running);
|
|
49
|
+
if (!required || !running || meetsMinimum(required, running)) return undefined;
|
|
50
|
+
return runtime;
|
|
30
51
|
}
|
|
31
52
|
|
|
32
53
|
async function run() {
|
|
@@ -41,10 +62,12 @@ async function run() {
|
|
|
41
62
|
await import(pathToFileURL(srcEntry).href);
|
|
42
63
|
}
|
|
43
64
|
|
|
44
|
-
const unsupported =
|
|
65
|
+
const unsupported = unsupportedRuntime();
|
|
45
66
|
if (unsupported) {
|
|
46
67
|
// eslint-disable-next-line no-console -- the bin has no logger
|
|
47
|
-
console.error(
|
|
68
|
+
console.error(
|
|
69
|
+
`seedcord requires ${unsupported.name} ${unsupported.range} but this process runs ${unsupported.running}.`
|
|
70
|
+
);
|
|
48
71
|
process.exit(1);
|
|
49
72
|
}
|
|
50
73
|
|