create-seedcord 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "create-seedcord",
3
3
  "type": "module",
4
- "version": "0.0.1",
4
+ "version": "0.1.0",
5
5
  "description": "Scaffold a new seedcord bot project",
6
6
  "engines": {
7
7
  "node": ">=24.11"
@@ -14,32 +14,28 @@
14
14
  "url": "https://github.com/seedcord/seedcord.git",
15
15
  "directory": "cli/create-seedcord"
16
16
  },
17
- "types": "./dist/index.d.mts",
18
- "exports": {
19
- ".": {
20
- "import": {
21
- "types": "./dist/index.d.mts",
22
- "default": "./dist/index.mjs"
23
- },
24
- "require": {
25
- "types": "./dist/index.d.cts",
26
- "default": "./dist/index.cjs"
27
- }
28
- }
17
+ "seedcordDocs": {
18
+ "skip": true
29
19
  },
30
20
  "files": [
31
21
  "bin",
32
22
  "dist",
23
+ "templates",
33
24
  "package.json",
34
25
  "README.md",
35
26
  "LICENSE"
36
27
  ],
37
28
  "devDependencies": {
29
+ "@clack/prompts": "^1.7.0",
30
+ "discord.js": "^14.27.0",
31
+ "handlebars": "^4.7.9",
32
+ "package-manager-detector": "^1.8.0",
38
33
  "tsx": "^4.23.5",
39
34
  "typescript": "^6.0.3",
40
- "@seedcord/cli-shared": "0.0.1",
35
+ "@seedcord/errors": "0.3.3",
41
36
  "@seedcord/eslint-config": "1.5.2",
42
37
  "@seedcord/tsconfig": "2.0.2",
38
+ "@seedcord/types": "0.8.2",
43
39
  "@seedcord/tsdown-config": "2.0.1",
44
40
  "@seedcord/vitest-config": "0.0.1"
45
41
  },
@@ -60,5 +56,5 @@
60
56
  "test:watch": "vitest dev",
61
57
  "coverage": "vitest run --coverage"
62
58
  },
63
- "readme": "<p 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</p>\n\n# @seedcord/create-seedcord\n\nScaffold a new seedcord bot project\n\nPart of the [seedcord](https://github.com/seedcord/seedcord) framework. Until a major v1.0.0 release, expect breaking changes in minor versions.\n"
59
+ "readme": "<p 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</p>\n\n# create-seedcord\n\nScaffold a new seedcord bot project.\n\n## Usage\n\n```sh\npnpm create seedcord my-bot\nnpm create seedcord my-bot\nyarn create seedcord my-bot\n```\n\nIt asks where the project goes, how Discord reaches your bot, what the bot should react to, your bot token, and an accent color. Then it writes the project, installs, formats, generates your command types, and makes the first commit.\n\n## Flags\n\nEvery question has a flag. Pass them all to skip all questions. `--help` prints the list.\n\nnpm forwards flags to the package only after a `--`:\n\n```sh\nnpm create seedcord my-bot -- --transport gateway --capabilities reactions\npnpm create seedcord my-bot --transport gateway --capabilities reactions\n```\n\n`--no-install` and `--no-git` turn off those two steps.\n\nWith no terminal to ask on, it reads the flags alone. It names the flag that would supply any answer you left out.\n\n## What you get\n\nYou get a TypeScript project with one slash command, its handler, a sample event handler (if you picked `gateway`), `seedcord.config.ts`, eslint, prettier, and a `.env` listing every key the framework reads.\n\n`pnpm dev` starts it with hot reload. On the http transport it also opens a cloudflared tunnel and sets it up, and Discord posts interactions to that URL.\n\n## Docs\n\n- Guide: <https://guide.seedcord.org>\n- API reference: <https://docs.seedcord.org>\n\nPart of the [seedcord](https://github.com/seedcord/seedcord) framework. Until a major v1.0.0 release, expect breaking changes in minor versions.\n"
64
60
  }
@@ -0,0 +1,62 @@
1
+ # {{ projectName }}
2
+
3
+ A Discord bot built with [seedcord](https://seedcord.org){{#if isGateway}} on the gateway transport{{else}} on the http transport{{/if}}.
4
+
5
+ ## Running it
6
+
7
+ ```sh
8
+ {{ pm.run }} dev
9
+ ```
10
+
11
+ That starts the dev server with hot reload{{#unless isGateway}} and opens a tunnel so Discord can reach your interactions endpoint{{/unless}}.
12
+
13
+ ## Scripts
14
+
15
+ <!-- prettier-ignore-start -->
16
+
17
+ | script | what it does |
18
+ | --- | --- |
19
+ | `{{ pm.run }} dev` | dev server with hot reload |
20
+ | `{{ pm.run }} build` | compile to `dist/` |
21
+ | `{{ pm.run }} start` | run the compiled build |
22
+ | `{{ pm.run }} codegen` | regenerate `src/seedcord-gen.d.ts` |
23
+ | `{{ pm.run }} lint` | eslint |
24
+ | `{{ pm.run }} tc` | type-check |
25
+
26
+ <!-- prettier-ignore-end -->
27
+
28
+ Run `codegen` after you add a command or change its options. It writes the types behind `this.options`, and the generated file is committed.
29
+
30
+ ## Environment
31
+
32
+ `.env` holds your secrets and is gitignored.
33
+
34
+ <!-- prettier-ignore-start -->
35
+
36
+ | key | required |
37
+ | --- | --- |
38
+ | `DISCORD_BOT_TOKEN` | yes |
39
+ {{#unless isGateway}}
40
+ | `DISCORD_PUBLIC_KEY` | yes |
41
+ {{/unless}}
42
+ | `UNKNOWN_EXCEPTION_WEBHOOK_URL` | no |
43
+ | `HANDLED_EXCEPTION_WEBHOOK_URL` | no |
44
+ | `ENV` | no, defaults to `development` |
45
+
46
+ <!-- prettier-ignore-end -->
47
+
48
+ The two webhook keys take Discord webhook URLs. Set them to get error reports posted to a channel.
49
+
50
+ ## Where things go
51
+
52
+ - `src/commands/` holds command definitions, one class per command.
53
+ - `src/handlers/` holds the code that runs when someone uses one.
54
+ {{#if isGateway}}
55
+ - `src/events/` holds event handlers for the things happening in a server.
56
+ {{/if}}
57
+ - `src/bot.ts` is the config.
58
+
59
+ ## Docs
60
+
61
+ - Guide: <https://guide.seedcord.org>
62
+ - API reference: <https://docs.seedcord.org>
@@ -0,0 +1,13 @@
1
+ # Your bot token, from the Bot page of your app in the Discord Developer Portal
2
+ DISCORD_BOT_TOKEN={{ token }}
3
+ {{#unless isGateway}}
4
+
5
+ # Public key, from the General Information page of the same app
6
+ DISCORD_PUBLIC_KEY={{ publicKey }}
7
+ {{/unless}}
8
+
9
+ # Discord webhooks the framework posts error reports to. Leave empty to skip reporting.
10
+ UNKNOWN_EXCEPTION_WEBHOOK_URL=
11
+ HANDLED_EXCEPTION_WEBHOOK_URL=
12
+
13
+ ENV=development
@@ -0,0 +1,8 @@
1
+ import createConfig from '@seedcord/eslint-config';
2
+
3
+ export default createConfig({
4
+ tsconfigRootDir: import.meta.dirname,
5
+ registerDiscordjsPlugin: true,
6
+ registerSeedcordPlugin: true,
7
+ generalIgnores: ['**/seedcord-gen.d.ts']
8
+ });
@@ -0,0 +1,12 @@
1
+ node_modules/
2
+ dist/
3
+ logs/
4
+ *.log
5
+ *.tsbuildinfo
6
+ .eslintcache
7
+ .seedcord/
8
+
9
+ .env*
10
+ !.env.example
11
+
12
+ .DS_Store
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "{{ projectName }}",
3
+ "type": "module",
4
+ "version": "0.1.0",
5
+ "private": true,
6
+ "engines": {
7
+ "node": ">=24.11"
8
+ },
9
+ "scripts": {
10
+ "dev": "seedcord dev",
11
+ "build": "seedcord build",
12
+ "start": "node --enable-source-maps dist/index.mjs",
13
+ "codegen": "seedcord codegen",
14
+ "lint": "eslint 'src/**/*.ts' --cache",
15
+ "lint:fix": "eslint 'src/**/*.ts' --fix --cache",
16
+ "fmt": "prettier --write 'src/**/*.{ts,json,md}' --cache",
17
+ "tc": "tsc --noEmit"
18
+ }
19
+ }
@@ -0,0 +1,3 @@
1
+ import { PRETTIER_CONFIG } from '@seedcord/eslint-config/prettier';
2
+
3
+ export default PRETTIER_CONFIG;
@@ -0,0 +1 @@
1
+ seedcord-gen.d.ts
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from 'seedcord';
2
+
3
+ export default defineConfig({
4
+ root: './src',
5
+ instance: './bot.ts',
6
+ entry: './index.ts',
7
+ build: {
8
+ tsconfig: './tsconfig.build.json'
9
+ }
10
+ });
@@ -0,0 +1,44 @@
1
+ import { resolve } from 'node:path';
2
+
3
+ {{#if isGateway}}
4
+ import { Seedcord } from '@seedcord/gateway';
5
+ import { GatewayIntentBits{{#if partials}}, Partials{{/if}} } from 'discord.js';
6
+ {{else}}
7
+ import { Seedcord } from '@seedcord/http';
8
+ {{/if}}
9
+ import { Envapter } from 'envapt';
10
+
11
+ Envapter.baseDir = resolve(import.meta.dirname, '..');
12
+
13
+ export const seedcord = new Seedcord({
14
+ bot: {
15
+ {{#if isGateway}}
16
+ clientOptions: {
17
+ intents: [
18
+ {{#each intents}}
19
+ GatewayIntentBits.{{ this }}{{#unless @last}},{{/unless}}
20
+ {{/each}}
21
+ ]{{#if partials}},
22
+ partials: [{{#each partials}}Partials.{{ this }}{{#unless @last}}, {{/unless}}{{/each}}]{{/if}}
23
+ },
24
+ {{/if}}
25
+ interactions: {
26
+ path: resolve(import.meta.dirname, './handlers')
27
+ },
28
+ commands: {
29
+ path: resolve(import.meta.dirname, './commands')
30
+ }{{#if isGateway}},
31
+ events: {
32
+ path: resolve(import.meta.dirname, './events')
33
+ }{{/if}}
34
+ },
35
+ subscribers: {
36
+ path: null
37
+ },
38
+ botColor: '{{ botColor }}',
39
+ notifications: {
40
+ developerUsername: '{{ developerUsername }}'
41
+ }
42
+ });
43
+
44
+ export default seedcord;
@@ -0,0 +1,13 @@
1
+ import { BuilderComponent, RegisterCommand } from '{{ transportPackage }}';
2
+
3
+ @RegisterCommand('global')
4
+ export class Ping extends BuilderComponent<'command'> {
5
+ constructor() {
6
+ super('command');
7
+
8
+ this.instance
9
+ .setName('ping')
10
+ .setDescription('Check that the bot is answering')
11
+ .addBooleanOption((option) => option.setName('detailed').setDescription('Include process uptime'));
12
+ }
13
+ }
@@ -0,0 +1,18 @@
1
+ {{#if hasMessages}}
2
+ import { EventHandler, Gated, IgnoreBots, RegisterEvent } from '{{ transportPackage }}';
3
+ import { Events } from 'discord.js';
4
+
5
+ @Gated(IgnoreBots)
6
+ @RegisterEvent([Events.MessageCreate])
7
+ export class Mentioned extends EventHandler<Events.MessageCreate> {
8
+ public async execute(): Promise<void> {
9
+ const [message] = this.event;
10
+ if (!message.inGuild()) return;
11
+
12
+ // discord sends the content of a message that mentions your app without the privileged intent
13
+ if (!message.mentions.users.has(message.client.user.id)) return;
14
+
15
+ await message.reply(`hey ${message.author.displayName}`);
16
+ }
17
+ }
18
+ {{/if}}
@@ -0,0 +1,16 @@
1
+ {{#if isGateway}}
2
+ {{#unless hasMessages}}
3
+ import { EventHandler, RegisterEvent } from '{{ transportPackage }}';
4
+ import { Events } from 'discord.js';
5
+
6
+ @RegisterEvent([Events.ClientReady, { frequency: 'once' }])
7
+ export class Ready extends EventHandler<Events.ClientReady> {
8
+ public async execute(): Promise<void> {
9
+ const [client] = this.event;
10
+ const application = await client.application.fetch();
11
+
12
+ this.logger.info(`${application.name} is in ${client.guilds.cache.size} servers`);
13
+ }
14
+ }
15
+ {{/unless}}
16
+ {{/if}}
@@ -0,0 +1,15 @@
1
+ import { SlashHandler, SlashRoute, timestampFromSnowflake } from '{{ transportPackage }}';
2
+
3
+ @SlashRoute('ping')
4
+ export class Ping extends SlashHandler<'ping'> {
5
+ public async execute(): Promise<void> {
6
+ const roundtrip = Date.now() - timestampFromSnowflake(this.event.id);
7
+ const lines = ['### Pong', `Roundtrip **${roundtrip}ms**`];
8
+
9
+ if (this.options.getBoolean('detailed')) {
10
+ lines.push(`Uptime **${Math.round(process.uptime())}s**`);
11
+ }
12
+
13
+ await this.reply(lines.join('\n'));
14
+ }
15
+ }
@@ -0,0 +1,3 @@
1
+ import seedcord from './bot';
2
+
3
+ await seedcord.start();
@@ -0,0 +1,11 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "extends": "./tsconfig.json",
4
+ "compilerOptions": {
5
+ "rootDir": "./src",
6
+ "outDir": "./dist",
7
+ "noEmit": false
8
+ },
9
+ "include": ["src/**/*.ts"],
10
+ "exclude": ["node_modules", "dist"]
11
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "extends": "@seedcord/tsconfig/node",
4
+ "compilerOptions": {
5
+ "rootDir": "./",
6
+ "outDir": "./dist"
7
+ },
8
+ "include": ["src/**/*.ts", "seedcord.config.ts"],
9
+ "exclude": ["node_modules", "dist"]
10
+ }
package/dist/index.cjs DELETED
@@ -1,8 +0,0 @@
1
- Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- //#region src/index.ts
3
- /** Package version */
4
- const version = "0.0.1";
5
-
6
- //#endregion
7
- exports.version = version;
8
- //# sourceMappingURL=index.cjs.map
@@ -1 +0,0 @@
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"}
package/dist/index.d.cts DELETED
@@ -1 +0,0 @@
1
- export type * from './index.d.mts'
package/dist/index.d.mts DELETED
@@ -1,6 +0,0 @@
1
- //#region src/index.d.ts
2
- /** Package version */
3
- declare const version: string;
4
- //#endregion
5
- export { version };
6
- //# sourceMappingURL=index.d.mts.map