mirror of
https://github.com/sern-handler/handler
synced 2026-06-06 01:16:55 +00:00
style: pretty
This commit is contained in:
@@ -1,27 +1,26 @@
|
||||
import {
|
||||
import {
|
||||
ChatInputCommandInteraction,
|
||||
Client,
|
||||
InteractionReplyOptions,
|
||||
Message,
|
||||
MessageReplyOptions,
|
||||
Snowflake,
|
||||
User
|
||||
} from "discord.js";
|
||||
import { CoreContext } from "../core/structures/context";
|
||||
import { Result , Ok , Err } from 'ts-results-es';
|
||||
import { ReplyOptions } from "../types/handler";
|
||||
User,
|
||||
} from 'discord.js';
|
||||
import { CoreContext } from '../core/structures/context';
|
||||
import { Result, Ok, Err } from 'ts-results-es';
|
||||
import { ReplyOptions } from '../types/handler';
|
||||
/**
|
||||
* @since 1.0.0
|
||||
* Provides values shared between
|
||||
* Message and ChatInputCommandInteraction
|
||||
*/
|
||||
export class Context extends CoreContext<Message, ChatInputCommandInteraction> {
|
||||
|
||||
get options() {
|
||||
return this.interaction.options
|
||||
get options() {
|
||||
return this.interaction.options;
|
||||
}
|
||||
protected constructor(protected ctx: Result<Message, ChatInputCommandInteraction>) {
|
||||
super(ctx)
|
||||
super(ctx);
|
||||
}
|
||||
|
||||
public get id(): Snowflake {
|
||||
@@ -64,7 +63,7 @@ export class Context extends CoreContext<Message, ChatInputCommandInteraction> {
|
||||
public get inGuild(): boolean {
|
||||
return this.ctx.val.inGuild();
|
||||
}
|
||||
|
||||
|
||||
public async reply(content: ReplyOptions) {
|
||||
return safeUnwrap(
|
||||
this.ctx
|
||||
@@ -83,9 +82,6 @@ export class Context extends CoreContext<Message, ChatInputCommandInteraction> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function safeUnwrap<T>(res: Result<T, T>) {
|
||||
return res.val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { ClientEvents } from "discord.js";
|
||||
import { CommandType, EventType, PluginType } from "./core/structures";
|
||||
import { AnyEventPlugin, Plugin } from "./types/plugin";
|
||||
import { CommandModule, EventModule, InputCommand, InputEvent } from "./types/module";
|
||||
import { partition } from "./core/functions";
|
||||
import { filename, filePath } from "./core/module-loading";
|
||||
import { Awaitable } from "./types/handler";
|
||||
export const sernMeta = Symbol('@sern/meta')
|
||||
import { ClientEvents } from 'discord.js';
|
||||
import { CommandType, EventType, PluginType } from './core/structures';
|
||||
import { AnyEventPlugin, Plugin } from './types/plugin';
|
||||
import { CommandModule, EventModule, InputCommand, InputEvent } from './types/module';
|
||||
import { partition } from './core/functions';
|
||||
import { filename, filePath } from './core/module-loading';
|
||||
import { Awaitable } from './types/handler';
|
||||
export const sernMeta = Symbol('@sern/meta');
|
||||
const appBitField = 0b000000011111;
|
||||
/*
|
||||
* Generates a number based on CommandType.
|
||||
@@ -13,11 +13,9 @@ const appBitField = 0b000000011111;
|
||||
* TextCommands are 0 as they aren't either or.
|
||||
*/
|
||||
function apiType(t: CommandType) {
|
||||
if(t === CommandType.Both || t === CommandType.Modal) return 1;
|
||||
if (t === CommandType.Both || t === CommandType.Modal) return 1;
|
||||
const log = Math.log2(t);
|
||||
return (appBitField & t) !== 0
|
||||
? log
|
||||
: log-2;
|
||||
return (appBitField & t) !== 0 ? log : log - 2;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -26,8 +24,8 @@ function apiType(t: CommandType) {
|
||||
* Then, another number generated by apiType function is appended
|
||||
*/
|
||||
function uniqueId(t: CommandType) {
|
||||
const am = ((appBitField & t) !== 0) ? 'A' : 'C';
|
||||
return am+apiType(t);
|
||||
const am = (appBitField & t) !== 0 ? 'A' : 'C';
|
||||
return am + apiType(t);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,18 +37,18 @@ export function commandModule(mod: InputCommand): CommandModule {
|
||||
mod.plugins ?? [],
|
||||
el => (el as Plugin).type === PluginType.Control,
|
||||
);
|
||||
const fullPath = filePath()
|
||||
const name = mod.name ?? filename(fullPath)
|
||||
const fullPath = filePath();
|
||||
const name = mod.name ?? filename(fullPath);
|
||||
return {
|
||||
...mod,
|
||||
description: mod.description ?? "...",
|
||||
description: mod.description ?? '...',
|
||||
name,
|
||||
onEvent,
|
||||
plugins,
|
||||
[sernMeta]: {
|
||||
id: `${name}__${uniqueId(mod.type)}`,
|
||||
fullPath,
|
||||
}
|
||||
},
|
||||
} as CommandModule;
|
||||
}
|
||||
/**
|
||||
@@ -65,12 +63,12 @@ export function eventModule(mod: InputEvent): EventModule {
|
||||
);
|
||||
const fullPath = filePath();
|
||||
return {
|
||||
name: mod.name ?? filename(fullPath),
|
||||
name: mod.name ?? filename(fullPath),
|
||||
onEvent,
|
||||
plugins,
|
||||
[sernMeta]: {
|
||||
id: 'no-id',
|
||||
fullPath
|
||||
fullPath,
|
||||
},
|
||||
...mod,
|
||||
} as EventModule;
|
||||
@@ -89,7 +87,6 @@ export function discordEvent<T extends keyof ClientEvents>(mod: {
|
||||
}) {
|
||||
return eventModule({
|
||||
type: EventType.Discord,
|
||||
...mod
|
||||
...mod,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { importModule } from '../module-loading';
|
||||
export interface ModuleManager {
|
||||
get(id: string): string | undefined;
|
||||
set(id: string, path: string): void;
|
||||
getPublishableCommands() : Promise<CommandModule[]>
|
||||
getPublishableCommands(): Promise<CommandModule[]>;
|
||||
}
|
||||
/**
|
||||
* @since 2.0.0
|
||||
@@ -18,16 +18,16 @@ export class DefaultModuleManager implements ModuleManager {
|
||||
return this.moduleStore.get(id);
|
||||
}
|
||||
set(id: string, path: string): void {
|
||||
this.moduleStore.set(id, path)
|
||||
this.moduleStore.set(id, path);
|
||||
}
|
||||
//not tested
|
||||
getPublishableCommands(): Promise<CommandModule[]> {
|
||||
const entries = this.moduleStore.entries();
|
||||
const publishable = 0b000000110;
|
||||
return Promise.all(
|
||||
Array.from(entries)
|
||||
.filter(([id,]) => (Number.parseInt(id.at(-1)!) & publishable) !== 0)
|
||||
.map(([, path]) => importModule<CommandModule>(path)))
|
||||
const entries = this.moduleStore.entries();
|
||||
const publishable = 0b000000110;
|
||||
return Promise.all(
|
||||
Array.from(entries)
|
||||
.filter(([id]) => (Number.parseInt(id.at(-1)!) & publishable) !== 0)
|
||||
.map(([, path]) => importModule<CommandModule>(path)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ export function single<T>(cb: () => T) {
|
||||
* use transient if you want a new dependency every time your container getter is called
|
||||
* @param cb
|
||||
*/
|
||||
export function transient<T>(cb: (() => () => T) ) {
|
||||
export function transient<T>(cb: () => () => T) {
|
||||
return cb;
|
||||
}
|
||||
/**
|
||||
@@ -36,9 +36,7 @@ export function transient<T>(cb: (() => () => T) ) {
|
||||
* Finally, update the containerSubject with the new container state
|
||||
* @param conf
|
||||
*/
|
||||
export function composeRoot<T extends AnyDependencies>(
|
||||
conf: DependencyConfiguration<T>
|
||||
) {
|
||||
export function composeRoot<T extends AnyDependencies>(conf: DependencyConfiguration<T>) {
|
||||
//This should have no client or logger yet.
|
||||
const currentContainer = containerSubject.getValue();
|
||||
const excludeLogger = conf.exclude?.has('@sern/logger');
|
||||
@@ -93,29 +91,29 @@ function defaultContainer() {
|
||||
>;
|
||||
}
|
||||
|
||||
const requiredDependencyKeys = [
|
||||
'@sern/emitter',
|
||||
'@sern/errors',
|
||||
'@sern/logger',
|
||||
] as const;
|
||||
const requiredDependencyKeys = ['@sern/emitter', '@sern/errors', '@sern/logger'] as const;
|
||||
|
||||
/**
|
||||
* A way for sern to grab only the necessary dependencies.
|
||||
* A way for sern to grab only the necessary dependencies.
|
||||
* Returns a function which allows for the user to call for more dependencies.
|
||||
*/
|
||||
export function makeFetcher<Dep extends AnyDependencies>(containerConfig : Wrapper['containerConfig']) {
|
||||
return <const Keys extends (keyof Dep)[]>(otherKeys: [...Keys]) =>
|
||||
containerConfig.get(...requiredDependencyKeys, ...otherKeys as (keyof AnyDependencies)[]) as MapDeps<
|
||||
Dep,
|
||||
[...typeof requiredDependencyKeys, ...Keys]
|
||||
>;
|
||||
export function makeFetcher<Dep extends AnyDependencies>(
|
||||
containerConfig: Wrapper['containerConfig'],
|
||||
) {
|
||||
return <const Keys extends (keyof Dep)[]>(otherKeys: [...Keys]) =>
|
||||
containerConfig.get(
|
||||
...requiredDependencyKeys,
|
||||
...(otherKeys as (keyof AnyDependencies)[]),
|
||||
) as MapDeps<Dep, [...typeof requiredDependencyKeys, ...Keys]>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0.0
|
||||
* @param conf a configuration for creating your project dependencies
|
||||
*/
|
||||
export function makeDependencies<const T extends AnyDependencies>(conf: DependencyConfiguration<T>) {
|
||||
export function makeDependencies<const T extends AnyDependencies>(
|
||||
conf: DependencyConfiguration<T>,
|
||||
) {
|
||||
//Until there are more optional dependencies, just check if the logger exists
|
||||
composeRoot(conf);
|
||||
return useContainer<T>();
|
||||
|
||||
@@ -2,10 +2,9 @@ import { Err, Ok } from 'ts-results-es';
|
||||
import { ApplicationCommandOptionType, AutocompleteInteraction } from 'discord.js';
|
||||
import type { SernAutocompleteData, SernOptionsData } from '../types/module';
|
||||
|
||||
|
||||
//function wrappers for empty ok / err
|
||||
export const ok = /* @__PURE__*/ () => Ok.EMPTY;
|
||||
export const err =/* @__PURE__*/ () => Err.EMPTY;
|
||||
export const err = /* @__PURE__*/ () => Err.EMPTY;
|
||||
|
||||
export function partition<T, V>(arr: (T & V)[], condition: (e: T & V) => boolean): [T[], V[]] {
|
||||
const t: T[] = [];
|
||||
@@ -20,7 +19,6 @@ export function partition<T, V>(arr: (T & V)[], condition: (e: T & V) => boolean
|
||||
return [t, v];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Uses an iterative DFS to check if an autocomplete node exists
|
||||
* @param iAutocomplete
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export * from './contracts';
|
||||
export * from './plugins';
|
||||
export * from './structures';
|
||||
export { single, transient, useContainerRaw, makeDependencies } from './dependencies'
|
||||
export { single, transient, useContainerRaw, makeDependencies } from './dependencies';
|
||||
|
||||
@@ -2,38 +2,35 @@ import { SernError } from './structures/errors';
|
||||
import { type Result, Err, Ok } from 'ts-results-es';
|
||||
import { Processed } from '../types/core';
|
||||
import { Module } from '../types/module';
|
||||
import * as assert from 'node:assert'
|
||||
import util from 'node:util'
|
||||
import * as assert from 'node:assert';
|
||||
import util from 'node:util';
|
||||
import { type Observable, from, mergeMap, ObservableInput } from 'rxjs';
|
||||
import { readdir, stat } from 'fs/promises';
|
||||
import { basename, join, resolve } from 'path';
|
||||
|
||||
export type ModuleResult<T> = Promise<Result<Processed<T>, SernError>>
|
||||
export type Loader<T> = (absPath: string) => ModuleResult<T>
|
||||
export type ModuleResult<T> = Promise<Result<Processed<T>, SernError>>;
|
||||
export type Loader<T> = (absPath: string) => ModuleResult<T>;
|
||||
export async function importModule<T>(absPath: string) {
|
||||
/// #if MODE === 'esm'
|
||||
return (await import(absPath)).default as T
|
||||
return import(absPath).then(i => i.default as T);
|
||||
/// #elif MODE === 'cjs'
|
||||
return require(absPath).default as T; // eslint-disable-line
|
||||
/// #endif
|
||||
}
|
||||
export async function defaultModuleLoader<T extends Module>(
|
||||
absPath: string,
|
||||
): ModuleResult<T> {
|
||||
export async function defaultModuleLoader<T extends Module>(absPath: string): ModuleResult<T> {
|
||||
// prettier-ignore
|
||||
const module = await importModule<T>(absPath);
|
||||
if (module === undefined) {
|
||||
return Err(SernError.UndefinedModule);
|
||||
return Err(SernError.UndefinedModule);
|
||||
}
|
||||
checkIsProcessed(module)
|
||||
checkIsProcessed(module);
|
||||
return Ok(module);
|
||||
}
|
||||
|
||||
function checkIsProcessed<T extends Module>(m: T): asserts m is Processed<T> {
|
||||
assert.ok(m.name !== undefined, `name is not defined for ${util.format(m)}`)
|
||||
assert.ok(m.name !== undefined, `name is not defined for ${util.format(m)}`);
|
||||
}
|
||||
|
||||
|
||||
export const fmtFileName = (n: string) => n.substring(0, n.length - 3);
|
||||
/**
|
||||
* a directory string is converted into a stream of modules.
|
||||
@@ -42,7 +39,7 @@ export const fmtFileName = (n: string) => n.substring(0, n.length - 3);
|
||||
* @param commandDir
|
||||
*/
|
||||
export function buildModuleStream<T extends Module>(
|
||||
input: ObservableInput<string>
|
||||
input: ObservableInput<string>,
|
||||
): Observable<Result<Processed<T>, SernError>> {
|
||||
return from(input).pipe(mergeMap(defaultModuleLoader<T>));
|
||||
}
|
||||
@@ -52,28 +49,28 @@ export function getCommands(dir: string) {
|
||||
}
|
||||
|
||||
export function filename(path: string) {
|
||||
return fmtFileName(basename(path))
|
||||
return fmtFileName(basename(path));
|
||||
}
|
||||
|
||||
async function* readPath(dir: string): AsyncGenerator<string> {
|
||||
try {
|
||||
const files = await readdir(dir);
|
||||
for (const file of files) {
|
||||
const fullPath = join(dir, file);
|
||||
const fileStats = await stat(fullPath);
|
||||
if (fileStats.isDirectory()) {
|
||||
yield* readPath(fullPath);
|
||||
} else {
|
||||
/// #if MODE === 'esm'
|
||||
yield 'file:///'+fullPath;
|
||||
/// #elif MODE === 'cjs'
|
||||
yield fullPath;
|
||||
/// #endif
|
||||
}
|
||||
try {
|
||||
const files = await readdir(dir);
|
||||
for (const file of files) {
|
||||
const fullPath = join(dir, file);
|
||||
const fileStats = await stat(fullPath);
|
||||
if (fileStats.isDirectory()) {
|
||||
yield* readPath(fullPath);
|
||||
} else {
|
||||
/// #if MODE === 'esm'
|
||||
yield 'file:///' + fullPath;
|
||||
/// #elif MODE === 'cjs'
|
||||
yield fullPath;
|
||||
/// #endif
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
//https://stackoverflow.com/questions/16697791/nodejs-get-filename-of-caller-function
|
||||
@@ -86,7 +83,8 @@ export function filePath() {
|
||||
|
||||
Error.prepareStackTrace = undefined;
|
||||
const path = stack[2].getFileName();
|
||||
if(path === null) {
|
||||
throw Error("Could not get the name of commandModule.")
|
||||
if (path === null) {
|
||||
throw Error('Could not get the name of commandModule.');
|
||||
}
|
||||
return path; }
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,20 @@
|
||||
* Each function should be modular and testable, not bound to discord / sern
|
||||
* and independent of each other
|
||||
*/
|
||||
import { concatMap, defaultIfEmpty, EMPTY, every, fromEvent, map, Observable, of, OperatorFunction, pipe, share, switchMap } from 'rxjs';
|
||||
import {
|
||||
concatMap,
|
||||
defaultIfEmpty,
|
||||
EMPTY,
|
||||
every,
|
||||
fromEvent,
|
||||
map,
|
||||
Observable,
|
||||
of,
|
||||
OperatorFunction,
|
||||
pipe,
|
||||
share,
|
||||
switchMap,
|
||||
} from 'rxjs';
|
||||
import type { PluginResult, VoidResult } from '../types/plugin';
|
||||
import { Result } from 'ts-results-es';
|
||||
import { Awaitable } from '../types/handler';
|
||||
@@ -16,16 +29,18 @@ export function filterMapTo<V>(item: () => V): OperatorFunction<boolean, V> {
|
||||
return concatMap(shouldKeep => (shouldKeep ? of(item()) : EMPTY));
|
||||
}
|
||||
|
||||
export function filterMap<In, Out>(cb: (i: In) => Awaitable<Result<Out, unknown>>): OperatorFunction<In, Out> {
|
||||
export function filterMap<In, Out>(
|
||||
cb: (i: In) => Awaitable<Result<Out, unknown>>,
|
||||
): OperatorFunction<In, Out> {
|
||||
return pipe(
|
||||
switchMap(async input => cb(input)),
|
||||
concatMap(s => {
|
||||
if(s.ok) {
|
||||
return of(s.val)
|
||||
if (s.ok) {
|
||||
return of(s.val);
|
||||
}
|
||||
return EMPTY;
|
||||
})
|
||||
)
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,7 +63,6 @@ export function callPlugin(args: unknown): OperatorFunction<
|
||||
|
||||
export const arrayifySource = map(src => (Array.isArray(src) ? (src as unknown[]) : [src]));
|
||||
|
||||
|
||||
/**
|
||||
* If the current value in Result stream is an error, calls callback.
|
||||
* This also extracts the Ok value from Result
|
||||
@@ -75,7 +89,5 @@ export const everyPluginOk: OperatorFunction<VoidResult, boolean> = pipe(
|
||||
);
|
||||
|
||||
export const sharedObservable = <T>(e: EventEmitter, eventName: string) => {
|
||||
return (fromEvent(e, eventName) as Observable<T>).pipe(share())
|
||||
return (fromEvent(e, eventName) as Observable<T>).pipe(share());
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ export function makePlugin<V extends unknown[]>(
|
||||
): Plugin<V> {
|
||||
return {
|
||||
type,
|
||||
execute
|
||||
execute,
|
||||
} as Plugin<V>;
|
||||
}
|
||||
/**
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
import { AnySelectMenuInteraction, AutocompleteInteraction, ButtonInteraction, ChatInputCommandInteraction, MessageContextMenuCommandInteraction, ModalSubmitInteraction, UserContextMenuCommandInteraction } from "discord.js";
|
||||
import { InteractionType } from "discord.js";
|
||||
import {
|
||||
AnySelectMenuInteraction,
|
||||
AutocompleteInteraction,
|
||||
ButtonInteraction,
|
||||
ChatInputCommandInteraction,
|
||||
MessageContextMenuCommandInteraction,
|
||||
ModalSubmitInteraction,
|
||||
UserContextMenuCommandInteraction,
|
||||
} from 'discord.js';
|
||||
import { InteractionType } from 'discord.js';
|
||||
|
||||
interface InteractionTypable {
|
||||
type: InteractionType
|
||||
type: InteractionType;
|
||||
}
|
||||
//discord.js pls fix ur typings or i will >:(
|
||||
type AnyMessageComponentInteraction = AnySelectMenuInteraction | ButtonInteraction;
|
||||
type AnyCommandInteraction = ChatInputCommandInteraction | MessageContextMenuCommandInteraction | UserContextMenuCommandInteraction;
|
||||
type AnyCommandInteraction =
|
||||
| ChatInputCommandInteraction
|
||||
| MessageContextMenuCommandInteraction
|
||||
| UserContextMenuCommandInteraction;
|
||||
export function isMessageComponent(i: InteractionTypable): i is AnyMessageComponentInteraction {
|
||||
return i.type === InteractionType.MessageComponent;
|
||||
}
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import { Result as Either } from 'ts-results-es';
|
||||
import { SernError } from './errors';
|
||||
import * as assert from 'node:assert'
|
||||
|
||||
import * as assert from 'node:assert';
|
||||
|
||||
/**
|
||||
* @since 3.0.0
|
||||
*/
|
||||
* @since 3.0.0
|
||||
*/
|
||||
export abstract class CoreContext<M, I> {
|
||||
protected constructor(protected ctx: Either<M, I>) {
|
||||
assert.ok(typeof ctx.val === 'object' && ctx.val != null)
|
||||
assert.ok(typeof ctx.val === 'object' && ctx.val != null);
|
||||
}
|
||||
get message(): M {
|
||||
return this.ctx.expect(SernError.MismatchEvent);
|
||||
}
|
||||
get interaction(): I {
|
||||
}
|
||||
get interaction(): I {
|
||||
return this.ctx.expectErr(SernError.MismatchEvent);
|
||||
}
|
||||
|
||||
@@ -25,11 +24,11 @@ export abstract class CoreContext<M, I> {
|
||||
return !this.isMessage();
|
||||
}
|
||||
//todo: add agnostic options resolver for Context
|
||||
abstract get options() : unknown
|
||||
|
||||
abstract get id() : string
|
||||
abstract get options(): unknown;
|
||||
|
||||
static wrap(_: unknown): unknown { throw Error("You need to override this method; cannot wrap an abstract class") }
|
||||
|
||||
abstract get id(): string;
|
||||
|
||||
static wrap(_: unknown): unknown {
|
||||
throw Error('You need to override this method; cannot wrap an abstract class');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,12 +15,12 @@
|
||||
* ```
|
||||
*/
|
||||
export enum CommandType {
|
||||
Text = 1 << 0,
|
||||
Slash = 1 << 1,
|
||||
Both = 3,
|
||||
Text = 1 << 0,
|
||||
Slash = 1 << 1,
|
||||
Both = 3,
|
||||
CtxUser = 1 << 2,
|
||||
CtxMsg = 1 << 3,
|
||||
Button = 1 << 4,
|
||||
CtxMsg = 1 << 3,
|
||||
Button = 1 << 4,
|
||||
StringSelect = 1 << 5,
|
||||
Modal = 1 << 6,
|
||||
ChannelSelect = 1 << 7,
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export * from './enums';
|
||||
export * from './context'
|
||||
export * from './sernEmitter'
|
||||
export * from './context';
|
||||
export * from './sernEmitter';
|
||||
|
||||
@@ -84,4 +84,3 @@ export class SernEmitter extends EventEmitter {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,13 +12,18 @@ export function contextArgs(
|
||||
/*
|
||||
* @overload
|
||||
*/
|
||||
export function contextArgs(wrappable: ChatInputCommandInteraction): () => [Context, ['slash', SlashOptions]];
|
||||
export function contextArgs(
|
||||
wrappable: ChatInputCommandInteraction,
|
||||
): () => [Context, ['slash', SlashOptions]];
|
||||
/**
|
||||
* function overloads to create an arguments list for Context
|
||||
* @param wrap
|
||||
* @param messageArgs
|
||||
*/
|
||||
export function contextArgs(wrappable: Message | ChatInputCommandInteraction, messageArgs?: string[]) {
|
||||
export function contextArgs(
|
||||
wrappable: Message | ChatInputCommandInteraction,
|
||||
messageArgs?: string[],
|
||||
) {
|
||||
const ctx = Context.wrap(wrappable);
|
||||
const args = ctx.isMessage() ? ['text', messageArgs!] : ['slash', ctx.options];
|
||||
return () => [ctx, args] as [Context, Args];
|
||||
@@ -27,4 +32,3 @@ export function contextArgs(wrappable: Message | ChatInputCommandInteraction, me
|
||||
export function interactionArg<T>(interaction: T) {
|
||||
return () => [interaction] as [T];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
import { BaseInteraction, ChatInputCommandInteraction, Interaction, InteractionType, Message } from "discord.js";
|
||||
import { Observable, filter, map } from "rxjs";
|
||||
import { CommandType, ModuleManager } from "../../core";
|
||||
import { SernError } from '../../core/structures/errors'
|
||||
import {
|
||||
BaseInteraction,
|
||||
ChatInputCommandInteraction,
|
||||
Interaction,
|
||||
InteractionType,
|
||||
Message,
|
||||
} from 'discord.js';
|
||||
import { Observable, filter, map } from 'rxjs';
|
||||
import { CommandType, ModuleManager } from '../../core';
|
||||
import { SernError } from '../../core/structures/errors';
|
||||
import { filterMap } from '../../core/operators';
|
||||
import { defaultModuleLoader } from "../../core/module-loading";
|
||||
import { Processed } from "../../types/core";
|
||||
import { BothCommand, CommandModule, Module } from "../../types/module";
|
||||
import { contextArgs, dispatchAutocomplete, dispatchCommand, interactionArg } from "./dispatchers";
|
||||
import { isAutocomplete } from "../../core/predicates";
|
||||
import { ObservableInput, pipe, switchMap} from "rxjs";
|
||||
import { SernEmitter } from "../../core";
|
||||
import { defaultModuleLoader } from '../../core/module-loading';
|
||||
import { Processed } from '../../types/core';
|
||||
import { BothCommand, CommandModule, Module } from '../../types/module';
|
||||
import { contextArgs, dispatchAutocomplete, dispatchCommand, interactionArg } from './dispatchers';
|
||||
import { isAutocomplete } from '../../core/predicates';
|
||||
import { ObservableInput, pipe, switchMap } from 'rxjs';
|
||||
import { SernEmitter } from '../../core';
|
||||
import { errTap } from '../../core/operators';
|
||||
import * as Files from '../../core/module-loading';
|
||||
import { sernMeta } from "../../commands";
|
||||
import { AnyModule } from "../../types/module";
|
||||
import { Err, Result } from "ts-results-es";
|
||||
import { Awaitable } from "../../types/handler";
|
||||
import { fmt } from "./messages";
|
||||
|
||||
|
||||
import { sernMeta } from '../../commands';
|
||||
import { AnyModule } from '../../types/module';
|
||||
import { Err, Result } from 'ts-results-es';
|
||||
import { Awaitable } from '../../types/handler';
|
||||
import { fmt } from './messages';
|
||||
|
||||
function createGenericHandler<Source, Narrowed extends Source, Output>(
|
||||
source: Observable<Source>,
|
||||
makeModule: (event: Narrowed) => Awaitable<Result<Output, unknown>>
|
||||
makeModule: (event: Narrowed) => Awaitable<Result<Output, unknown>>,
|
||||
) {
|
||||
return (pred: (i: Source) => i is Narrowed) =>
|
||||
source.pipe(
|
||||
filter(pred),
|
||||
filterMap(makeModule)
|
||||
)
|
||||
return (pred: (i: Source) => i is Narrowed) => source.pipe(filter(pred), filterMap(makeModule));
|
||||
}
|
||||
/**
|
||||
*
|
||||
@@ -43,37 +43,33 @@ export function createInteractionHandler<T extends Interaction>(
|
||||
) {
|
||||
return createGenericHandler<Interaction, T, ReturnType<typeof createDispatcher>>(
|
||||
source,
|
||||
( event ) => {
|
||||
const fullPath = mg.get(createId(event as unknown as Interaction))
|
||||
if(!fullPath) return Err(SernError.UndefinedModule + " No full path found in module store");
|
||||
return defaultModuleLoader<CommandModule>(fullPath)
|
||||
.then(res =>
|
||||
res.map(module => createDispatcher({ module, event }))
|
||||
)
|
||||
}
|
||||
)
|
||||
event => {
|
||||
const fullPath = mg.get(createId(event as unknown as Interaction));
|
||||
if (!fullPath)
|
||||
return Err(SernError.UndefinedModule + ' No full path found in module store');
|
||||
return defaultModuleLoader<CommandModule>(fullPath).then(res =>
|
||||
res.map(module => createDispatcher({ module, event })),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export function createMessageHandler(
|
||||
source: Observable<Message>,
|
||||
defaultPrefix: string,
|
||||
mg: ModuleManager
|
||||
mg: ModuleManager,
|
||||
) {
|
||||
return createGenericHandler(
|
||||
source,
|
||||
( event ) => {
|
||||
const [prefix, ...rest] = fmt(event.content, defaultPrefix);
|
||||
const fullPath = mg.get(`${prefix}__A0`);
|
||||
if (fullPath === undefined) {
|
||||
return Err(SernError.UndefinedModule + " No full path found in module store");
|
||||
}
|
||||
return defaultModuleLoader<CommandModule>(fullPath).then(
|
||||
result => {
|
||||
const args = contextArgs(event, rest);
|
||||
return result.map(module => dispatchCommand(module, args))
|
||||
})
|
||||
return createGenericHandler(source, event => {
|
||||
const [prefix, ...rest] = fmt(event.content, defaultPrefix);
|
||||
const fullPath = mg.get(`${prefix}__A0`);
|
||||
if (fullPath === undefined) {
|
||||
return Err(SernError.UndefinedModule + ' No full path found in module store');
|
||||
}
|
||||
)
|
||||
return defaultModuleLoader<CommandModule>(fullPath).then(result => {
|
||||
const args = contextArgs(event, rest);
|
||||
return result.map(module => dispatchCommand(module, args));
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Creates a unique ID for a given interaction object.
|
||||
@@ -81,21 +77,27 @@ export function createMessageHandler(
|
||||
* @returns A unique string ID based on the type and properties of the interaction object.
|
||||
*/
|
||||
function createId<T extends Interaction>(event: T) {
|
||||
let id: string;
|
||||
switch(event.type) {
|
||||
case InteractionType.MessageComponent: {
|
||||
let id: string;
|
||||
switch (event.type) {
|
||||
case InteractionType.MessageComponent:
|
||||
{
|
||||
id = `${event.customId}__C${event.componentType}`;
|
||||
} break;
|
||||
case InteractionType.ApplicationCommand:
|
||||
case InteractionType.ApplicationCommandAutocomplete: {
|
||||
}
|
||||
break;
|
||||
case InteractionType.ApplicationCommand:
|
||||
case InteractionType.ApplicationCommandAutocomplete:
|
||||
{
|
||||
id = `${event.commandName}__A${event.commandType}`;
|
||||
console.log(id)
|
||||
} break;
|
||||
case InteractionType.ModalSubmit: {
|
||||
console.log(id);
|
||||
}
|
||||
break;
|
||||
case InteractionType.ModalSubmit:
|
||||
{
|
||||
id = `${event.customId}__C1`;
|
||||
} break;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
function createDispatcher({
|
||||
@@ -107,7 +109,7 @@ function createDispatcher({
|
||||
}) {
|
||||
switch (module.type) {
|
||||
case CommandType.Text:
|
||||
throw Error(SernError.MismatchEvent+ " Found a text module in interaction stream.");
|
||||
throw Error(SernError.MismatchEvent + ' Found a text module in interaction stream.');
|
||||
case CommandType.Slash:
|
||||
case CommandType.Both: {
|
||||
if (isAutocomplete(event)) {
|
||||
@@ -117,7 +119,7 @@ function createDispatcher({
|
||||
* too different from regular command modules
|
||||
*/
|
||||
return dispatchAutocomplete(module as Processed<BothCommand>, event);
|
||||
}
|
||||
}
|
||||
return dispatchCommand(module, contextArgs(event as ChatInputCommandInteraction));
|
||||
}
|
||||
default:
|
||||
@@ -125,16 +127,15 @@ function createDispatcher({
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function buildModules<T extends AnyModule>(
|
||||
input: ObservableInput<string>, sernEmitter: SernEmitter
|
||||
input: ObservableInput<string>,
|
||||
sernEmitter: SernEmitter,
|
||||
) {
|
||||
return pipe(
|
||||
switchMap(() => Files.buildModuleStream<T>(input)),
|
||||
errTap(error => {
|
||||
sernEmitter.emit('module.register', SernEmitter.failure(undefined, error));
|
||||
}),
|
||||
map(module => ({ module, absPath: module[sernMeta].fullPath }))
|
||||
map(module => ({ module, absPath: module[sernMeta].fullPath })),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,37 +1,30 @@
|
||||
import { BaseInteraction, Interaction } from 'discord.js';
|
||||
import {
|
||||
catchError,
|
||||
concatMap,
|
||||
finalize,
|
||||
merge,
|
||||
} from 'rxjs';
|
||||
import { catchError, concatMap, finalize, merge } from 'rxjs';
|
||||
import { SernError } from '../../core/structures/errors';
|
||||
import { executeModule, makeModuleExecutor } from './observableHandling';
|
||||
import { ErrorHandling, handleError } from '../../core/contracts/errorHandling';
|
||||
import { SernEmitter, WebsocketStrategy } from '../../core';
|
||||
import { sharedObservable } from '../../core/operators'
|
||||
import { sharedObservable } from '../../core/operators';
|
||||
import { useContainerRaw } from '../../core/dependencies';
|
||||
import type { Logging, ModuleManager } from '../../core/contracts';
|
||||
import type { EventEmitter } from 'node:events';
|
||||
import { isAutocomplete, isCommand, isMessageComponent, isModal } from '../../core/predicates';
|
||||
import { createInteractionHandler } from './generic';
|
||||
|
||||
|
||||
export function makeInteractionCreate([s, err, log, modules, client]: [
|
||||
SernEmitter,
|
||||
ErrorHandling,
|
||||
Logging | undefined,
|
||||
ModuleManager,
|
||||
EventEmitter
|
||||
]
|
||||
) {
|
||||
EventEmitter,
|
||||
]) {
|
||||
const interactionStream$ = sharedObservable<Interaction>(client, 'interactionCreate');
|
||||
const handle = createInteractionHandler<Interaction>(interactionStream$, modules);
|
||||
const interactionHandler$ = merge(
|
||||
handle(isMessageComponent),
|
||||
handle(isAutocomplete),
|
||||
handle(isCommand),
|
||||
handle(isModal)
|
||||
handle(isModal),
|
||||
);
|
||||
return interactionHandler$
|
||||
.pipe(
|
||||
|
||||
@@ -37,29 +37,26 @@ export function makeMessageCreate(
|
||||
ModuleManager,
|
||||
EventEmitter,
|
||||
],
|
||||
defaultPrefix: string | undefined
|
||||
defaultPrefix: string | undefined,
|
||||
) {
|
||||
if(!defaultPrefix) {
|
||||
log?.debug({ message: 'No prefix found. message handler shut down' })
|
||||
return EMPTY.subscribe()
|
||||
if (!defaultPrefix) {
|
||||
log?.debug({ message: 'No prefix found. message handler shut down' });
|
||||
return EMPTY.subscribe();
|
||||
}
|
||||
const messageStream$ = sharedObservable<Message>(client, 'messageCreate');
|
||||
const handler = createMessageHandler(messageStream$, defaultPrefix, modules);
|
||||
const messageHandler = handler(
|
||||
ignoreNonBot(defaultPrefix) as (m: Message) => m is Message
|
||||
)
|
||||
return messageHandler
|
||||
.pipe(
|
||||
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' }));
|
||||
}),
|
||||
)
|
||||
const messageHandler = handler(ignoreNonBot(defaultPrefix) as (m: Message) => m is Message);
|
||||
return messageHandler.pipe(
|
||||
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' }));
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,20 +6,18 @@ import { callPlugin, everyPluginOk, filterMapTo } from '../../core/operators';
|
||||
import type { ImportPayload, Processed } from '../../types/core';
|
||||
import type { ControlPlugin, VoidResult } from '../../types/plugin';
|
||||
import { Awaitable } from '../../types/handler';
|
||||
import { Message } from 'discord.js'
|
||||
import { Message } from 'discord.js';
|
||||
function hasPrefix(prefix: string, content: string) {
|
||||
const prefixInContent = content.slice(0, prefix.length);
|
||||
return prefixInContent.localeCompare(prefix, undefined, { sensitivity: 'accent' }) === 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ignores messages from any person / bot except itself
|
||||
* @param prefix
|
||||
*/
|
||||
export function ignoreNonBot(prefix: string) {
|
||||
return ({ author, content }: Message) =>
|
||||
!author.bot && hasPrefix(prefix, content);
|
||||
return ({ author, content }: Message) => !author.bot && hasPrefix(prefix, content);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,7 +74,7 @@ export function createResultResolver<
|
||||
const task$ = config.createStream(args);
|
||||
return task$.pipe(
|
||||
tap(result => {
|
||||
result.err && config.onStop?.(args.module);
|
||||
result.err && config.onStop?.(args.module);
|
||||
}),
|
||||
everyPluginOk,
|
||||
filterMapTo(() => config.onNext(args)),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ObservableInput, fromEvent, of, take } from 'rxjs';
|
||||
import { callInitPlugins } from './observableHandling';
|
||||
import { CommandType } from '../../core/structures';
|
||||
import { SernError } from '../../core/structures/errors'
|
||||
import { SernError } from '../../core/structures/errors';
|
||||
import { Result } from 'ts-results-es';
|
||||
import type { ModuleManager } from '../../core/contracts';
|
||||
import { SernEmitter, PlatformStrategy, DispatchType } from '../../core';
|
||||
@@ -12,7 +12,9 @@ import * as assert from 'node:assert';
|
||||
import { buildModules } from './generic';
|
||||
|
||||
export function startReadyEvent(
|
||||
[sEmitter, errorHandler, , moduleManager, client]: ServerlessDependencyList | WebsocketDependencyList,
|
||||
[sEmitter, errorHandler, , moduleManager, client]:
|
||||
| ServerlessDependencyList
|
||||
| WebsocketDependencyList,
|
||||
input: ObservableInput<string>,
|
||||
) {
|
||||
const ready$ = fromEvent(client!, 'interactionCreate').pipe(take(1));
|
||||
@@ -40,19 +42,15 @@ export function startReadyEvent(
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function registerModule<T extends Processed<Module>>(
|
||||
manager: ModuleManager,
|
||||
module: T,
|
||||
): Result<void, void> {
|
||||
const { id, fullPath } = module[sernMeta];
|
||||
if(module.type === CommandType.Both || module.type === CommandType.Text) {
|
||||
assert.ok('alias' in module)
|
||||
assert.ok(Array.isArray(module.alias))
|
||||
module.alias?.forEach(a => manager.set(`${a}__A0` , fullPath))
|
||||
const { id, fullPath } = module[sernMeta];
|
||||
if (module.type === CommandType.Both || module.type === CommandType.Text) {
|
||||
assert.ok('alias' in module);
|
||||
assert.ok(Array.isArray(module.alias));
|
||||
module.alias?.forEach(a => manager.set(`${a}__A0`, fullPath));
|
||||
}
|
||||
return Result.wrap(() => manager.set(id, fullPath))
|
||||
return Result.wrap(() => manager.set(id, fullPath));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { CommandModule, EventModule } from '../../types/module';
|
||||
import type { EventEmitter } from 'node:events';
|
||||
import { SernEmitter } from '../../core';
|
||||
import type { ErrorHandling, Logging } from '../../core/contracts';
|
||||
import { EventType } from '../../core/structures'
|
||||
import { EventType } from '../../core/structures';
|
||||
import { SernError } from '../../core/structures/errors';
|
||||
import { eventDispatcher } from './dispatchers';
|
||||
import { handleError } from '../../core/contracts/errorHandling';
|
||||
@@ -32,29 +32,31 @@ export function makeEventsHandler(
|
||||
);
|
||||
}
|
||||
};
|
||||
of(null).pipe(
|
||||
buildModules(eventsPath, s),
|
||||
callInitPlugins({
|
||||
onStop: module =>
|
||||
s.emit('module.register', SernEmitter.failure(module, SernError.PluginFailure)),
|
||||
onNext: ({ module }) => {
|
||||
s.emit('module.register', SernEmitter.success(module));
|
||||
return module;
|
||||
},
|
||||
}),
|
||||
map(intoDispatcher),
|
||||
/**
|
||||
* Where all events are turned on
|
||||
*/
|
||||
mergeAll(),
|
||||
catchError(handleError(err, log)),
|
||||
finalize(() => {
|
||||
log?.info({ message: 'an event module reached end of lifetime' });
|
||||
useContainerRaw()
|
||||
?.disposeAll()
|
||||
.then(() => {
|
||||
log?.info({ message: 'Cleaning container and crashing' });
|
||||
});
|
||||
}),
|
||||
).subscribe();
|
||||
of(null)
|
||||
.pipe(
|
||||
buildModules(eventsPath, s),
|
||||
callInitPlugins({
|
||||
onStop: module =>
|
||||
s.emit('module.register', SernEmitter.failure(module, SernError.PluginFailure)),
|
||||
onNext: ({ module }) => {
|
||||
s.emit('module.register', SernEmitter.success(module));
|
||||
return module;
|
||||
},
|
||||
}),
|
||||
map(intoDispatcher),
|
||||
/**
|
||||
* Where all events are turned on
|
||||
*/
|
||||
mergeAll(),
|
||||
catchError(handleError(err, log)),
|
||||
finalize(() => {
|
||||
log?.info({ message: 'an event module reached end of lifetime' });
|
||||
useContainerRaw()
|
||||
?.disposeAll()
|
||||
.then(() => {
|
||||
log?.info({ message: 'Cleaning container and crashing' });
|
||||
});
|
||||
}),
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
@@ -27,7 +27,9 @@ export function init(wrapper: Wrapper) {
|
||||
const dependencies = dependenciesAnd(['@sern/modules', '@sern/client']);
|
||||
if (wrapper.events !== undefined) {
|
||||
makeEventsHandler(
|
||||
dependenciesAnd(['@sern/client']), wrapper.events, wrapper.containerConfig
|
||||
dependenciesAnd(['@sern/client']),
|
||||
wrapper.events,
|
||||
wrapper.containerConfig,
|
||||
);
|
||||
}
|
||||
startReadyEvent(dependencies, getCommands(wrapper.commands));
|
||||
@@ -35,16 +37,15 @@ export function init(wrapper: Wrapper) {
|
||||
makeInteractionCreate(dependencies);
|
||||
const endTime = performance.now();
|
||||
dependencies[2]?.info({ message: `sern : ${(endTime - startTime).toFixed(2)} ms` });
|
||||
|
||||
}
|
||||
/**
|
||||
* @deprecated - Please import the function directly:
|
||||
* ```ts
|
||||
* import { makeDependencies } from '@sern/handler'
|
||||
*
|
||||
* ```
|
||||
*/
|
||||
export { makeDependencies }
|
||||
* @deprecated - Please import the function directly:
|
||||
* ```ts
|
||||
* import { makeDependencies } from '@sern/handler'
|
||||
*
|
||||
* ```
|
||||
*/
|
||||
export { makeDependencies };
|
||||
/**
|
||||
* @since 1.0.0
|
||||
* The object passed into every plugin to control a command's behavior
|
||||
@@ -53,4 +54,3 @@ export const controller = {
|
||||
next: ok,
|
||||
stop: err,
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,6 @@ export * from './types/handler';
|
||||
export * from './types/module';
|
||||
export * from './types/plugin';
|
||||
export * from './core';
|
||||
export { controller } from './handler/sern'
|
||||
export { commandModule, eventModule } from './commands'
|
||||
export { Context } from './classic/context'
|
||||
export { controller } from './handler/sern';
|
||||
export { commandModule, eventModule } from './commands';
|
||||
export { Context } from './classic/context';
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
import { type EventEmitter } from "node:events";
|
||||
import { ErrorHandling, Logging, ModuleManager, SernEmitter } from "../core";
|
||||
import { Container, UnpackFunction } from "iti";
|
||||
import { type EventEmitter } from 'node:events';
|
||||
import { ErrorHandling, Logging, ModuleManager, SernEmitter } from '../core';
|
||||
import { Container, UnpackFunction } from 'iti';
|
||||
|
||||
export type ModuleStore = Map<string,string>
|
||||
export type ServerlessDependencyList = [ SernEmitter,ErrorHandling, Logging | undefined, ModuleManager];
|
||||
export type WebsocketDependencyList = [SernEmitter,ErrorHandling, Logging | undefined, ModuleManager, EventEmitter];
|
||||
export type ModuleStore = Map<string, string>;
|
||||
export type ServerlessDependencyList = [
|
||||
SernEmitter,
|
||||
ErrorHandling,
|
||||
Logging | undefined,
|
||||
ModuleManager,
|
||||
];
|
||||
export type WebsocketDependencyList = [
|
||||
SernEmitter,
|
||||
ErrorHandling,
|
||||
Logging | undefined,
|
||||
ModuleManager,
|
||||
EventEmitter,
|
||||
];
|
||||
/**
|
||||
* After modules are transformed, name and description are given default values if none
|
||||
* are provided to Module. This type represents that transformation
|
||||
@@ -22,20 +33,18 @@ export interface CoreDependencies {
|
||||
'@sern/errors': Singleton<ErrorHandling>;
|
||||
}
|
||||
/**
|
||||
* To support older versions. Type alias for WebsocketDependencies
|
||||
* @deprecated
|
||||
*/
|
||||
export type Dependencies = WebsocketDependencies
|
||||
* To support older versions. Type alias for WebsocketDependencies
|
||||
* @deprecated
|
||||
*/
|
||||
export type Dependencies = WebsocketDependencies;
|
||||
export interface ServerlessDependencies extends CoreDependencies {
|
||||
'@sern/client': never
|
||||
'@sern/client': never;
|
||||
}
|
||||
|
||||
export interface WebsocketDependencies extends CoreDependencies {
|
||||
'@sern/client': Singleton<EventEmitter>;
|
||||
}
|
||||
export type AnyDependencies =
|
||||
| ServerlessDependencies
|
||||
| WebsocketDependencies;
|
||||
export type AnyDependencies = ServerlessDependencies | WebsocketDependencies;
|
||||
|
||||
//prettier-ignore
|
||||
export type MapDeps<Deps extends AnyDependencies, T extends readonly unknown[]> = T extends [
|
||||
@@ -58,8 +67,8 @@ export interface DependencyConfiguration<T extends AnyDependencies> {
|
||||
|
||||
export interface ImportPayload<T> {
|
||||
module: T;
|
||||
absPath: string
|
||||
};
|
||||
absPath: string;
|
||||
}
|
||||
|
||||
export interface Wrapper {
|
||||
commands: string;
|
||||
@@ -67,5 +76,5 @@ export interface Wrapper {
|
||||
events?: string;
|
||||
containerConfig: {
|
||||
get: (...keys: (keyof WebsocketDependencies)[]) => unknown[];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import type { InteractionReplyOptions, MessageReplyOptions, CommandInteractionOptionResolver } from 'discord.js';
|
||||
import type {
|
||||
InteractionReplyOptions,
|
||||
MessageReplyOptions,
|
||||
CommandInteractionOptionResolver,
|
||||
} from 'discord.js';
|
||||
import { Processed } from './core';
|
||||
import { AnyModule, CommandModule, EventModule } from './module';
|
||||
import { PayloadType } from '../core';
|
||||
@@ -14,13 +18,11 @@ export type Args = ParseType<{ text: string[]; slash: SlashOptions }>;
|
||||
|
||||
export type SlashOptions = Omit<CommandInteractionOptionResolver, 'getMessage' | 'getFocused'>;
|
||||
|
||||
|
||||
export type ReplyOptions =
|
||||
| string
|
||||
| Omit<InteractionReplyOptions, 'fetchReply'>
|
||||
| MessageReplyOptions;
|
||||
|
||||
|
||||
export type AnyDefinedModule = Processed<CommandModule | EventModule>;
|
||||
export type Payload =
|
||||
| { type: PayloadType.Success; module: AnyModule }
|
||||
@@ -32,4 +34,4 @@ export interface SernEventsMapping {
|
||||
'module.activate': [Payload];
|
||||
error: [Payload];
|
||||
warning: [Payload];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import type {
|
||||
ApplicationCommandSubGroupData,
|
||||
BaseApplicationCommandOptionsData,
|
||||
} from 'discord.js';
|
||||
import {
|
||||
import {
|
||||
AutocompleteInteraction,
|
||||
ButtonInteraction,
|
||||
ChannelSelectMenuInteraction,
|
||||
@@ -21,13 +21,12 @@ import {
|
||||
RoleSelectMenuInteraction,
|
||||
StringSelectMenuInteraction,
|
||||
UserContextMenuCommandInteraction,
|
||||
UserSelectMenuInteraction
|
||||
|
||||
} from "discord.js";
|
||||
import { InitArgs, } from "../core";
|
||||
import { Args, Payload, SlashOptions } from "../types/handler";
|
||||
import { Context } from "../classic/context";
|
||||
import { Processed } from "../types/core";
|
||||
UserSelectMenuInteraction,
|
||||
} from 'discord.js';
|
||||
import { InitArgs } from '../core';
|
||||
import { Args, Payload, SlashOptions } from '../types/handler';
|
||||
import { Context } from '../classic/context';
|
||||
import { Processed } from '../types/core';
|
||||
import { CommandType, PluginType } from '../core/structures/enums';
|
||||
import type { Awaitable, SernEventsMapping } from './handler';
|
||||
import type { InitPlugin, ControlPlugin } from './plugin';
|
||||
@@ -36,8 +35,8 @@ import type { AnyCommandPlugin, AnyEventPlugin } from './plugin';
|
||||
import { sernMeta } from '../commands';
|
||||
|
||||
interface CommandMeta {
|
||||
fullPath: string;
|
||||
id: string;
|
||||
fullPath: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface Module {
|
||||
@@ -46,14 +45,14 @@ export interface Module {
|
||||
onEvent: ControlPlugin[];
|
||||
plugins: InitPlugin[];
|
||||
description?: string;
|
||||
[sernMeta] : CommandMeta
|
||||
[sernMeta]: CommandMeta;
|
||||
execute: (...args: any[]) => Awaitable<any>;
|
||||
}
|
||||
export interface CommandTypeModule extends Module {
|
||||
type: CommandType
|
||||
type: CommandType;
|
||||
}
|
||||
export interface EventTypeModule extends Module {
|
||||
type: EventType
|
||||
type: EventType;
|
||||
}
|
||||
export interface SernEventCommand<T extends keyof SernEventsMapping = keyof SernEventsMapping>
|
||||
extends Module {
|
||||
@@ -68,7 +67,6 @@ export interface ExternalEventCommand extends Module {
|
||||
execute(...args: unknown[]): Awaitable<unknown>;
|
||||
}
|
||||
|
||||
|
||||
export interface ContextMenuUser extends Module {
|
||||
type: CommandType.CtxUser;
|
||||
execute: (ctx: UserContextMenuCommandInteraction) => Awaitable<unknown>;
|
||||
@@ -195,7 +193,7 @@ export interface CommandArgsMatrix {
|
||||
[PluginType.Control]: [/* library coupled */ ModalSubmitInteraction];
|
||||
[PluginType.Init]: [InitArgs<Processed<ModalSubmitCommand>>];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface EventArgsMatrix {
|
||||
[EventType.Discord]: {
|
||||
@@ -210,7 +208,7 @@ export interface EventArgsMatrix {
|
||||
[PluginType.Control]: unknown[];
|
||||
[PluginType.Init]: [InitArgs<Processed<ExternalEventCommand>>];
|
||||
};
|
||||
};
|
||||
}
|
||||
export type EventModule = DiscordEventCommand | SernEventCommand | ExternalEventCommand;
|
||||
export type CommandModule =
|
||||
| TextCommand
|
||||
@@ -243,13 +241,13 @@ export interface CommandModuleDefs {
|
||||
[CommandType.MentionableSelect]: MentionableSelectCommand;
|
||||
[CommandType.UserSelect]: UserSelectCommand;
|
||||
[CommandType.Modal]: ModalSubmitCommand;
|
||||
};
|
||||
}
|
||||
|
||||
export interface EventModuleDefs {
|
||||
[EventType.Sern]: SernEventCommand;
|
||||
[EventType.Discord]: DiscordEventCommand;
|
||||
[EventType.External]: ExternalEventCommand;
|
||||
};
|
||||
}
|
||||
|
||||
export interface SernAutocompleteData
|
||||
extends Omit<BaseApplicationCommandOptionsData, 'autocomplete'> {
|
||||
|
||||
@@ -40,4 +40,3 @@ export interface ControlPlugin<Args extends any[] = any[]> {
|
||||
|
||||
export type AnyCommandPlugin = ControlPlugin | InitPlugin<[InitArgs<Processed<CommandModule>>]>;
|
||||
export type AnyEventPlugin = ControlPlugin | InitPlugin<[InitArgs<Processed<EventModule>>]>;
|
||||
|
||||
|
||||
@@ -19,10 +19,8 @@ export default defineConfig([
|
||||
target: 'node16',
|
||||
tsconfig: './tsconfig-esm.json',
|
||||
outDir: './dist/esm',
|
||||
splitting: false,
|
||||
esbuildPlugins: [
|
||||
ifdefPlugin({ variables: { MODE: 'esm' }, verbose: true }),
|
||||
],
|
||||
splitting: false,
|
||||
esbuildPlugins: [ifdefPlugin({ variables: { MODE: 'esm' }, verbose: true })],
|
||||
outExtension() {
|
||||
return {
|
||||
js: '.mjs',
|
||||
|
||||
Reference in New Issue
Block a user