{"_id":"@azurioh/discord-kernel","name":"@azurioh/discord-kernel","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@azurioh/discord-kernel","version":"0.1.0","description":"Framework kernel for Discord bots: command DSL, guards, interaction routing, composed components, i18n, ports (Presenter, Logger, DatabaseConnection, Authorizer, Scheduler).","keywords":["discord","discord.js","discord-bot","framework","clean-architecture","hexagonal","typescript","i18n"],"license":"MIT","author":{"name":"Alan Cunin","url":"https://github.com/Azurioh"},"repository":{"type":"git","url":"git+https://github.com/Azurioh/discord-kernel.git"},"bugs":{"url":"https://github.com/Azurioh/discord-kernel/issues"},"homepage":"https://github.com/Azurioh/discord-kernel#readme","engines":{"node":">=22.12.0"},"publishConfig":{"access":"public"},"exports":{"./package.json":"./package.json","./errors":{"types":"./dist/errors/index.d.ts","default":"./dist/errors/index.js"},"./i18n":{"types":"./dist/i18n/index.d.ts","default":"./dist/i18n/index.js"},"./discord/components/interactive-message":{"types":"./dist/discord/components/interactive-message/index.d.ts","default":"./dist/discord/components/interactive-message/index.js"},"./discord/components/paginator":{"types":"./dist/discord/components/paginator/index.d.ts","default":"./dist/discord/components/paginator/index.js"},"./discord/components/settings-editor":{"types":"./dist/discord/components/settings-editor/index.d.ts","default":"./dist/discord/components/settings-editor/index.js"},"./*":{"types":"./dist/*.d.ts","default":"./dist/*.js"}},"scripts":{"build":"tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json","typecheck":"tsc -p tsconfig.json","lint":"biome ci","format":"biome check --write","knip":"knip","test":"vitest run","test:watch":"vitest","prepublishOnly":"npm run build"},"dependencies":{"node-cron":"4.6.0"},"peerDependencies":{"discord.js":"^14.27.0"},"devDependencies":{"@biomejs/biome":"2.5.7","@types/node":"24.13.3","discord.js":"14.27.0","knip":"^6.15.0","tsc-alias":"^1.8.16","typescript":"^5.9.3","vite-tsconfig-paths":"^6.1.1","vitest":"^4.1.8"},"packageManager":"pnpm@11.20.0","gitHead":"b914461f3be0948f00fcffc54753aa6a60102291","_id":"@azurioh/discord-kernel@0.1.0","_nodeVersion":"24.19.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-2LZFHjYEEO67DYu+YdeEQBJ22eduwGUjbB5LGE+AIleKahWIAKsmYbdi1PS9NUuPeRjEXXsNmEapOqC5/2MrMQ==","shasum":"037a5d745b2eb1a05a15fc2753dbae4f00af48ee","tarball":"https://registry.npmjs.org/@azurioh/discord-kernel/-/discord-kernel-0.1.0.tgz","fileCount":373,"unpackedSize":1005945,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBk9O2RxfhGXLSwcvU5PgU8qzjz4t3oR9d9LdSDXGa3zAiArIV21n0KN6BM3ASVHPPEjXo73E2QEweLH1gFBZmj4/g=="}]},"_npmUser":{"name":"azurioh","email":"alan.cunin@epitech.eu"},"directories":{},"maintainers":[{"name":"azurioh","email":"alan.cunin@epitech.eu"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/discord-kernel_0.1.0_1787955558196_0.2791992317604186"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-28T22:19:17.961Z","0.1.0":"2026-08-28T22:19:18.384Z","modified":"2026-08-28T22:19:18.650Z"},"maintainers":[{"name":"azurioh","email":"alan.cunin@epitech.eu"}],"description":"Framework kernel for Discord bots: command DSL, guards, interaction routing, composed components, i18n, ports (Presenter, Logger, DatabaseConnection, Authorizer, Scheduler).","homepage":"https://github.com/Azurioh/discord-kernel#readme","keywords":["discord","discord.js","discord-bot","framework","clean-architecture","hexagonal","typescript","i18n"],"repository":{"type":"git","url":"git+https://github.com/Azurioh/discord-kernel.git"},"author":{"name":"Alan Cunin","url":"https://github.com/Azurioh"},"bugs":{"url":"https://github.com/Azurioh/discord-kernel/issues"},"license":"MIT","readme":"# @azurioh/discord-kernel\n\nThe framework half of a Discord bot, without the bot: a command DSL, guards,\ninteraction routing, composed components, localisation, and the ports an\napplication implements. It knows discord.js and nothing else — no database, no\nlogger implementation, no opinion about what your bot does.\n\nBuilt for Clean Architecture with vertically-sliced feature modules: the kernel\nis the innermost ring, and the fact that it is a package rather than a folder is\nwhat enforces that — an outer ring simply is not in its dependency graph.\n\n```bash\npnpm add @azurioh/discord-kernel discord.js\n```\n\n`discord.js` is a **peer dependency**, never a dependency: two copies of the\nlibrary in one tree would break every `instanceof` the gateway relies on.\n\n## What is in it\n\n| Area | What it gives you |\n| ---- | ----------------- |\n| `discord/command/` | `createCommand` (flat or grouped), typed options, guards (`allOf`/`anyOf`, permissions, roles, cooldowns), the per-interaction `Context`, autocomplete, the `CommandRouter` |\n| `discord/interaction/` | `createButton`, `createModal`, the four typed select menus (`createStringSelect`, `createChannelSelect`, `createRoleSelect`, `createUserSelect`), the `InteractionRouter`/`InteractionDispatcher` seam |\n| `discord/components/` | `ComponentRouter` for persistent `customId` routing, and collector-backed screens: `paginator`, `interactive-message`, `settings-editor` |\n| `discord/events/` | `createEvent` and the `EventRouter` — the one place `client.on` is called |\n| `discord/ui/` | Embeds with Discord's size limits handled, `createCard` containers, a configurable palette, a colour-input parser |\n| `i18n/` | Catalogs (`{ en, fr? }`, `en` mandatory), a registry that fails the boot on a duplicate key, per-interaction locale resolution |\n| `authz/` | An `Authorizer` port with `viewer`/`editor` grants and a `requireLevel` guard |\n| `errors/` | `BusinessError` and friends, carrying an optional translation key beside the English source |\n| `scheduler/` | A `Scheduler` port and a node-cron implementation |\n| Ports | `Logger`, `DatabaseConnection`, `Presenter`, `Clock`, `ChannelExporter` — declared here, implemented by your app |\n\nEvery path is imported directly; there is no root barrel:\n\n```ts\nimport { createCommand } from \"@azurioh/discord-kernel/discord/command/create-command\";\nimport type { Logger } from \"@azurioh/discord-kernel/logger\";\nimport { type Catalog, createTranslator } from \"@azurioh/discord-kernel/i18n\";\n```\n\n## What is deliberately not in it\n\n- **A database.** `DatabaseConnection` is a lifecycle port — connect, close — and\n  nothing more. Query APIs differ too much between engines to abstract usefully,\n  so an adapter exposes its own and your repositories are the only code that\n  touches it.\n- **A logger.** `Logger` is a port; pino, Sentry or `console` live in your app.\n- **A configuration shape.** The kernel ships env-reading primitives\n  (`requireEnv`, `enumEnv`, …); which keys exist is your composition root's call.\n- **A palette.** Embeds render in Discord's blurple until you say otherwise, so a\n  bot never starts out wearing someone else's identity.\n\n## Making it yours\n\nTwo things are global by nature — a bot has one look, decided once — and are set\nfrom the composition root before any module is constructed:\n\n```ts\nimport { configureEmbedColors } from \"@azurioh/discord-kernel/discord/ui/colors\";\nimport { registerColorAliases } from \"@azurioh/discord-kernel/discord/ui/color-input\";\n\nconfigureEmbedColors({ brand: 0xf3c909 });\nregisterColorAliases({ gold: \"#f3c909\", or: \"#f3c909\" });\n```\n\nEverything else is injected: your modules are factories receiving a container\nyou define, so nothing in the kernel is reachable as a singleton.\n\n## Requirements\n\nNode 22.12+, discord.js 14.27+, TypeScript 5.9. The published build is\nCommonJS with declaration files, resolved through explicit subpath `exports`.\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-1059cae98800859846a79001e90487ae"}