23 Commits
v1.0.0 ... main

Author SHA1 Message Date
renovate[bot]
992619f8e5 chore(deps): update dependency @typescript-eslint/parser to v5.36.2 (#131)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: xxDeveloper <77380166+Murtatrxx@users.noreply.github.com>
2022-09-11 14:24:50 +03:00
renovate[bot]
b995560ec6 chore(deps): update dependency @typescript-eslint/eslint-plugin to v5.36.2 (#130)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: xxDeveloper <77380166+Murtatrxx@users.noreply.github.com>
2022-09-11 14:19:40 +03:00
renovate[bot]
f01ef9b86c chore(deps): lock file maintenance (#129)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-09-11 14:16:19 +03:00
xxDeveloper
702c5750fc docs: Fix the code example (#128) 2022-09-03 14:52:26 +03:00
renovate[bot]
d5d1b4129b chore(deps): update dependency @typescript-eslint/eslint-plugin to v5.36.1 (#126)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-09-03 11:26:55 +03:00
renovate[bot]
7658d3e3ab chore(deps): update dependency @typescript-eslint/parser to v5.36.1 (#127)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-09-03 11:24:09 +03:00
renovate[bot]
9c1abc6b2e chore(deps): lock file maintenance (#118) 2022-08-29 14:07:45 +03:00
github-actions[bot]
20bc135a7d chore(main): release 1.1.0 (#125)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-08-28 21:58:11 -05:00
EvolutionX
8a373de880 chore: release 1.1.0
Release-As: 1.1.0
2022-08-29 08:24:54 +05:30
Jacob Nguyen
395549c173 feat: add proper error handling (#115) 2022-08-29 08:09:52 +05:30
Evo
dbc180fa78 chore: duck you typo 2022-08-29 07:57:48 +05:30
github-actions[bot]
ff5c161469 stlye: pretty please (#124)
Co-authored-by: EvolutionX-10 <EvolutionX-10@users.noreply.github.com>
2022-08-29 07:12:33 +05:30
Evo
82637245f3 chore: typo and limits (#121) 2022-08-29 07:10:59 +05:30
Evo
bc3ed918da ci: add a formatting workflow (#116) 2022-08-29 07:01:28 +05:30
renovate[bot]
62bfcb1eb7 chore(deps): update dependency @typescript-eslint/parser to v5.35.1 (#111) 2022-08-28 09:40:48 +03:00
renovate[bot]
fbf54c9d36 chore(deps): update dependency typescript to v4.8.2 (#113) 2022-08-28 09:39:48 +03:00
renovate[bot]
b999918b71 chore(deps): update dependency eslint to v8.23.0 (#112) 2022-08-28 09:39:10 +03:00
renovate[bot]
224ce97fe8 chore(deps): update dependency @typescript-eslint/eslint-plugin to v5.35.1 (#110) 2022-08-28 09:38:01 +03:00
renovate[bot]
f52dd01ca5 chore(deps): lock file maintenance (#109)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-22 22:11:42 +03:00
renovate[bot]
b8841e926d chore(deps): lock file maintenance (#105)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-21 22:35:28 +03:00
renovate[bot]
f0f54cb7f2 chore(deps): update dependency eslint to v8.22.0 (#103)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-21 22:34:54 +03:00
renovate[bot]
ebe759f5e0 chore(deps): update dependency @typescript-eslint/parser to v5.33.1 (#102) 2022-08-18 22:16:10 +03:00
renovate[bot]
58d97e08a5 chore(deps): update dependency @typescript-eslint/eslint-plugin to v5.33.1 (#101) 2022-08-18 22:15:18 +03:00
19 changed files with 5424 additions and 4910 deletions

View File

@@ -3,9 +3,9 @@
"extends": ["plugin:@typescript-eslint/recommended"],
"parserOptions": { "ecmaVersion": "latest", "sourceType": "script" },
"rules": {
"@typescript-eslint/no-non-null-assertion": "off",
"quotes": [2, "single", { "avoidEscape": true, "allowTemplateLiterals" : true }],
"semi": ["error", "always"],
"@typescript-eslint/no-empty-interface": 0
"@typescript-eslint/no-non-null-assertion": "off",
"quotes": [2, "single", { "avoidEscape": true, "allowTemplateLiterals": true }],
"semi": ["error", "always"],
"@typescript-eslint/no-empty-interface": 0
}
}
}

View File

@@ -0,0 +1,44 @@
name: Continuous Integration
on:
# Trigger the workflow on push or pull request or custom
push:
branches:
main
pull_request_target:
branches:
main
workflow_dispatch:
jobs:
Prettier:
name: Run Prettier
runs-on: ubuntu-latest
steps:
- name: Check out Git repository
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3
- name: Set up Node.js
uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3
with:
node-version: 17
# Prettier must be in `package.json`
- name: Install Node.js dependencies
run: npm i -g prettier && npm i
- name: Run Prettier
run: prettier --write .
- name: Create Pull Request
id: cpr
uses: peter-evans/create-pull-request@v4
with:
commit-message: "style: pretty please"
branch: prettier
delete-branch: true
branch-suffix: short-commit-hash
title: "style: pretty please"
body: "pretty pretty prettier"
reviewers: EvolutionX-10

View File

@@ -1,8 +1,8 @@
{
"semi": true,
"trailingComma": "all",
"singleQuote": true,
"printWidth": 100,
"tabWidth": 4,
"arrowParens": "avoid"
"semi": true,
"trailingComma": "all",
"singleQuote": true,
"printWidth": 100,
"tabWidth": 4,
"arrowParens": "avoid"
}

View File

@@ -1,5 +1,17 @@
# Changelog
## [1.1.0](https://github.com/sern-handler/handler/compare/v1.0.0...v1.1.0) (2022-08-29)
### Features
* add proper error handling ([#115](https://github.com/sern-handler/handler/issues/115)) ([395549c](https://github.com/sern-handler/handler/commit/395549c173cb62a18205e451bf2cb5579ba9a6e0))
### Miscellaneous Chores
* release 1.1.0 ([8a373de](https://github.com/sern-handler/handler/commit/8a373de880ff18df85af812adf9f6f6a4f45028d))
## 1.0.0 (2022-08-15)

View File

@@ -71,7 +71,7 @@ client.login(token);
#### ` ping.js (CommonJS)`
```js
const { CommandType } = require('@sern/handler');
const { CommandType, commandModule } = require('@sern/handler');
exports.default = commandModule({
name: 'ping',

9856
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,54 +1,54 @@
{
"name": "@sern/handler",
"version": "1.0.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",
"types": "dist/index.d.ts",
"exports": {
".": {
"import": "./dist/esm/index.mjs",
"require": "./dist/cjs/index.cjs"
}
},
"scripts": {
"watch": "tsup --watch --dts",
"clean-modules": "rimraf node_modules/ && npm install",
"lint": "eslint src/**/*.ts",
"format": "eslint src/**/*.ts --fix",
"build": "tsup && node scripts/mkjson.mjs dist/cjs dist/esm && tsup --dts-only --outDir dist",
"publish": "npm run build && npm publish"
},
"keywords": [
"sern-handler",
"sern",
"handler",
"sern handler",
"wrapper",
"discord.js",
"framework"
],
"author": "SernDevs",
"license": "MIT",
"dependencies": {
"rxjs": "^7.5.6",
"ts-pattern": "^4.0.2",
"ts-results-es": "^3.5.0"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "5.32.0",
"@typescript-eslint/parser": "5.32.0",
"eslint": "8.21.0",
"prettier": "2.7.1",
"tsup": "^6.1.3",
"typescript": "4.7.4"
},
"peerDependencies": {
"discord.js": "^14.2.x"
},
"repository": {
"type": "git",
"url": "git+https://github.com/sern-handler/handler.git"
},
"homepage": "https://sern-handler.js.org"
"name": "@sern/handler",
"version": "1.1.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",
"types": "dist/index.d.ts",
"exports": {
".": {
"import": "./dist/esm/index.mjs",
"require": "./dist/cjs/index.cjs"
}
},
"scripts": {
"watch": "tsup --watch --dts",
"clean-modules": "rimraf node_modules/ && npm install",
"lint": "eslint src/**/*.ts",
"format": "eslint src/**/*.ts --fix",
"build": "tsup && node scripts/mkjson.mjs dist/cjs dist/esm && tsup --dts-only --outDir dist",
"publish": "npm run build && npm publish"
},
"keywords": [
"sern-handler",
"sern",
"handler",
"sern handler",
"wrapper",
"discord.js",
"framework"
],
"author": "SernDevs",
"license": "MIT",
"dependencies": {
"rxjs": "^7.5.6",
"ts-pattern": "^4.0.2",
"ts-results-es": "^3.5.0"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "5.36.1",
"@typescript-eslint/parser": "5.36.2",
"eslint": "8.22.0",
"prettier": "2.7.1",
"tsup": "^6.1.3",
"typescript": "4.7.4"
},
"peerDependencies": {
"discord.js": "^14.2.x"
},
"repository": {
"type": "git",
"url": "git+https://github.com/sern-handler/handler.git"
},
"homepage": "https://sern-handler.js.org"
}

View File

@@ -1,14 +1,14 @@
{
"major": {
"dependencyDashboardApproval": true,
"reviewers": ["EvolutionX-10", "jacoobes", "Murtatrxx"]
},
"minor": {
"reviewers": ["jacoobes", "Murtatrxx"]
},
"schedule": ["every weekend"],
"lockFileMaintenance": {
"enabled": true,
"automerge": false
}
"major": {
"dependencyDashboardApproval": true,
"reviewers": ["EvolutionX-10", "jacoobes", "Murtatrxx"]
},
"minor": {
"reviewers": ["jacoobes", "Murtatrxx"]
},
"schedule": ["every weekend"],
"lockFileMaintenance": {
"enabled": true,
"automerge": false
}
}

View File

@@ -1,15 +1,13 @@
import { writeFile } from 'fs/promises'
import { writeFile } from 'fs/promises';
import { join } from 'path';
// A quick script to regenerate package.jsons for each cjs and esm after tsup cleans distributions
const locations = process.argv;
locations.shift();
locations.shift();
for(const loc of locations) {
if(loc.endsWith('cjs')) {
await writeFile(join(loc, 'package.json'), JSON.stringify({ type : 'commonjs' }))
for (const loc of locations) {
if (loc.endsWith('cjs')) {
await writeFile(join(loc, 'package.json'), JSON.stringify({ type: 'commonjs' }));
} else {
await writeFile(join(loc, 'package.json'), JSON.stringify({ type : 'module' }))
await writeFile(join(loc, 'package.json'), JSON.stringify({ type: 'module' }));
}
}

View File

@@ -1,5 +1,5 @@
import type { Interaction } from 'discord.js';
import { concatMap, from, fromEvent, map, Observable } from 'rxjs';
import { catchError, concatMap, from, fromEvent, map, Observable } from 'rxjs';
import type Wrapper from '../structures/wrapper';
import { EventsHandler } from './eventsHandler';
import {
@@ -11,7 +11,7 @@ import {
import * as Files from '../utilities/readFile';
import type { CommandModule } from '../structures/module';
import { SernError } from '../structures/errors';
import { CommandType } from '../structures/enums';
import { CommandType, PayloadType } from '../structures/enums';
import { match, P } from 'ts-pattern';
import {
applicationCommandDispatcher,
@@ -49,27 +49,24 @@ export default class InteractionHandler extends EventsHandler<{
return from(eventPluginRes).pipe(map(res => ({ mod, res, execute })));
}),
concatMap(payload => executeModule(wrapper, payload)),
)
.subscribe({
error: err => {
catchError((err, caught) => {
wrapper.sernEmitter?.emit('error', err);
},
});
return caught;
}),
)
.subscribe();
}
override init() {
this.discordEvent.subscribe({
next: event => {
if (isMessageComponent(event)) {
const mod = Files.MessageCompCommands[event.componentType].get(
event.customId,
);
const mod = Files.MessageCompCommands[event.componentType].get(event.customId);
this.setState({ event, mod });
} else if (isApplicationCommand(event) || isAutocomplete(event)) {
const mod =
Files.ApplicationCommands[event.commandType].get(
event.commandName,
) ?? Files.BothCommands.get(event.commandName);
Files.ApplicationCommands[event.commandType].get(event.commandName) ??
Files.BothCommands.get(event.commandName);
this.setState({ event, mod });
} else if (isModalSubmit(event)) {
/**
@@ -81,8 +78,8 @@ export default class InteractionHandler extends EventsHandler<{
throw Error('This interaction is not supported yet');
}
},
error: e => {
this.wrapper.sernEmitter?.emit('error', e);
error: reason => {
this.wrapper.sernEmitter?.emit('error', { type: PayloadType.Failure, reason });
},
});
}
@@ -106,10 +103,7 @@ export default class InteractionHandler extends EventsHandler<{
{ type: CommandType.Modal },
modalCommandDispatcher(event as ModalSubmitInteraction),
)
.with(
{ type: CommandType.Button },
buttonCommandDispatcher(event as ButtonInteraction),
)
.with({ type: CommandType.Button }, buttonCommandDispatcher(event as ButtonInteraction))
.with(
{ type: CommandType.MenuSelect },
selectMenuCommandDispatcher(event as SelectMenuInteraction),

View File

@@ -1,5 +1,5 @@
import { EventsHandler } from './eventsHandler';
import { concatMap, from, fromEvent, map, Observable, of, switchMap } from 'rxjs';
import { catchError, concatMap, from, fromEvent, map, Observable, of, switchMap } from 'rxjs';
import type Wrapper from '../structures/wrapper';
import type { Message } from 'discord.js';
import { executeModule, ignoreNonBot, isOneOfCorrectModules } from './observableHandling';
@@ -7,7 +7,7 @@ import { fmt } from '../utilities/messageHelpers';
import Context from '../structures/context';
import * as Files from '../utilities/readFile';
import type { TextCommand } from '../structures/module';
import { CommandType } from '../structures/enums';
import { CommandType, PayloadType } from '../structures/enums';
import { asyncResolveArray } from '../utilities/asyncResolveArray';
import { controller } from '../sern';
@@ -36,12 +36,12 @@ export default class MessageHandler extends EventsHandler<{
return from(res).pipe(map(res => ({ mod, execute, res })));
}),
concatMap(payload => executeModule(wrapper, payload)),
)
.subscribe({
error: err => {
catchError((err, caught) => {
wrapper.sernEmitter?.emit('error', err);
},
});
return caught;
}),
)
.subscribe();
}
protected init(): void {
@@ -61,16 +61,17 @@ export default class MessageHandler extends EventsHandler<{
Files.TextCommands.aliases.get(prefix),
};
}),
concatMap(element => {
return of(element.mod).pipe(
concatMap(element =>
of(element.mod).pipe(
isOneOfCorrectModules(CommandType.Text),
map(mod => ({ ...element, mod })),
);
}),
),
),
)
.subscribe({
next: value => this.setState(value),
error: err => this.wrapper.sernEmitter?.emit('error', err),
error: reason =>
this.wrapper.sernEmitter?.emit('error', { type: PayloadType.Failure, reason }),
});
}

View File

@@ -1,13 +1,12 @@
import type { Message } from 'discord.js';
import { from, Observable, of, tap, throwError } from 'rxjs';
import { concatMap, from, Observable, of, tap, throwError } from 'rxjs';
import { SernError } from '../structures/errors';
import type { Module, CommandModuleDefs, CommandModule } from '../structures/module';
import type { Result } from 'ts-results-es';
import { Result } from 'ts-results-es';
import type { CommandType } from '../structures/enums';
import type Wrapper from '../structures/wrapper';
import { PayloadType } from '../structures/enums';
export function ignoreNonBot(prefix: string) {
return (src: Observable<Message>) =>
new Observable<Message>(subscriber => {
@@ -80,12 +79,26 @@ export function executeModule(
},
) {
if (payload.res.every(el => el.ok)) {
return from(Promise.resolve(payload.execute())).pipe(
tap(() => {
wrapper.sernEmitter?.emit('module.activate', {
type: PayloadType.Success,
module: payload.mod,
});
const executeFn = Result.wrapAsync<unknown, Error | string>(() =>
Promise.resolve(payload.execute()),
);
return from(executeFn).pipe(
concatMap(res => {
if (res.err) {
return throwError(() => ({
type: PayloadType.Failure,
reason: res.val,
module: payload.mod,
}));
}
return of(res.val).pipe(
tap(() =>
wrapper.sernEmitter?.emit('module.activate', {
type: PayloadType.Success,
module: payload.mod,
}),
),
);
}),
);
} else {
@@ -94,6 +107,6 @@ export function executeModule(
module: payload.mod,
reason: SernError.PluginFailure,
});
return of(null);
return of(undefined);
}
}

View File

@@ -1,7 +1,7 @@
import { ApplicationCommandType, ComponentType } from 'discord.js';
import { readdirSync, statSync } from 'fs';
import { join } from 'path';
import { type Observable, from, concatAll } from 'rxjs';
import { type Observable, from, concatAll } from 'rxjs';
import type { CommandModule } from '../structures/module';
import { SernError } from '../structures/errors';
import { type Result, Err, Ok } from 'ts-results-es';
@@ -63,19 +63,22 @@ export function buildData<T>(commandDir: string): Observable<
>
> {
const commands = getCommands(commandDir);
return from(Promise.all(commands.map(async absPath => {
let mod : T | undefined;
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
mod = require(absPath).default;
} catch {
mod = (await import(`file:///` +absPath)).default;
}
if (mod !== undefined) {
return Ok({ mod, absPath });
} else return Err(SernError.UndefinedModule);
})
)).pipe(concatAll());
return from(
Promise.all(
commands.map(async absPath => {
let mod: T | undefined;
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
mod = require(absPath).default;
} catch {
mod = (await import(`file:///` + absPath)).default;
}
if (mod !== undefined) {
return Ok({ mod, absPath });
} else return Err(SernError.UndefinedModule);
}),
),
).pipe(concatAll());
}
export function getCommands(dir: string): string[] {

View File

@@ -1,31 +1,40 @@
import type { SernOptionsData } from '../structures/module';
import { ApplicationCommandOptionType, AutocompleteInteraction } from 'discord.js';
export default function treeSearch(iAutocomplete: AutocompleteInteraction, options: SernOptionsData[] | undefined) {
if(options === undefined) return undefined;
export default function treeSearch(
iAutocomplete: AutocompleteInteraction,
options: SernOptionsData[] | undefined,
) {
if (options === undefined) return undefined;
const _options = options.slice(); // required to prevent direct mutation of options
while ( _options.length > 0 ) {
while (_options.length > 0) {
const cur = _options.pop()!;
switch ( cur.type ) {
case ApplicationCommandOptionType.Subcommand : {
for ( const option of cur.options ?? [] ) {
_options.push(option);
}
} break;
case ApplicationCommandOptionType.SubcommandGroup : {
for (const command of cur.options ?? []) {
_options.push(command);
}
} break;
default : {
if(cur.autocomplete) {
const choice = iAutocomplete.options.getFocused(true);
if(cur.name === choice.name && cur.autocomplete) {
return cur;
switch (cur.type) {
case ApplicationCommandOptionType.Subcommand:
{
for (const option of cur.options ?? []) {
_options.push(option);
}
return undefined;
}
} break;
break;
case ApplicationCommandOptionType.SubcommandGroup:
{
for (const command of cur.options ?? []) {
_options.push(command);
}
}
break;
default:
{
if (cur.autocomplete) {
const choice = iAutocomplete.options.getFocused(true);
if (cur.name === choice.name && cur.autocomplete) {
return cur;
}
return undefined;
}
}
break;
}
}
}
}

View File

@@ -49,10 +49,10 @@ export type DefinedCommandModule = DefinitelyDefined<CommandModule, 'name' | 'de
export type DefinedEventModule = DefinitelyDefined<EventModule, 'name' | 'description'>;
export type Payload =
| { type: PayloadType.Success; module: Module }
| { type: PayloadType.Failure; module: Module | undefined; reason: string | Error };
| { type: PayloadType.Failure; module?: Module; reason: string | Error };
export type SernEventsMapping = {
['module.register']: [Payload];
['module.activate']: [Payload];
['error']: [Error | string];
['error']: [Payload];
['warning']: [string];
};

View File

@@ -1,17 +1,17 @@
{
"compilerOptions": {
"rootDir": "src",
"strict": true,
"esModuleInterop": true,
"noImplicitAny": true,
"strictNullChecks": true,
"importsNotUsedAsValues": "error",
"moduleResolution": "node",
"skipLibCheck": true,
"declaration": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
},
"exclude": ["node_modules", "dist"],
"include": ["src"],
"compilerOptions": {
"rootDir": "src",
"strict": true,
"esModuleInterop": true,
"noImplicitAny": true,
"strictNullChecks": true,
"importsNotUsedAsValues": "error",
"moduleResolution": "node",
"skipLibCheck": true,
"declaration": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true
},
"exclude": ["node_modules", "dist"],
"include": ["src"]
}

View File

@@ -1,8 +1,8 @@
{
"extends": "./tsconfig-base.json",
"compilerOptions": {
"module": "commonjs",
"outDir": "dist/cjs",
"target": "esnext"
}
}
"extends": "./tsconfig-base.json",
"compilerOptions": {
"module": "commonjs",
"outDir": "dist/cjs",
"target": "esnext"
}
}

View File

@@ -1,8 +1,8 @@
{
"extends": "./tsconfig-base.json",
"compilerOptions": {
"module": "esnext",
"outDir": "dist/esm",
"target": "esnext"
}
}
"extends": "./tsconfig-base.json",
"compilerOptions": {
"module": "esnext",
"outDir": "dist/esm",
"target": "esnext"
}
}

View File

@@ -3,36 +3,36 @@ import { defineConfig } from 'tsup';
export default defineConfig([
{
entry: ['src/index.ts'],
format : 'esm',
format: 'esm',
sourcemap: false,
target: 'node16',
tsconfig : './tsconfig-esm.json',
outDir : './dist/esm',
tsconfig: './tsconfig-esm.json',
outDir: './dist/esm',
platform: 'node',
external: ['discord.js'],
clean: true,
treeshake: true,
outExtension() {
return {
js : '.mjs'
js: '.mjs',
};
}
},
},
{
entry: ['src/index.ts'],
format : 'cjs',
format: 'cjs',
splitting: false,
sourcemap: false,
external: ['discord.js'],
clean: true,
target: 'node16',
tsconfig : './tsconfig-cjs.json',
outDir : './dist/cjs',
tsconfig: './tsconfig-cjs.json',
outDir: './dist/cjs',
platform: 'node',
outExtension() {
return {
js : '.cjs'
js: '.cjs',
};
}
}
},
},
]);