diff --git a/package.json b/package.json index 8da8116..1161279 100644 --- a/package.json +++ b/package.json @@ -4,13 +4,19 @@ "version": "3.3.4", "description": "A complete, customizable, typesafe, & reactive framework for discord bots.", "main": "./dist/index.js", - "module": "./dist/index.mjs", + "module": "./dist/index.js", "types": "./dist/index.d.ts", "exports": { ".": { - "import": "./dist/index.mjs", + "import": "./dist/index.js", "require": "./dist/index.js", "types": "./dist/index.d.ts" + }, + "./internal": { + "import": "./dist/_internal.js", + "require": "./dist/_internal.js", + "types": "./dist/_internal.d.ts" + } }, "scripts": { diff --git a/src/_internal.ts b/src/_internal.ts new file mode 100644 index 0000000..93382d9 --- /dev/null +++ b/src/_internal.ts @@ -0,0 +1,34 @@ +import type { Interaction } from 'discord.js'; +import { mergeMap, merge, concatMap } from 'rxjs'; +import { PayloadType } from './core'; +import { + isAutocomplete, + isCommand, + isMessageComponent, + isModal, + sharedEventStream, + SernError, + filterTap, + resultPayload, +} from './core/_internal'; +import { createInteractionHandler, executeModule, makeModuleExecutor } from './handlers/event-utils'; +import type { DependencyList } from './types/ioc'; + + +export function interactionHandler([emitter, err, log, modules, client]: DependencyList) { + const interactionStream$ = sharedEventStream(client, 'interactionCreate'); + const handle = createInteractionHandler(interactionStream$, modules); + + const interactionHandler$ = merge( + handle(isMessageComponent), + handle(isAutocomplete), + handle(isCommand), + handle(isModal), + ); + return interactionHandler$ + .pipe( + filterTap(e => emitter.emit('warning', resultPayload(PayloadType.Warning, undefined, e))), + concatMap(makeModuleExecutor(module => + emitter.emit('module.activate', resultPayload(PayloadType.Failure, module, SernError.PluginFailure)))), + mergeMap(payload => executeModule(emitter, log, err, payload))); +} diff --git a/src/core/module-loading.ts b/src/core/module-loading.ts index 48c6886..b2be6ab 100644 --- a/src/core/module-loading.ts +++ b/src/core/module-loading.ts @@ -1,9 +1,6 @@ import path from 'node:path'; import assert from 'assert'; -import { createRequire } from 'node:module'; -import type { Wrapper } from '../types/core'; import { existsSync } from 'fs'; -import type { Logging } from './interfaces'; export const parseCallsite = (fpath: string) => { @@ -54,32 +51,3 @@ export const fmtFileName = (fileName: string) => path.parse(fileName).name; export const filename = (p: string) => fmtFileName(path.basename(p)); -const requir = createRequire(import.meta.url); - -export function loadConfig(wrapper: Wrapper | 'file', log: Logging | undefined): Wrapper { - if (wrapper !== 'file') { - return wrapper; - } - log?.info({ message: 'Experimental loading of sern.config.json'}); - const config = requir(path.resolve('sern.config.json')); - - const makePath = (dir: PropertyKey) => - config.language === 'typescript' - ? path.join('dist', config.paths[dir]!) - : path.join(config.paths[dir]!); - - log?.info({ message: 'Loading config: ' + JSON.stringify(config, null, 4) }); - const commandsPath = makePath('commands'); - - log?.info({ message: `Commands path is set to ${commandsPath}` }); - let eventsPath: string | undefined; - if (config.paths.events) { - eventsPath = makePath('events'); - log?.info({ message: `Events path is set to ${eventsPath} `}); - } - - return { defaultPrefix: config.defaultPrefix, - commands: commandsPath, - events: eventsPath }; - -} diff --git a/src/core/modules.ts b/src/core/modules.ts index 96136aa..ea361bb 100644 --- a/src/core/modules.ts +++ b/src/core/modules.ts @@ -67,9 +67,6 @@ export function discordEvent(mod: { plugins?: AnyEventPlugin[]; execute: (...args: ClientEvents[T]) => Awaitable; }) { - return eventModule({ - type: EventType.Discord, - ...mod, - }); + return eventModule({ type: EventType.Discord, ...mod, }); } diff --git a/src/core/presences.ts b/src/core/presences.ts index 33ad8cd..dbd5c6b 100644 --- a/src/core/presences.ts +++ b/src/core/presences.ts @@ -3,65 +3,63 @@ import type { IntoDependencies } from "../types/ioc"; import type { Emitter } from "./interfaces"; type Status = 'online' | 'idle' | 'invisible' | 'dnd' -type PresenceReduce = (previous: Result) => Result; +type PresenceReduce = (previous: PresenceResult) => PresenceResult; -export interface Result { +export interface PresenceResult { status?: Status; afk?: boolean; activities?: ActivitiesOptions[]; shardId?: number[]; repeat?: number | [Emitter, string]; - onRepeat?: (previous: Result) => Result; + onRepeat?: (previous: PresenceResult) => PresenceResult; } -export type Config = -{ +export const Presence = { + /** + * A small wrapper to provide type inference. + * Create a Presence module which **MUST** be put in a file called presence.(language-extension) + * adjacent to the file where **Sern.init** is CALLED. + */ + module : (conf: PresenceConfig) => conf, + /** + * Create a Presence body which can be either: + * - once, the presence is activated only once. + * - repeated, per cycle or event, the presence can be changed. + */ + of : (root: Omit) => { + return { + /** + * @example + * Presence + * .of({ + * activities: [{ name: "deez nuts" }] + * }) //starts the presence with "deez nuts". + * .repeated(prev => { + * return { + * afk: true, + * activities: prev.activities?.map(s => ({ ...s, name: s.name+"s" })) + * }; + * }, 10000)) //every 10 s, the callback sets the presence to the returned one. + */ + repeated: (onRepeat: PresenceReduce, repeat: number | [Emitter, string]) => { + return { repeat, onRepeat, ...root } + }, + /** + * @example + * Presence + * .of({ + * activities: [ + * { name: "Chilling out" } + * ] + * }) + * .once() // Sets the presence once, with what's provided in '.of()' + */ + once: () => root + }; + } +} + +export type PresenceConfig = { inject?: [...T] - execute: (...v: IntoDependencies) => Result; + execute: (...v: IntoDependencies) => PresenceResult; }; - -/** - * A small wrapper to provide type inference. - * Create a Presence module which **MUST** be put in a file called presence.(language-extension) - * adjacent to the file where **Sern.init** is CALLED. - */ -export const module = (conf: Config) => conf; - - -/** - * Create a Presence body which can be either: - * - once, the presence is activated only once. - * - repeated, per cycle or event, the presence can be changed. - */ -export function of(root: Omit) { - return { - /** - * @example - * Presence - * .of({ - * activities: [{ name: "deez nuts" }] - * }) //starts the presence with "deez nuts". - * .repeated(prev => { - * return { - * afk: true, - * activities: prev.activities?.map(s => ({ ...s, name: s.name+"s" })) - * }; - * }, 10000)) //every 10 s, the callback sets the presence to the returned one. - */ - repeated: (onRepeat: PresenceReduce, repeat: number | [Emitter, string]) => { - return { repeat, onRepeat, ...root } - }, - /** - * @example - * Presence - * .of({ - * activities: [ - * { name: "Chilling out" } - * ] - * }) - * .once() // Sets the presence once, with what's provided in '.of()' - */ - once: () => root - }; -} - diff --git a/src/core/structures/default-services.ts b/src/core/structures/default-services.ts index c4c1169..2bcd41d 100644 --- a/src/core/structures/default-services.ts +++ b/src/core/structures/default-services.ts @@ -8,12 +8,10 @@ export class DefaultErrorHandling implements ErrorHandling { crash(err: Error): never { throw err; } - - #keepAlive = 1; - + keepAlive = 1; updateAlive(err: Error) { - this.#keepAlive--; - if (this.#keepAlive === 0) { + this.keepAlive--; + if (this.keepAlive === 0) { throw err; } } diff --git a/src/handlers/presence.ts b/src/handlers/presence.ts index 761fbb1..f5caa89 100644 --- a/src/handlers/presence.ts +++ b/src/handlers/presence.ts @@ -1,12 +1,12 @@ import { concatMap, from, interval, of, map, scan, startWith, fromEvent, take } from "rxjs" import { Files } from "../core/_internal"; -import * as Presence from "../core/presences"; +import { PresenceConfig, PresenceResult } from "../core/presences"; import { Services } from "../core/ioc"; import assert from "node:assert"; -type SetPresence = (conf: Presence.Result) => Promise +type SetPresence = (conf: PresenceResult) => Promise -const parseConfig = async (conf: Promise) => { +const parseConfig = async (conf: Promise) => { return conf.then(s => { if('repeat' in s) { const { onRepeat, repeat } = s; @@ -25,7 +25,7 @@ const parseConfig = async (conf: Promise) => { export const presenceHandler = (path: string, setPresence: SetPresence) => { interface PresenceModule { - module: Presence.Config<(keyof Dependencies)[]> + module: PresenceConfig<(keyof Dependencies)[]> } const presence = Files .importModule(path) diff --git a/src/index.ts b/src/index.ts index dcb35dc..06a2ccd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -50,6 +50,5 @@ export { discordEvent, } from './core/modules'; -export * as Presence from './core/presences' - +export * from './core/presences' diff --git a/src/sern.ts b/src/sern.ts index d716ee1..68f2dbb 100644 --- a/src/sern.ts +++ b/src/sern.ts @@ -1,17 +1,6 @@ -import { handleCrash } from './handlers/event-utils'; import callsites from 'callsites'; import { Files } from './core/_internal'; -import path from 'node:path' -import { merge } from 'rxjs'; import { Services } from './core/ioc'; -import { eventsHandler } from './handlers/user-defined-events'; -import { readyHandler } from './handlers/ready-event'; -import { messageHandler } from './handlers/message-event'; -import { interactionHandler } from './handlers/interaction-event'; -import { presenceHandler } from './handlers/presence'; -import type { Client } from 'discord.js'; -import { type Wrapper } from './'; - /** * @since 1.0.0 diff --git a/tsconfig.json b/tsconfig.json index bbb5bc2..abc01ec 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,8 @@ "allowSyntheticDefaultImports": true, "forceConsistentCasingInFileNames": true, "isolatedModules": true, - "module": "esnext", + "outDir": "dist", + "module": "commonjs", "target": "esnext" }, "exclude": ["node_modules", "dist"], diff --git a/tsup.config.js b/tsup.config.js index 812c2a6..ed9811b 100644 --- a/tsup.config.js +++ b/tsup.config.js @@ -1,4 +1,5 @@ import { defineConfig } from 'tsup'; + const shared = { entry: ['src/index.ts'], external: ['discord.js', 'iti'], @@ -12,6 +13,16 @@ const shared = { }, }; export default defineConfig([ + { + ...shared, + format: ['esm', 'cjs'], + target: 'node18', + tsconfig: './tsconfig.json', + outDir: './dist', + minify: false, + dts: true, + entry: ['src/_internal.ts'], + }, { format: ['esm', 'cjs'], target: 'node18',