Compare commits

..

49 Commits

Author SHA1 Message Date
github-actions[bot]
d381ff568e chore(main): release 2.6.0 (#248)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-09 16:18:06 -06:00
Jacob Nguyen
6db5c71506 chore: update workflow 2023-03-09 16:15:29 -06:00
github-actions[bot]
507c9e7939 style: pretty please (#247)
Co-authored-by: jacoobes <jacoobes@users.noreply.github.com>
2023-03-09 16:11:29 -06:00
Jacob Nguyen
09610d0501 refactor: eventhandlers (#246)
* refactor:import

* feat: save progress

* feat:progress

* refactor: event handlers

* fix: merge all subscriptions into event handler

* fix: remove duplicate minify key

* fix: leftover this

* docs: jsdoc

* chore: clean pnpm

---------

Co-authored-by: jacoobes <jacobnguyend@gmail.com>
2023-03-09 16:09:35 -06:00
github-actions[bot]
0862bf92d0 style: pretty please (#244)
Co-authored-by: renovate[bot] <renovate[bot]@users.noreply.github.com>
2023-03-03 09:22:02 -06:00
renovate[bot]
62162f6b8c chore(deps): lock file maintenance (#240)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Jacob Nguyen <76754747+jacoobes@users.noreply.github.com>
2023-03-02 19:03:02 -06:00
renovate[bot]
eb501db09a chore(deps): update dependency @typescript-eslint/eslint-plugin to v5.54.0 (#243)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-02 19:01:18 -06:00
renovate[bot]
964848a4e2 chore(deps): update dependency @typescript-eslint/parser to v5.54.0 (#194)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Jacob Nguyen <76754747+jacoobes@users.noreply.github.com>
2023-03-02 18:48:56 -06:00
renovate[bot]
78dead1b49 chore(deps): update pnpm to v7.28.0 (#239)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-02 18:48:32 -06:00
renovate[bot]
39e6d6d2f9 chore(deps): update dependency @typescript-eslint/eslint-plugin to v5.52.0 (#238)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-20 00:30:10 -06:00
renovate[bot]
5aff57ed6d chore(deps): update dependency typescript to v4.9.5 (#208)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-20 00:27:36 -06:00
github-actions[bot]
4095471346 style: pretty please (#237)
Co-authored-by: jacoobes <jacoobes@users.noreply.github.com>
2023-02-17 15:47:33 -06:00
Jacob Nguyen
f7b9c52df1 Merge remote-tracking branch 'origin/main' 2023-02-17 15:40:54 -06:00
Jacob Nguyen
d20d01524b feat: adding pure annotation for better tree shaking 2023-02-17 15:40:32 -06:00
renovate[bot]
5684c060bc chore(deps): lock file maintenance (#225)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Jacob Nguyen <76754747+jacoobes@users.noreply.github.com>
2023-02-17 13:13:15 -06:00
github-actions[bot]
ca8b31f280 chore(main): release 2.5.3 (#235)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-16 11:11:32 -06:00
jacoobes
ce9a0831a6 chore: release 2.5.3
Release-As: 2.5.3
2023-02-16 11:09:46 -06:00
jacoobes
3a32968a17 chore: bump version 2023-02-16 10:57:38 -06:00
github-actions[bot]
e549f8bc3e chore(main): release 2.5.2 (#234)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-16 10:52:14 -06:00
jacoobes
3ab73459ad bump version 2023-02-16 10:49:02 -06:00
jacoobes
16af2e996d chore: minifiy build output 2023-02-16 10:44:38 -06:00
Jacob Nguyen
4f9a842b0e update ci 2023-02-15 21:31:18 -06:00
Jacob Nguyen
5dfd1a1fc1 Update README.md 2023-02-15 21:28:48 -06:00
Jacob Nguyen
c45a10c950 Update README.md 2023-02-15 21:28:25 -06:00
Jacob Nguyen
b45ba34f3c Update README.md 2023-02-15 18:22:23 -06:00
Jacob Nguyen
facee79c90 revert: version 2023-02-14 17:54:31 -06:00
Jacob Nguyen
306eee071d chore: bump dependencies 2023-02-14 17:52:23 -06:00
Jacob Nguyen
00d55208a0 Merge remote-tracking branch 'origin/main' 2023-02-14 17:42:26 -06:00
Jacob Nguyen
49fad801a5 chore: bump dependencies 2023-02-14 17:41:54 -06:00
Neo
c9f44ce72b docs: changed name of Benzo-Fury's Bot (#226) 2023-02-13 11:46:28 -06:00
Jacob Nguyen
a9a2528faf Update README.md 2023-02-12 17:07:51 -06:00
github-actions[bot]
529edb7da5 style: pretty please (#224)
Co-authored-by: jacoobes <jacoobes@users.noreply.github.com>
2023-02-12 12:59:34 -06:00
github-actions[bot]
f236dc05e2 chore(main): release 2.5.1 (#222)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-02-12 12:58:00 -06:00
Jacob Nguyen
c78936a225 chore: release 2.5.1
Release-As: 2.5.1
2023-02-12 12:54:18 -06:00
Jacob Nguyen
1860b898f3 fix: autocomplete 2023-02-12 12:51:49 -06:00
renovate[bot]
fd10772a9b chore(deps): lock file maintenance (#213)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-12 11:47:37 -06:00
renovate[bot]
cd36bd8a47 chore(deps): update dependency @typescript-eslint/eslint-plugin to v5.51.0 (#187)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-12 11:33:00 -06:00
renovate[bot]
dda7f41231 chore(deps): update dependency prettier to v2.8.4 (#215)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Jacob Nguyen <76754747+jacoobes@users.noreply.github.com>
2023-02-12 11:29:38 -06:00
renovate[bot]
371a57194c chore(deps): update pnpm to v7.27.0 (#216)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-12 11:28:54 -06:00
Neo
bfcc160a39 docs: change protectors WIP mark to its name (#214)
Idk I was bored and saw this was different to mine. Change mine instead or just close this pr, idm.
2023-02-07 20:16:23 -06:00
Neo
86fa531eb6 docs: Adding the WIP to my bot (#212)
feat: Adding the WIP to my bot
2023-02-04 10:37:03 -06:00
Gary
58052e94cb docs: add my bot to the ReadMe (#211) 2023-02-04 01:38:07 -06:00
Neo
96f4281121 feat: Adding my bot to readme (#210) 2023-02-03 23:55:26 -06:00
Jacob Nguyen
f9ae7c003b docs: clarify example 2023-02-03 23:46:19 -06:00
Jacob Nguyen
ec211d5a8d docs: do some updating on readme 2023-02-03 23:14:57 -06:00
github-actions[bot]
3faf83bbf7 style: pretty please (#209)
Co-authored-by: jacoobes <jacoobes@users.noreply.github.com>
2023-02-03 23:04:13 -06:00
renovate[bot]
8eed099503 chore(deps): lock file maintenance (#183)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-03 23:00:46 -06:00
renovate[bot]
e2874be4e7 chore(deps): update pnpm to v7.26.3 (#203)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-03 22:56:17 -06:00
github-actions[bot]
1d6751a9cd style: pretty please (#207)
Co-authored-by: jacoobes <jacoobes@users.noreply.github.com>
2023-01-30 12:35:37 -06:00
26 changed files with 2821 additions and 2171 deletions

View File

@@ -5,6 +5,8 @@ on:
push:
branches:
main
paths:
- '**.ts'
pull_request_target:
branches:
main

View File

@@ -1,30 +1,23 @@
name: NPM / Publish
on:
release:
types: [created]
workflow_dispatch:
jobs:
build:
test-and-publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
- run: npm ci
- run: npm test
publish-npm:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
node-version: 17
- uses: pnpm/action-setup@v2
with:
node-version: 16
registry-url: https://registry.npmjs.org/
- run: npm ci
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.npm_token}}
run_install: |
- recursive: true
args: [--strict-peer-dependencies]
- run: pnpm install
- run: pnpm build
- uses: JS-DevTools/npm-publish@v1
with:
token: ${{ secrets.NPM_TOKEN }}
access: "public"

View File

@@ -1,5 +1,44 @@
# Changelog
## [2.6.0](https://github.com/sern-handler/handler/compare/v2.5.3...v2.6.0) (2023-03-09)
### Features
* adding pure annotation for better tree shaking ([d20d015](https://github.com/sern-handler/handler/commit/d20d01524b872549da501e21feec147ab204f397))
## [2.5.3](https://github.com/sern-handler/handler/compare/v2.5.2...v2.5.3) (2023-02-16)
### Miscellaneous Chores
* release 2.5.3 ([ce9a083](https://github.com/sern-handler/handler/commit/ce9a0831a6e47dd38648f34653f0bd89b1d2e48e))
## [2.5.2](https://github.com/sern-handler/handler/compare/v2.5.1...v2.5.2) (2023-02-16)
### Reverts
* version ([facee79](https://github.com/sern-handler/handler/commit/facee79c904ad663d3c57ce56fb825419fcc12f9))
## [2.5.1](https://github.com/sern-handler/handler/compare/v2.5.0...v2.5.1) (2023-02-12)
### Features
* Adding my bot to readme ([#210](https://github.com/sern-handler/handler/issues/210)) ([96f4281](https://github.com/sern-handler/handler/commit/96f42811218e4898a47e75a8138ccd452ae2c5c2))
* Adding the WIP to my bot ([86fa531](https://github.com/sern-handler/handler/commit/86fa531eb620d2ac649bad6decb29d5c55a25445))
### Bug Fixes
* autocomplete ([1860b89](https://github.com/sern-handler/handler/commit/1860b898f3a231840e2a8b781e007ef9d6f587a4))
### Miscellaneous Chores
* release 2.5.1 ([c78936a](https://github.com/sern-handler/handler/commit/c78936a22574da4af71826f5b5f72f354a4eb06a))
## [2.5.0](https://github.com/sern-handler/handler/compare/v2.1.1...v2.5.0) (2023-01-30)

View File

@@ -3,7 +3,7 @@
</div>
<h1 align="center">Handlers. Redefined.</h1>
<h4 align="center">A customizable, batteries-included, powerful discord.js framework to streamline bot development.</h4>
<h4 align="center">A complete, customizable, typesafe, & reactive framework for discord bots</h4>
<div align="center" styles="margin-top: 10px">
<img src="https://img.shields.io/badge/open-source-brightgreen" />
@@ -14,20 +14,6 @@
<img alt="Lines of code" src="https://img.shields.io/badge/total%20lines-2k-blue" />
</div>
## 📜 Installation
```sh
npm install @sern/handler
```
```sh
yarn add @sern/handler
```
```sh
pnpm add @sern/handler
```
## Why?
- Most handlers don't support discord.js 14.7+
- Customizable commands
@@ -43,6 +29,20 @@ pnpm add @sern/handler
* ESM, CommonJS and TypeScript support
* A powerful CLI and awesome community-made plugins
## 📜 Installation
```sh
npm install @sern/handler
```
```sh
yarn add @sern/handler
```
```sh
pnpm add @sern/handler
```
## 👶 Basic Usage
#### ` index.js (CommonJS)`
@@ -52,10 +52,7 @@ pnpm add @sern/handler
const { Client, GatewayIntentBits } = require('discord.js');
// Import Sern namespace
const { Sern } = require('@sern/handler');
// Our configuration file
const { defaultPrefix, token } = require('./config.json');
const { Sern, single } = require('@sern/handler');
const client = new Client({
intents: [
@@ -66,8 +63,8 @@ const client = new Client({
});
export const useContainer = Sern.makeDependencies({
build: root => root
.add({ '@sern/client': single(client) })
.add({ '@sern/logger': single(new DefaultLogging()) })
.add({ '@sern/client': single(() => client) })
.upsert({ '@sern/logger': single(() => new DefaultLogging()) })
});
//View docs for all options
@@ -80,7 +77,7 @@ Sern.init({
}
});
client.login(token);
client.login("YOUR_BOT_TOKEN_HERE");
```
#### ` ping.js (CommonJS)`
@@ -89,16 +86,21 @@ client.login(token);
const { CommandType, commandModule } = require('@sern/handler');
exports.default = commandModule({
name: 'ping',
description: 'A ping pong command',
type: CommandType.Slash,
description: 'A ping pong command',
execute(ctx) {
ctx.reply('pong!');
}
});
```
See our [templates](https://github.com/sern-handler/templates) for TypeScript examples and more.
## 🤖 Bots Using sern
- [Community Bot](https://github.com/sern-handler/sern-community), the community bot for our [discord server](https://sern.dev/discord).
- [Vinci](https://github.com/SrIzan10/vinci), the bot for Mara Turing.
- [Bask](https://github.com/baskbotml/bask), Listen your favorite artists on Discord.
- [ava](https://github.com/SrIzan10/ava), A discord bot that plays KNGI and Gensokyo Radio.
- [ALMA (WIP)](https://github.com/Benzo-Fury/ALMA), Using AI to unleash the power in your server.
- [Protector (WIP)](https://github.com/needhamgary/Protector), Just a simple bot to help enhance a private minecraft server.
## 💻 CLI
@@ -115,6 +117,4 @@ It is **highly encouraged** to use the [command line interface](https://github.c
- Pull up on [issues](https://github.com/sern-handler/handler/issues) and report bugs
- All kinds of contributions are welcomed.
## 🚈 Roadmap
You can check our [roadmap](https://github.com/sern-handler/roadmap) to see what's going to be added or patched in the future.

View File

@@ -1,7 +1,7 @@
{
"name": "@sern/handler",
"packageManager": "pnpm@7.25.0",
"version": "2.5.0",
"packageManager": "pnpm@7.28.0",
"version": "2.6.0",
"description": "A customizable, batteries-included, powerful discord.js framework to automate and streamline bot development.",
"main": "dist/cjs/index.cjs",
"module": "dist/esm/index.mjs",
@@ -13,7 +13,7 @@
}
},
"scripts": {
"watch": "tsup --watch --dts",
"watch": "tsup --dts --watch",
"clean-modules": "rimraf node_modules/ && npm install",
"lint": "eslint src/**/*.ts",
"format": "eslint src/**/*.ts --fix",
@@ -34,18 +34,18 @@
"license": "MIT",
"dependencies": {
"iti": "^0.6.0",
"rxjs": "^7.5.6",
"ts-pattern": "^4.0.6",
"rxjs": "^7.8.0",
"ts-pattern": "^4.1.4",
"ts-results-es": "^3.5.0"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "5.47.1",
"@typescript-eslint/parser": "5.48.0",
"discord.js": ">= ^14.7.x",
"@typescript-eslint/eslint-plugin": "5.54.0",
"@typescript-eslint/parser": "5.54.0",
"discord.js": "^14.7.1",
"eslint": "8.30.0",
"prettier": "2.8.3",
"tsup": "^6.1.3",
"typescript": "4.9.4"
"prettier": "2.8.4",
"tsup": "^6.6.3",
"typescript": "4.9.5"
},
"repository": {
"type": "git",

4157
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@ import type { Processed } from '../../types/handler';
export interface ModuleManager {
get<T extends CommandType>(
strat: (ms: ModuleStore) => Processed<CommandModuleDefs[T]> | undefined,
): CommandModuleDefs[T] | undefined;
): Processed<CommandModuleDefs[T]> | undefined;
set(strat: (ms: ModuleStore) => void): void;
}

View File

@@ -1,2 +1,2 @@
export { single, transient, many } from './lifetimeFunctions';
export { useContainerRaw } from './provider';
export { useContainerRaw } from './provider';

View File

@@ -1,47 +1,57 @@
import { _const } from '../utilities/functions';
type NotFunction = string | number | boolean | null | undefined | bigint |
readonly any[] | { apply?: never, [k: string]: any } |
{ call?: never, [k: string]: any };
type NotFunction =
| string
| number
| boolean
| null
| undefined
| bigint
| readonly any[]
| { apply?: never; [k: string]: any }
| { call?: never; [k: string]: any };
/**
* @deprecated
* @param cb
*/
export function single<T extends NotFunction>(cb: T) : () => T;
export function single<T extends NotFunction>(cb: T): () => T;
/**
* New signature
* @param cb
*/
export function single<T extends () => unknown>(cb: T) : T;
export function single<T extends () => unknown>(cb: T): T;
/**
* @__PURE__
* Please note that on intellij, the deprecation is for all signatures, which is unintended behavior (and
* very annoying).
* For future versions, ensure that single is being passed as a **callback!!**
* @param cb
*/
export function single<T>(cb: T) {
if(typeof cb === 'function') return cb;
return () => cb;
if (typeof cb === 'function') return cb;
return () => cb;
}
/**
* @deprecated
* @param cb
* Deprecated signature
*/
export function transient<T extends NotFunction>(cb: T) : () => () => T
export function transient<T extends () => () => unknown>(cb: T) : T;
export function transient<T extends NotFunction>(cb: T): () => () => T;
export function transient<T extends () => () => unknown>(cb: T): T;
/**
* @__PURE__
* Following iti's singleton and transient implementation,
* use transient if you want a new dependency every time your container getter is called
* @param cb
*/
export function transient<T>(cb: (() => () => T) | T) {
if(typeof cb !== 'function') return () => () => cb;
if (typeof cb !== 'function') return () => () => cb;
return cb;
}
/**
* @__PURE__
* @deprecated
* @param value
* Please use the transient function instead

View File

@@ -1,12 +1,11 @@
import type { Container } from 'iti';
import { SernError } from '../structures/errors';
import type { Dependencies, DependencyConfiguration, MapDeps } from '../../types/handler';
import SernEmitter from '../sernEmitter';
import { DefaultErrorHandling, DefaultLogging, DefaultModuleManager } from '../contracts';
import { ModuleStore } from '../structures/moduleStore';
import { Result } from 'ts-results-es';
import { BehaviorSubject } from 'rxjs';
import { createContainer } from 'iti';
import { type Wrapper, ModuleStore, SernError } from '../structures';
export const containerSubject = new BehaviorSubject(defaultContainer());
@@ -20,20 +19,18 @@ export function composeRoot<T extends Dependencies>(conf: DependencyConfiguratio
//Get the current container. This should have no client or possible logger yet.
const currentContainer = containerSubject.getValue();
const excludeLogger = conf.exclude?.has('@sern/logger');
if(!excludeLogger) {
if (!excludeLogger) {
currentContainer.add({
'@sern/logger' : () => new DefaultLogging()
'@sern/logger': () => new DefaultLogging(),
});
}
//Build the container based on the callback provided by the user
const container = conf.build(currentContainer);
//Check if the built container contains @sern/client or throw
// a runtime exception
Result
.wrap(() => container.get('@sern/client'))
.expect(SernError.MissingRequired);
Result.wrap(() => container.get('@sern/client')).expect(SernError.MissingRequired);
if(!excludeLogger) {
if (!excludeLogger) {
container.get('@sern/logger')?.info({ message: 'All dependencies loaded successfully.' });
}
//I'm sorry little one
@@ -61,12 +58,29 @@ export function useContainerRaw<T extends Dependencies>() {
*/
function defaultContainer() {
return createContainer()
.add({ '@sern/errors': () => new DefaultErrorHandling()})
.add({ '@sern/store' : () => new ModuleStore()})
.add(ctx => {
return {
'@sern/modules': () => new DefaultModuleManager(ctx['@sern/store'])
};
.add({ '@sern/errors': () => new DefaultErrorHandling() })
.add({ '@sern/store': () => new ModuleStore() })
.add(ctx => {
return {
'@sern/modules': () => new DefaultModuleManager(ctx['@sern/store']),
};
})
.add({ '@sern/emitter': () => new SernEmitter()}) as Container<Omit<Dependencies, '@sern/client' | '@sern/logger'>, {}>;
}
.add({ '@sern/emitter': () => new SernEmitter() }) as Container<
Omit<Dependencies, '@sern/client' | '@sern/logger'>,
{}
>;
}
export function makeFetcher(wrapper: Wrapper) {
const requiredDependencyKeys = [
'@sern/emitter',
'@sern/client',
'@sern/errors',
'@sern/logger',
] as ['@sern/emitter', '@sern/client', '@sern/errors', '@sern/logger'];
return <Keys extends (keyof Dependencies)[]>(otherKeys: [...Keys]) =>
wrapper.containerConfig.get(...requiredDependencyKeys, ...otherKeys) as MapDeps<
Dependencies,
[...typeof requiredDependencyKeys, ...Keys]
>;
}

View File

@@ -54,7 +54,7 @@ export function dispatchAutocomplete(
const option = treeSearch(interaction, module.options);
if (option !== undefined) {
return {
module,
module: option.command as Processed<Module>, //autocomplete is not a true "module" warning cast!
args: [interaction],
};
}

View File

@@ -1,34 +0,0 @@
import type Wrapper from '../structures/wrapper';
import { Subject, type Observable } from 'rxjs';
import type { EventEmitter } from 'events';
import type SernEmitter from '../sernEmitter';
import type { ErrorHandling, Logging, ModuleManager } from '../contracts';
/**
* why did I make this, definitely going to be changed in the future
*/
export abstract class EventsHandler<T> {
protected payloadSubject = new Subject<T>();
protected abstract discordEvent: Observable<unknown>;
protected client: EventEmitter;
protected emitter: SernEmitter;
protected crashHandler: ErrorHandling;
protected logger?: Logging;
protected modules: ModuleManager;
protected constructor({ containerConfig }: Wrapper) {
const [client, emitter, crash, modules, logger] = containerConfig.get(
'@sern/client',
'@sern/emitter',
'@sern/errors',
'@sern/modules',
'@sern/logger',
);
this.logger = logger as Logging | undefined;
this.modules = modules as ModuleManager;
this.client = client as EventEmitter;
this.emitter = emitter as SernEmitter;
this.crashHandler = crash as ErrorHandling;
}
protected abstract init(): void;
protected abstract setState(state: T): void;
}

View File

@@ -1,135 +1,122 @@
import type { Interaction } from 'discord.js';
import { catchError, concatMap, finalize, fromEvent, map, Observable } from 'rxjs';
import type Wrapper from '../structures/wrapper';
import { EventsHandler } from './eventsHandler';
import { CommandType, SernError, type ModuleStore } from '../structures';
import {
catchError,
concatMap,
EMPTY,
filter,
finalize,
fromEvent,
map,
Observable,
of,
OperatorFunction,
pipe,
} from 'rxjs';
import { CommandType, type ModuleStore, SernError } from '../structures';
import { match, P } from 'ts-pattern';
import { contextArgs, interactionArg, dispatchAutocomplete, dispatchCommand } from './dispatchers';
import { contextArgs, dispatchAutocomplete, dispatchCommand, interactionArg } from './dispatchers';
import { executeModule, makeModuleExecutor } from './observableHandling';
import type { CommandModule } from '../../types/module';
import { handleError } from '../contracts/errorHandling';
import { ErrorHandling, handleError } from '../contracts/errorHandling';
import SernEmitter from '../sernEmitter';
import type { Processed } from '../../types/handler';
import { useContainerRaw } from '../dependencies';
import type { Logging, ModuleManager } from '../contracts';
import type { EventEmitter } from 'node:events';
export default class InteractionHandler extends EventsHandler<{
function makeInteractionProcessor(
modules: ModuleManager,
): OperatorFunction<Interaction, { module: Processed<CommandModule>; event: Interaction }> {
const get = (cb: (ms: ModuleStore) => Processed<CommandModule> | undefined) => {
return modules.get(cb);
};
return pipe(
concatMap(event => {
if (event.isMessageComponent()) {
const module = get(ms =>
ms.InteractionHandlers[event.componentType].get(event.customId),
);
return of({ module, event });
} else if (event.isCommand() || event.isAutocomplete()) {
const module = get(
ms =>
/**
* try to fetch from ApplicationCommands, if nothing, try BothCommands
* exists on the API but not sern
*/
ms.ApplicationCommands[event.commandType].get(event.commandName) ??
ms.BothCommands.get(event.commandName),
);
return of({ module, event });
} else if (event.isModalSubmit()) {
const module = get(ms => ms.ModalSubmit.get(event.customId));
return of({ module, event });
} else return EMPTY;
}),
filter(m => m.module !== undefined),
) as OperatorFunction<Interaction, { module: Processed<CommandModule>; event: Interaction }>;
}
export function makeInteractionCreate([s, client, err, log, modules]: [
SernEmitter,
EventEmitter,
ErrorHandling,
Logging | undefined,
ModuleManager,
]) {
//map. If nothing again,this means a slash command
const interactionStream$ = fromEvent(client, 'interactionCreate') as Observable<Interaction>;
const interactionProcessor = makeInteractionProcessor(modules);
return interactionStream$
.pipe(
interactionProcessor,
map(createDispatcher),
makeModuleExecutor(module => {
s.emit('module.activate', SernEmitter.failure(module, SernError.PluginFailure));
}),
concatMap(module => executeModule(s, module)),
catchError(handleError(err, log)),
finalize(() => {
log?.info({
message: 'interactionCreate stream closed or reached end of lifetime',
});
useContainerRaw()
?.disposeAll()
.then(() => log?.info({ message: 'Cleaning container and crashing' }));
}),
)
.subscribe();
}
function createDispatcher({
module,
event,
}: {
event: Interaction;
module: Processed<CommandModule>;
}> {
protected override discordEvent: Observable<Interaction>;
constructor(wrapper: Wrapper) {
super(wrapper);
this.discordEvent = <Observable<Interaction>>fromEvent(this.client, 'interactionCreate');
this.init();
this.payloadSubject
.pipe(
map(this.createDispatcher),
makeModuleExecutor(module => {
this.emitter.emit(
'module.activate',
SernEmitter.failure(module, SernError.PluginFailure),
);
}),
concatMap(payload => executeModule(this.emitter, payload)),
catchError(handleError(this.crashHandler, this.logger)),
finalize(() => {
this.logger?.info({ message: 'interactionCreate stream closed or reached end of lifetime'});
useContainerRaw()
?.disposeAll()
.then(() => {
this.logger?.info({ message: 'Cleaning container and crashing' });
});
})
)
.subscribe();
}
override init() {
const get = (cb: (ms: ModuleStore) => Processed<CommandModule> | undefined) => {
return this.modules.get(cb);
};
/**
* Module retrieval:
* ModuleStores are mapped by Discord API values and modules mapped
* by customId or command name.
*/
this.discordEvent.subscribe({
next: event => {
if (event.isMessageComponent()) {
const module = get(ms =>
ms.InteractionHandlers[event.componentType].get(event.customId),
);
this.setState({ event, module });
} else if (event.isCommand() || event.isAutocomplete()) {
const module = get(
ms =>
/**
* try to fetch from ApplicationCommands, if nothing, try BothCommands
* map. If nothing again,this means a slash command
* exists on the API but not sern
*/
ms.ApplicationCommands[event.commandType].get(event.commandName) ??
ms.BothCommands.get(event.commandName),
);
this.setState({ event, module });
} else if (event.isModalSubmit()) {
const module = get(ms => ms.ModalSubmit.get(event.customId));
this.setState({ event, module });
}) {
return (
match(module)
.with({ type: CommandType.Text }, () => {
throw Error(SernError.MismatchEvent);
})
//P.union = either CommandType.Slash or CommandType.Both
.with({ type: P.union(CommandType.Slash, CommandType.Both) }, module => {
if (event.isAutocomplete()) {
/**
* Autocomplete is a special case that
* must be handled separately, since it's
* too different from regular command modules
*/
return dispatchAutocomplete(module, event);
} else {
throw Error('This interaction is not supported yet');
return dispatchCommand(module, contextArgs(event));
}
},
error: reason => {
this.emitter.emit('error', SernEmitter.failure(undefined, reason));
},
});
}
protected setState(state: { event: Interaction; module: CommandModule | undefined }): void {
if (state.module === undefined) {
this.emitter.emit(
'warning',
SernEmitter.warning('Found no module for this interaction'),
);
} else {
//if statement above checks already, safe cast
this.payloadSubject.next(
state as { event: Interaction; module: Processed<CommandModule> },
);
}
}
protected createDispatcher({
module,
event,
}: {
event: Interaction;
module: Processed<CommandModule>;
}) {
return (
match(module)
.with({ type: CommandType.Text }, () =>
this.crashHandler.crash(Error(SernError.MismatchEvent)),
)
//P.union = either CommandType.Slash or CommandType.Both
.with({ type: P.union(CommandType.Slash, CommandType.Both) }, module => {
if (event.isAutocomplete()) {
/**
* Autocomplete is a special case that
* must be handled separately, since it's
* too different from regular command modules
*/
return dispatchAutocomplete(module, event);
} else {
return dispatchCommand(module, contextArgs(event));
}
})
/**
* Every other command module takes a one argument parameter, its corresponding interaction
* this makes this usage safe
*/
.otherwise(mod => dispatchCommand(mod, interactionArg(event)))
);
}
})
/**
* Every other command module takes a one argument parameter, its corresponding interaction
* this makes this usage safe
*/
.otherwise(mod => dispatchCommand(mod, interactionArg(event)))
);
}

View File

@@ -1,82 +1,79 @@
import { EventsHandler } from './eventsHandler';
import { catchError, concatMap, EMPTY, finalize, fromEvent, map, Observable, of } from 'rxjs';
import { type Wrapper, type ModuleStore, SernError } from '../structures';
import { catchError, concatMap, EMPTY, finalize, fromEvent, map, of, pipe } from 'rxjs';
import { type ModuleStore, SernError } from '../structures';
import type { Message } from 'discord.js';
import { executeModule, ignoreNonBot, makeModuleExecutor } from './observableHandling';
import { fmt } from '../utilities/messageHelpers';
import type { CommandModule, Module, TextCommand } from '../../types/module';
import { handleError } from '../contracts/errorHandling';
import type { CommandModule, TextCommand } from '../../types/module';
import { ErrorHandling, handleError } from '../contracts/errorHandling';
import { contextArgs, dispatchCommand } from './dispatchers';
import SernEmitter from '../sernEmitter';
import type { Processed } from '../../types/handler';
import { useContainerRaw } from '../dependencies';
import type { Logging, ModuleManager } from '../contracts';
import type { EventEmitter } from 'node:events';
export default class MessageHandler extends EventsHandler<{
module: Processed<Module>;
args: unknown[];
}> {
protected discordEvent: Observable<Message>;
/**
* An operator function that processes a message to fetch a command module and prepares context payload.
* @param defaultPrefix
* @param get
*/
const createMessageProcessor = (
defaultPrefix: string,
get: (
cb: (ms: ModuleStore) => Processed<CommandModule> | undefined,
) => CommandModule | undefined,
) =>
pipe(
ignoreNonBot(defaultPrefix),
//This concatMap checks if module is undefined, and if it is, do not continue.
// Synonymous to filterMap, but I haven't thought of a generic implementation for filterMap yet
concatMap(message => {
const [prefix, ...rest] = fmt(message, defaultPrefix);
const module = get(ms => ms.TextCommands.get(prefix) ?? ms.BothCommands.get(prefix));
if (module === undefined) {
return EMPTY;
}
const payload = {
args: contextArgs(message, rest),
module,
};
return of(payload);
}),
map(({ args, module }) => dispatchCommand(module as Processed<TextCommand>, args)),
);
public constructor(protected wrapper: Wrapper) {
super(wrapper);
this.discordEvent = <Observable<Message>>fromEvent(this.client, 'messageCreate');
this.init();
this.payloadSubject
.pipe(
makeModuleExecutor(module => {
this.emitter.emit(
'module.activate',
SernEmitter.failure(module, SernError.PluginFailure),
);
}),
concatMap(payload => executeModule(this.emitter, payload)),
catchError(handleError(this.crashHandler, this.logger)),
finalize(() => {
this.logger?.info({ message: 'messageCreate stream closed or reached end of lifetime'});
useContainerRaw()
?.disposeAll()
.then(() => {
this.logger?.info({ message: 'Cleaning container and crashing' });
});
})
)
.subscribe();
}
protected init(): void {
if (this.wrapper.defaultPrefix === undefined) return; //for now, just ignore if prefix doesn't exist
const { defaultPrefix } = this.wrapper;
const get = (cb: (ms: ModuleStore) => Processed<CommandModule> | undefined) => {
return this.modules.get(cb);
};
this.discordEvent
.pipe(
ignoreNonBot(this.wrapper.defaultPrefix),
//This concatMap checks if module is undefined, and if it is, do not continue.
// Synonymous to filterMap, but I haven't thought of a generic implementation for filterMap yet
concatMap(message => {
const [prefix, ...rest] = fmt(message, defaultPrefix);
const module = get(
ms => ms.TextCommands.get(prefix) ?? ms.BothCommands.get(prefix),
);
if (module === undefined) {
return EMPTY;
}
const payload = {
args: contextArgs(message, rest),
module,
};
return of(payload);
}),
map(({ args, module }) => dispatchCommand(module as Processed<TextCommand>, args)),
)
.subscribe({
next: value => this.setState(value),
error: reason => this.emitter.emit('error', SernEmitter.failure(reason)),
});
}
protected setState(state: { module: Processed<Module>; args: unknown[] }) {
this.payloadSubject.next(state);
export function makeMessageCreate(
[s, client, err, log, modules]: [
SernEmitter,
EventEmitter,
ErrorHandling,
Logging | undefined,
ModuleManager,
],
defaultPrefix?: string,
) {
if (!defaultPrefix) {
return EMPTY.subscribe();
}
const get = (cb: (ms: ModuleStore) => Processed<CommandModule> | undefined) => {
return modules.get(cb);
};
const messageStream$ = fromEvent<Message>(client, 'messageCreate');
const messageProcessor = createMessageProcessor(defaultPrefix, get);
return messageStream$
.pipe(
messageProcessor,
makeModuleExecutor(module => {
s.emit('module.activate', SernEmitter.failure(module, SernError.PluginFailure));
}),
concatMap(payload => executeModule(s, payload)),
catchError(handleError(err, log)),
finalize(() => {
log?.info({ message: 'messageCreate stream closed or reached end of lifetime' });
useContainerRaw()
?.disposeAll()
.then(() => log?.info({ message: 'Cleaning container and crashing' }));
}),
)
.subscribe();
}

View File

@@ -7,7 +7,7 @@ import { _const as i } from '../utilities/functions';
import SernEmitter from '../sernEmitter';
import { callPlugin, everyPluginOk, filterMapTo } from './operators';
import type { Processed } from '../../types/handler';
import type { VoidResult } from '../../types/plugin';
import type { ControlPlugin, VoidResult } from '../../types/plugin';
/**
* Ignores messages from any person / bot except itself
@@ -94,7 +94,7 @@ export function executeModule(
* @returns receiver function for flattening a stream of data
*/
export function createResultResolver<
T extends Processed<Module>,
T extends { execute: (...args: any[]) => any; onEvent: ControlPlugin[] },
Args extends { module: T; [key: string]: unknown },
Output,
>(config: {

View File

@@ -32,7 +32,7 @@ export function callPlugin(args: unknown): OperatorFunction<
return pipe(
concatMap(async plugin => {
const isNewPlugin = Reflect.has(plugin, guayin);
if(isNewPlugin) {
if (isNewPlugin) {
if (Array.isArray(args)) {
return plugin.execute(...args);
}

View File

@@ -1,72 +1,58 @@
import { EventsHandler } from './eventsHandler';
import type Wrapper from '../structures/wrapper';
import { concatMap, fromEvent, type Observable, take } from 'rxjs';
import { fromEvent, pipe, switchMap, take } from 'rxjs';
import * as Files from '../utilities/readFile';
import { errTap, scanModule } from './observableHandling';
import { CommandType, SernError, type ModuleStore } from '../structures';
import { CommandType, type ModuleStore, SernError } from '../structures';
import { match } from 'ts-pattern';
import { Result } from 'ts-results-es';
import { ApplicationCommandType, ComponentType } from 'discord.js';
import type { CommandModule } from '../../types/module';
import type { Processed } from '../../types/handler';
import type { ModuleManager } from '../contracts';
import type { ErrorHandling, Logging, ModuleManager } from '../contracts';
import { _const, err, ok } from '../utilities/functions';
import { defineAllFields } from './operators';
import SernEmitter from '../sernEmitter';
import type { EventEmitter } from 'node:events';
export default class ReadyHandler extends EventsHandler<{
module: Processed<CommandModule>;
absPath: string;
}> {
protected discordEvent!: Observable<{ module: CommandModule; absPath: string }>;
constructor(wrapper: Wrapper) {
super(wrapper);
const ready$ = fromEvent(this.client, 'ready').pipe(take(1));
this.discordEvent = ready$.pipe(
concatMap(() =>
Files.buildData<CommandModule>(wrapper.commands).pipe(
errTap(reason => {
this.emitter.emit(
'module.register',
SernEmitter.failure(undefined, reason),
);
}),
),
),
);
this.init();
this.payloadSubject
.pipe(
scanModule({
onFailure: module => {
this.emitter.emit(
'module.register',
SernEmitter.failure(module, SernError.PluginFailure),
);
},
onSuccess: ({ module }) => {
this.emitter.emit('module.register', SernEmitter.success(module));
return module;
},
}),
)
.subscribe(module => {
const res = registerModule(this.modules, module as Processed<CommandModule>);
if (res.err) {
this.crashHandler.crash(Error(SernError.InvalidModuleType));
}
});
}
protected init() {
this.discordEvent.pipe(defineAllFields()).subscribe({
next: value => this.setState(value),
complete: () => this.payloadSubject.unsubscribe(),
export function makeReadyEvent(
[sEmitter, client, errorHandler, , moduleManager]: [
SernEmitter,
EventEmitter,
ErrorHandling,
Logging | undefined,
ModuleManager,
],
commandDir: string,
) {
const readyOnce$ = fromEvent(client, 'ready').pipe(take(1));
const parseCommandModules = pipe(
switchMap(() => Files.buildData<CommandModule>(commandDir)),
errTap(error => {
sEmitter.emit('module.register', SernEmitter.failure(undefined, error));
}),
defineAllFields(),
);
return readyOnce$
.pipe(
parseCommandModules,
scanModule({
onFailure: module => {
sEmitter.emit(
'module.register',
SernEmitter.failure(module, SernError.PluginFailure),
);
},
onSuccess: ({ module }) => {
sEmitter.emit('module.register', SernEmitter.success(module));
return module;
},
}),
)
.subscribe(module => {
const result = registerModule(moduleManager, module as Processed<CommandModule>);
if (result.err) {
errorHandler.crash(Error(SernError.InvalidModuleType));
}
});
}
protected setState(state: { absPath: string; module: Processed<CommandModule> }): void {
this.payloadSubject.next(state);
}
}
function registerModule<T extends Processed<CommandModule>>(

View File

@@ -1,4 +1,4 @@
import { catchError, finalize, map, tap } from 'rxjs';
import { catchError, finalize, map, tap, mergeAll } from 'rxjs';
import { buildData } from '../utilities/readFile';
import type { Dependencies, Processed } from '../../types/handler';
import { errTap, scanModule } from './observableHandling';
@@ -13,57 +13,51 @@ import { handleError } from '../contracts/errorHandling';
import { defineAllFields } from './operators';
import { useContainerRaw } from '../dependencies';
export function processEvents({ containerConfig, events }: Wrapper) {
const [client, errorHandling, sernEmitter, logger] = containerConfig.get(
'@sern/client',
'@sern/errors',
'@sern/emitter',
'@sern/logger',
) as [EventEmitter, ErrorHandling, SernEmitter, Logging?];
const lazy = (k: string) => containerConfig.get(k as keyof Dependencies)[0];
const eventStream$ = eventObservable$(events!, sernEmitter);
export function makeEventsHandler(
[s, client, err, log]: [SernEmitter, EventEmitter, ErrorHandling, Logging | undefined],
eventsPath: string,
containerGetter: Wrapper['containerConfig'],
) {
const lazy = (k: string) => containerGetter.get(k as keyof Dependencies)[0];
const eventStream$ = eventObservable(eventsPath, s);
const eventCreation$ = eventStream$.pipe(
defineAllFields(),
scanModule({
onFailure: module => sernEmitter.emit('module.register', SernEmitter.success(module)),
onFailure: module => s.emit('module.register', SernEmitter.success(module)),
onSuccess: ({ module }) => {
sernEmitter.emit(
'module.register',
SernEmitter.failure(module, SernError.PluginFailure),
);
s.emit('module.register', SernEmitter.failure(module, SernError.PluginFailure));
return module;
},
}),
);
const intoDispatcher = (e: Processed<EventModule | CommandModule>) =>
match(e)
.with({ type: EventType.Sern }, m => eventDispatcher(m, sernEmitter))
.with({ type: EventType.Sern }, m => eventDispatcher(m, s))
.with({ type: EventType.Discord }, m => eventDispatcher(m, client))
.with({ type: EventType.External }, m => eventDispatcher(m, lazy(m.emitter)))
.otherwise(() => errorHandling.crash(Error(SernError.InvalidModuleType)));
.otherwise(() => err.crash(Error(SernError.InvalidModuleType)));
eventCreation$
.pipe(
map(intoDispatcher),
/**
* Where all events are turned on
*/
tap(dispatcher => dispatcher.subscribe()),
catchError(handleError(errorHandling, logger)),
mergeAll(),
catchError(handleError(err, log)),
finalize(() => {
logger?.info({ message: 'an event module reached end of lifetime'});
log?.info({ message: 'an event module reached end of lifetime' });
useContainerRaw()
?.disposeAll()
.then(() => {
logger?.info({ message: 'Cleaning container and crashing' });
log?.info({ message: 'Cleaning container and crashing' });
});
})
}),
)
.subscribe();
}
function eventObservable$(events: string, emitter: SernEmitter) {
function eventObservable(events: string, emitter: SernEmitter) {
return buildData<EventModule>(events).pipe(
errTap(reason => {
emitter.emit('module.register', SernEmitter.failure(undefined, reason));

View File

@@ -16,7 +16,8 @@ import type {
StringSelectCommand,
TextCommand,
UserSelectCommand,
ContextMenuMsg, Module,
ContextMenuMsg,
Module,
} from '../../types/module';
import type { Args, Payload, Processed, SlashOptions } from '../../types/handler';
import type Context from '../structures/context';

View File

@@ -1,4 +1,4 @@
import { CommandType, EventType, PluginType } from '../structures/enums';
import { CommandType, EventType, PluginType } from '../structures';
import type { Plugin, PluginResult } from '../../types/plugin';
import type { CommandArgs, EventArgs } from './args';
import type { ClientEvents } from 'discord.js';
@@ -10,7 +10,7 @@ export function makePlugin<V extends unknown[]>(
return {
type,
execute,
[guayin]: undefined
[guayin]: undefined,
} as Plugin<V>;
}

View File

@@ -1,10 +1,10 @@
import type Wrapper from './structures/wrapper';
import { processEvents } from './events/userDefinedEventsHandling';
import { makeEventsHandler } from './events/userDefinedEventsHandling';
import { CommandType, EventType, PluginType } from './structures/enums';
import type { AnyEventPlugin, ControlPlugin, InitPlugin, Plugin } from '../types/plugin';
import InteractionHandler from './events/interactionHandler';
import ReadyHandler from './events/readyHandler';
import MessageHandler from './events/messageHandler';
import { makeInteractionCreate } from './events/interactionHandler';
import { makeReadyEvent } from './events/readyHandler';
import { makeMessageCreate } from './events/messageHandler';
import type {
CommandModule,
CommandModuleDefs,
@@ -14,7 +14,7 @@ import type {
InputEvent,
} from '../types/module';
import type { Dependencies, DependencyConfiguration } from '../types/handler';
import { composeRoot, useContainer } from './dependencies/provider';
import { composeRoot, makeFetcher, useContainer } from './dependencies/provider';
import type { Logging } from './contracts';
import { err, ok, partition } from './utilities/functions';
import type { Awaitable, ClientEvents } from 'discord.js';
@@ -37,14 +37,15 @@ import type { Awaitable, ClientEvents } from 'discord.js';
*/
export function init(wrapper: Wrapper) {
const logger = wrapper.containerConfig.get('@sern/logger')[0] as Logging | undefined;
const requiredDependenciesAnd = makeFetcher(wrapper);
const startTime = performance.now();
const { events } = wrapper;
if (events !== undefined) {
processEvents(wrapper);
makeEventsHandler(requiredDependenciesAnd([]), events, wrapper.containerConfig);
}
new ReadyHandler(wrapper);
new MessageHandler(wrapper);
new InteractionHandler(wrapper);
makeReadyEvent(requiredDependenciesAnd(['@sern/modules']), wrapper.commands);
makeMessageCreate(requiredDependenciesAnd(['@sern/modules']), wrapper.defaultPrefix);
makeInteractionCreate(requiredDependenciesAnd(['@sern/modules']));
const endTime = performance.now();
logger?.info({ message: `sern : ${(endTime - startTime).toFixed(2)} ms` });
}

View File

@@ -5,6 +5,7 @@ import { Err, Ok } from 'ts-results-es';
* A function that returns whatever value is provided.
* Warning: this evaluates { @param value }. It does not defer a value.
* @param value
* @__PURE__
*/
// prettier-ignore
export const _const = <T>(value: T) => () => value;

View File

@@ -15,4 +15,4 @@ export * from './handler/structures';
export * from './handler/plugins';
export * from './handler/contracts';
export { SernEmitter };
export * from './handler/dependencies';
export * from './handler/dependencies';

View File

@@ -62,8 +62,8 @@ export type MapDeps<Deps extends Dependencies, T extends readonly unknown[]> = T
//Basically, '@sern/client' | '@sern/store' | '@sern/modules' | '@sern/error' | '@sern/emitter' will be provided defaults, and you can exclude the rest
export type OptionalDependencies = '@sern/logger';
export type Processed<T> = T & { name: string; description: string };
export type Deprecated<Message extends string> = [never, Message]
export type Deprecated<Message extends string> = [never, Message];
export interface DependencyConfiguration<T extends Dependencies> {
exclude?: Set<OptionalDependencies>;
build: (root: Container<Omit<Dependencies, '@sern/client'>, {}>) => Container<T, {}>
}
exclude?: Set<OptionalDependencies>;
build: (root: Container<Omit<Dependencies, '@sern/client'>, {}>) => Container<T, {}>;
}

View File

@@ -22,8 +22,8 @@ export type PluginResult = Awaitable<VoidResult>;
export type VoidResult = Result<void, void>;
export interface Controller {
next: () => Ok<void>
stop: () => Err<void>
next: () => Ok<void>;
stop: () => Err<void>;
}
export interface Plugin<Args extends any[] = any[]> {
type: PluginType;
@@ -50,7 +50,10 @@ export interface CommandPlugin<T extends CommandType = CommandType> {
name?: string;
description?: string;
type: PluginType.Command;
execute: (m: InitArgs<Processed<CommandModule>>, controller?: Deprecated<'Please import controller instead'>) => PluginResult;
execute: (
m: InitArgs<Processed<CommandModule>>,
controller?: Deprecated<'Please import controller instead'>,
) => PluginResult;
}
/**
* @deprecated
@@ -60,7 +63,7 @@ export interface EventPlugin<T extends CommandType> {
name?: string;
description?: string;
type: PluginType.Event;
execute: (args : CommandArgs<T, PluginType.Event>, controller?: Controller) => PluginResult
execute: (args: CommandArgs<T, PluginType.Event>, controller?: Controller) => PluginResult;
}
export type DiscordEmitterPlugin = Deprecated<'Please view alternatives: '>;
export type ExternalEmitterPlugin = Deprecated<'Please view alternatives: '>;

View File

@@ -5,6 +5,7 @@ const shared = {
platform: 'node',
clean: true,
sourcemap: false,
minify: true,
};
export default defineConfig([
{
@@ -12,7 +13,6 @@ export default defineConfig([
target: 'node16',
tsconfig: './tsconfig-esm.json',
outDir: './dist/esm',
external: ['discord.js'],
treeshake: true,
outExtension() {
return {
@@ -24,7 +24,6 @@ export default defineConfig([
{
format: 'cjs',
splitting: false,
external: ['discord.js'],
target: 'node16',
tsconfig: './tsconfig-cjs.json',
outDir: './dist/cjs',