mirror of
https://github.com/sern-handler/handler
synced 2026-06-23 16:22:15 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c73cf96cb2 | ||
|
|
7458befe8a | ||
|
|
efe49391e8 | ||
|
|
3140f80c10 | ||
|
|
504cdee7b2 | ||
|
|
c7661f272c | ||
|
|
daac37c288 | ||
|
|
a579e272d0 |
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,5 +1,19 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [3.3.0](https://github.com/sern-handler/handler/compare/v3.2.1...v3.3.0) (2023-12-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* presence ([#345](https://github.com/sern-handler/handler/issues/345)) ([7458bef](https://github.com/sern-handler/handler/commit/7458befe8a5900480cd71900df02a8364837dc00))
|
||||||
|
|
||||||
|
## [3.2.1](https://github.com/sern-handler/handler/compare/v3.2.0...v3.2.1) (2023-12-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* logger swap failing ([daac37c](https://github.com/sern-handler/handler/commit/daac37c28858c42b21042bdcb8141239db634e7d))
|
||||||
|
|
||||||
## [3.2.0](https://github.com/sern-handler/handler/compare/v3.1.1...v3.2.0) (2023-12-15)
|
## [3.2.0](https://github.com/sern-handler/handler/compare/v3.1.1...v3.2.0) (2023-12-15)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
41
README.md
41
README.md
@@ -19,28 +19,16 @@
|
|||||||
- Lightweight. Does a lot while being small.
|
- Lightweight. Does a lot while being small.
|
||||||
- Latest features. Support for discord.js v14 and all of its interactions.
|
- Latest features. Support for discord.js v14 and all of its interactions.
|
||||||
- Start quickly. Plug and play or customize to your liking.
|
- Start quickly. Plug and play or customize to your liking.
|
||||||
- Switch and customize how errors are handled, logging, and more.
|
|
||||||
- works with [bun](https://bun.sh/) and [node](https://nodejs.org/en) out the box!
|
- works with [bun](https://bun.sh/) and [node](https://nodejs.org/en) out the box!
|
||||||
- Use it with TypeScript or JavaScript. CommonJS and ESM supported.
|
- Use it with TypeScript or JavaScript. CommonJS and ESM supported.
|
||||||
- Active and growing community, always here to help. [Join us](https://sern.dev/discord)
|
- Active and growing community, always here to help. [Join us](https://sern.dev/discord)
|
||||||
- Unleash its full potential with a powerful CLI and awesome plugins.
|
- Unleash its full potential with a powerful CLI and awesome plugins.
|
||||||
|
|
||||||
## 📜 Installation
|
## 📜 Installation
|
||||||
|
[Start here!!](https://sern.dev/docs/guide/walkthrough/new-project)
|
||||||
```sh
|
|
||||||
npm install @sern/handler
|
|
||||||
```
|
|
||||||
|
|
||||||
```sh
|
|
||||||
yarn add @sern/handler
|
|
||||||
```
|
|
||||||
|
|
||||||
```sh
|
|
||||||
pnpm add @sern/handler
|
|
||||||
```
|
|
||||||
|
|
||||||
## 👶 Basic Usage
|
## 👶 Basic Usage
|
||||||
<details open><summary>ping.ts</summary>
|
<details><summary>ping.ts</summary>
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
export default commandModule({
|
export default commandModule({
|
||||||
@@ -54,7 +42,7 @@ export default commandModule({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
</details>
|
</details>
|
||||||
<details open><summary>modal.ts</summary>
|
<details><summary>modal.ts</summary>
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
export default commandModule({
|
export default commandModule({
|
||||||
@@ -74,30 +62,7 @@ export default commandModule({
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
</details>
|
</details>
|
||||||
<details open><summary>index.ts</summary>
|
|
||||||
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { Client, GatewayIntentBits } from 'discord.js';
|
|
||||||
import { Sern, single } from '@sern/handler';
|
|
||||||
|
|
||||||
//client has been declared previously
|
|
||||||
//Version 3
|
|
||||||
await makeDependencies({
|
|
||||||
build: root => root
|
|
||||||
.add({ '@sern/client': single(() => client) })
|
|
||||||
});
|
|
||||||
|
|
||||||
//View docs for all options
|
|
||||||
Sern.init({
|
|
||||||
defaultPrefix: '!', // removing defaultPrefix will shut down text commands
|
|
||||||
commands: 'src/commands',
|
|
||||||
// events: 'src/events' (optional),
|
|
||||||
});
|
|
||||||
|
|
||||||
client.login("YOUR_BOT_TOKEN_HERE");
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
## 🤖 Bots Using sern
|
## 🤖 Bots Using sern
|
||||||
- [Community Bot](https://github.com/sern-handler/sern-community), the community bot for our [discord server](https://sern.dev/discord).
|
- [Community Bot](https://github.com/sern-handler/sern-community), the community bot for our [discord server](https://sern.dev/discord).
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@sern/handler",
|
"name": "@sern/handler",
|
||||||
"packageManager": "yarn@3.5.0",
|
"packageManager": "yarn@3.5.0",
|
||||||
"version": "3.2.0",
|
"version": "3.3.0",
|
||||||
"description": "A complete, customizable, typesafe, & reactive framework for discord bots.",
|
"description": "A complete, customizable, typesafe, & reactive framework for discord bots.",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"module": "./dist/index.mjs",
|
"module": "./dist/index.mjs",
|
||||||
@@ -37,6 +37,7 @@
|
|||||||
"author": "SernDevs",
|
"author": "SernDevs",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"callsites": "^3.1.0",
|
||||||
"iti": "^0.6.0",
|
"iti": "^0.6.0",
|
||||||
"rxjs": "^7.8.0",
|
"rxjs": "^7.8.0",
|
||||||
"ts-results-es": "^4.0.0"
|
"ts-results-es": "^4.0.0"
|
||||||
|
|||||||
@@ -88,8 +88,8 @@ export async function makeDependencies<const T extends Dependencies>
|
|||||||
if(typeof conf === 'function') {
|
if(typeof conf === 'function') {
|
||||||
const excluded: string[] = [];
|
const excluded: string[] = [];
|
||||||
conf(dependencyBuilder(containerSubject, excluded));
|
conf(dependencyBuilder(containerSubject, excluded));
|
||||||
if(!excluded.includes('@sern/logger')) {
|
if(!excluded.includes('@sern/logger')
|
||||||
assert.ok(!containerSubject.getTokens()['@sern/logger'])
|
&& !containerSubject.getTokens()['@sern/logger']) {
|
||||||
insertLogger(containerSubject);
|
insertLogger(containerSubject);
|
||||||
}
|
}
|
||||||
containerSubject.ready();
|
containerSubject.ready();
|
||||||
|
|||||||
@@ -6,9 +6,19 @@ import assert from 'assert';
|
|||||||
import { createRequire } from 'node:module';
|
import { createRequire } from 'node:module';
|
||||||
import type { ImportPayload, Wrapper } from '../types/core';
|
import type { ImportPayload, Wrapper } from '../types/core';
|
||||||
import type { Module } from '../types/core-modules';
|
import type { Module } from '../types/core-modules';
|
||||||
|
import { existsSync } from 'fs';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
|
export const shouldHandle = (path: string, fpath: string) => {
|
||||||
|
const newPath = new URL(fpath+extname(path), path).href;
|
||||||
|
return {
|
||||||
|
exists: existsSync(fileURLToPath(newPath)),
|
||||||
|
path: newPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export type ModuleResult<T> = Promise<ImportPayload<T>>;
|
export type ModuleResult<T> = Promise<ImportPayload<T>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Import any module based on the absolute path.
|
* Import any module based on the absolute path.
|
||||||
* This can accept four types of exported modules
|
* This can accept four types of exported modules
|
||||||
@@ -66,6 +76,7 @@ const isSkippable = (filename: string) => {
|
|||||||
const validExtensions = ['.js', '.cjs', '.mts', '.mjs', '.cts', '.ts', ''];
|
const validExtensions = ['.js', '.cjs', '.mts', '.mjs', '.cts', '.ts', ''];
|
||||||
return filename[0] === '!' || !validExtensions.includes(extname(filename));
|
return filename[0] === '!' || !validExtensions.includes(extname(filename));
|
||||||
};
|
};
|
||||||
|
|
||||||
async function deriveFileInfo(dir: string, file: string) {
|
async function deriveFileInfo(dir: string, file: string) {
|
||||||
const fullPath = join(dir, file);
|
const fullPath = join(dir, file);
|
||||||
return {
|
return {
|
||||||
@@ -74,6 +85,7 @@ async function deriveFileInfo(dir: string, file: string) {
|
|||||||
base: basename(file),
|
base: basename(file),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function* readPaths(dir: string): AsyncGenerator<string> {
|
async function* readPaths(dir: string): AsyncGenerator<string> {
|
||||||
try {
|
try {
|
||||||
const files = await readdir(dir);
|
const files = await readdir(dir);
|
||||||
@@ -118,6 +130,8 @@ export function loadConfig(wrapper: Wrapper | 'file'): Wrapper {
|
|||||||
eventsPath = makePath('events');
|
eventsPath = makePath('events');
|
||||||
console.log('Events path is set to', eventsPath);
|
console.log('Events path is set to', eventsPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
defaultPrefix: config.defaultPrefix,
|
defaultPrefix: config.defaultPrefix,
|
||||||
commands: commandsPath,
|
commands: commandsPath,
|
||||||
|
|||||||
@@ -61,18 +61,19 @@ export function discordEvent<T extends keyof ClientEvents>(mod: {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
function prepareClassPlugins(c: Module) {
|
function prepareClassPlugins(c: Module) {
|
||||||
const [onEvent, initPlugins] = partitionPlugins(c.plugins);
|
const [onEvent, initPlugins] = partitionPlugins(c.plugins);
|
||||||
c.plugins = initPlugins as InitPlugin[];
|
c.plugins = initPlugins as InitPlugin[];
|
||||||
c.onEvent = onEvent as ControlPlugin[];
|
c.onEvent = onEvent as ControlPlugin[];
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// Class modules:
|
|
||||||
// Can be refactored.
|
|
||||||
// Both implement singleton, could I make them inherit a singleton parent class?
|
|
||||||
/**
|
/**
|
||||||
* @Experimental
|
* @deprecated
|
||||||
* Will be refactored / changed in future
|
* Will be removed in future
|
||||||
*/
|
*/
|
||||||
export abstract class CommandExecutable<const Type extends CommandType = CommandType> {
|
export abstract class CommandExecutable<const Type extends CommandType = CommandType> {
|
||||||
abstract type: Type;
|
abstract type: Type;
|
||||||
@@ -92,8 +93,8 @@ export abstract class CommandExecutable<const Type extends CommandType = Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Experimental
|
* @deprecated
|
||||||
* Will be refactored in future
|
* Will be removed in future
|
||||||
*/
|
*/
|
||||||
export abstract class EventExecutable<Type extends EventType> {
|
export abstract class EventExecutable<Type extends EventType> {
|
||||||
abstract type: Type;
|
abstract type: Type;
|
||||||
|
|||||||
70
src/core/presences.ts
Normal file
70
src/core/presences.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import type { ActivitiesOptions } from "discord.js";
|
||||||
|
import type { IntoDependencies } from "../types/ioc";
|
||||||
|
import type { Emitter } from "./contracts/emitter";
|
||||||
|
|
||||||
|
type Status = 'online' | 'idle' | 'invisible' | 'dnd'
|
||||||
|
type PresenceReduce = (previous: Result) => Result;
|
||||||
|
|
||||||
|
export interface Result {
|
||||||
|
status?: Status;
|
||||||
|
afk?: boolean;
|
||||||
|
activities?: ActivitiesOptions[];
|
||||||
|
shardId?: number[];
|
||||||
|
repeat?: number | [Emitter, string];
|
||||||
|
onRepeat?: (previous: Result) => Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Config <T extends (keyof Dependencies)[]> =
|
||||||
|
{
|
||||||
|
inject?: [...T]
|
||||||
|
execute: (...v: IntoDependencies<T>) => Result;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 function module<T extends (keyof Dependencies)[]>
|
||||||
|
(conf: Config<T>) {
|
||||||
|
return 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<Result, 'repeat' | 'onRepeat'>) {
|
||||||
|
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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
46
src/handlers/presence.ts
Normal file
46
src/handlers/presence.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { concatMap, from, interval, of, map, scan, startWith, fromEvent, take } from "rxjs"
|
||||||
|
import { Files } from "../core/_internal";
|
||||||
|
import * as Presence from "../core/presences";
|
||||||
|
import { Services } from "../core/ioc";
|
||||||
|
import assert from "node:assert";
|
||||||
|
|
||||||
|
type SetPresence = (conf: Presence.Result) => Promise<unknown>
|
||||||
|
|
||||||
|
const parseConfig = async (conf: Promise<Presence.Result>) => {
|
||||||
|
return conf.then(s => {
|
||||||
|
if('repeat' in s) {
|
||||||
|
const { onRepeat, repeat } = s;
|
||||||
|
assert(repeat !== undefined, "repeat option is undefined");
|
||||||
|
assert(onRepeat !== undefined, "onRepeat callback is undefined, but repeat exists");
|
||||||
|
const src$ = typeof repeat === 'number'
|
||||||
|
? interval(repeat)
|
||||||
|
: fromEvent(...repeat);
|
||||||
|
return src$
|
||||||
|
.pipe(scan(onRepeat, s),
|
||||||
|
startWith(s));
|
||||||
|
}
|
||||||
|
//take 1?
|
||||||
|
return of(s).pipe(take(1));
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
export const presenceHandler = (path: string, setPresence: SetPresence) => {
|
||||||
|
interface PresenceModule {
|
||||||
|
module: Presence.Config<(keyof Dependencies)[]>
|
||||||
|
}
|
||||||
|
const presence = Files
|
||||||
|
.importModule<PresenceModule>(path)
|
||||||
|
.then(({ module }) => {
|
||||||
|
//fetch services with the order preserved, passing it to the execute fn
|
||||||
|
const fetchedServices = Services(...module.inject ?? []);
|
||||||
|
return async () => module.execute(...fetchedServices);
|
||||||
|
})
|
||||||
|
const module$ = from(presence);
|
||||||
|
return module$.pipe(
|
||||||
|
//compose:.
|
||||||
|
//call the execute function, passing that result into parseConfig.
|
||||||
|
//concatMap resolves the promise, and passes it to the next concatMap.
|
||||||
|
concatMap(fn => parseConfig(fn())),
|
||||||
|
// subscribe to the observable parseConfig yields, and set the presence.
|
||||||
|
concatMap(conf => conf.pipe(map(setPresence))))
|
||||||
|
}
|
||||||
@@ -25,8 +25,7 @@ export function startReadyEvent(
|
|||||||
|
|
||||||
const once = () => pipe(
|
const once = () => pipe(
|
||||||
first(),
|
first(),
|
||||||
ignoreElements()
|
ignoreElements())
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
function register<T extends Processed<AnyModule>>(
|
function register<T extends Processed<AnyModule>>(
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ export {
|
|||||||
CommandExecutable,
|
CommandExecutable,
|
||||||
} from './core/modules';
|
} from './core/modules';
|
||||||
|
|
||||||
|
export * as Presence from './core/presences'
|
||||||
|
|
||||||
export {
|
export {
|
||||||
useContainerRaw
|
useContainerRaw
|
||||||
} from './core/_internal'
|
} from './core/_internal'
|
||||||
|
|||||||
22
src/sern.ts
22
src/sern.ts
@@ -1,4 +1,5 @@
|
|||||||
import { handleCrash } from './handlers/_internal';
|
import { handleCrash } from './handlers/_internal';
|
||||||
|
import callsites from 'callsites';
|
||||||
import { err, ok, Files } from './core/_internal';
|
import { err, ok, Files } from './core/_internal';
|
||||||
import { merge } from 'rxjs';
|
import { merge } from 'rxjs';
|
||||||
import { Services } from './core/ioc';
|
import { Services } from './core/ioc';
|
||||||
@@ -7,6 +8,8 @@ import { eventsHandler } from './handlers/user-defined-events';
|
|||||||
import { startReadyEvent } from './handlers/ready-event';
|
import { startReadyEvent } from './handlers/ready-event';
|
||||||
import { messageHandler } from './handlers/message-event';
|
import { messageHandler } from './handlers/message-event';
|
||||||
import { interactionHandler } from './handlers/interaction-event';
|
import { interactionHandler } from './handlers/interaction-event';
|
||||||
|
import { presenceHandler } from './handlers/presence';
|
||||||
|
import { Client } from 'discord.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 1.0.0
|
* @since 1.0.0
|
||||||
@@ -31,14 +34,21 @@ export function init(maybeWrapper: Wrapper | 'file') {
|
|||||||
if (wrapper.events !== undefined) {
|
if (wrapper.events !== undefined) {
|
||||||
eventsHandler(dependencies, Files.getFullPathTree(wrapper.events));
|
eventsHandler(dependencies, Files.getFullPathTree(wrapper.events));
|
||||||
}
|
}
|
||||||
|
const initCallsite = callsites()[1].getFileName();
|
||||||
|
const presencePath = Files.shouldHandle(initCallsite!, "presence");
|
||||||
//Ready event: load all modules and when finished, time should be taken and logged
|
//Ready event: load all modules and when finished, time should be taken and logged
|
||||||
startReadyEvent(dependencies, Files.getFullPathTree(wrapper.commands)).add(() => {
|
startReadyEvent(dependencies, Files.getFullPathTree(wrapper.commands))
|
||||||
const time = ((performance.now() - startTime) / 1000).toFixed(2);
|
.add(() => {
|
||||||
dependencies[0].emit('modulesLoaded');
|
const time = ((performance.now() - startTime) / 1000).toFixed(2);
|
||||||
logger?.info({
|
dependencies[0].emit('modulesLoaded');
|
||||||
message: `sern: registered all modules in ${time} s`,
|
logger?.info({ message: `sern: registered all modules in ${time} s`, });
|
||||||
|
if(presencePath.exists) {
|
||||||
|
const setPresence = async (p: any) => {
|
||||||
|
return (dependencies[4] as Client).user?.setPresence(p);
|
||||||
|
}
|
||||||
|
presenceHandler(presencePath.path, setPresence).subscribe();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
const messages$ = messageHandler(dependencies, wrapper.defaultPrefix);
|
const messages$ = messageHandler(dependencies, wrapper.defaultPrefix);
|
||||||
const interactions$ = interactionHandler(dependencies);
|
const interactions$ = interactionHandler(dependencies);
|
||||||
|
|||||||
57
test/core/presence.test.ts
Normal file
57
test/core/presence.test.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import { describe, expect, it, vi } from 'vitest';
|
||||||
|
import { Presence } from '../../src';
|
||||||
|
|
||||||
|
|
||||||
|
// Example test suite for the module function
|
||||||
|
describe('module function', () => {
|
||||||
|
it('should return a valid configuration', () => {
|
||||||
|
const config: Presence.Config<['dependency1', 'dependency2']> = Presence.module({
|
||||||
|
inject: ['dependency1', 'dependency2'],
|
||||||
|
execute: vi.fn(),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(config).toBeDefined();
|
||||||
|
expect(config.inject).toEqual(['dependency1', 'dependency2']);
|
||||||
|
expect(typeof config.execute).toBe('function');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('of function', () => {
|
||||||
|
it('should return a valid presence configuration without repeat and onRepeat', () => {
|
||||||
|
const presenceConfig = Presence.of({
|
||||||
|
status: 'online',
|
||||||
|
afk: false,
|
||||||
|
activities: [{ name: 'Test Activity' }],
|
||||||
|
shardId: [1, 2, 3],
|
||||||
|
}).once();
|
||||||
|
|
||||||
|
expect(presenceConfig).toBeDefined();
|
||||||
|
//@ts-ignore Maybe fix?
|
||||||
|
expect(presenceConfig.repeat).toBeUndefined();
|
||||||
|
//@ts-ignore Maybe fix?
|
||||||
|
expect(presenceConfig.onRepeat).toBeUndefined();
|
||||||
|
expect(presenceConfig).toMatchObject({
|
||||||
|
status: 'online',
|
||||||
|
afk: false,
|
||||||
|
activities: [{ name: 'Test Activity' }],
|
||||||
|
shardId: [1, 2, 3],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a valid presence configuration with repeat and onRepeat', () => {
|
||||||
|
const onRepeatCallback = vi.fn();
|
||||||
|
const presenceConfig = Presence.of({
|
||||||
|
status: 'idle',
|
||||||
|
activities: [{ name: 'Another Test Activity' }],
|
||||||
|
}).repeated(onRepeatCallback, 5000);
|
||||||
|
|
||||||
|
expect(presenceConfig).toBeDefined();
|
||||||
|
expect(presenceConfig.repeat).toBe(5000);
|
||||||
|
expect(presenceConfig.onRepeat).toBe(onRepeatCallback);
|
||||||
|
expect(presenceConfig).toMatchObject({
|
||||||
|
status: 'idle',
|
||||||
|
activities: [{ name: 'Another Test Activity' }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
@@ -627,6 +627,7 @@ __metadata:
|
|||||||
"@types/node": ^18.15.11
|
"@types/node": ^18.15.11
|
||||||
"@typescript-eslint/eslint-plugin": 5.58.0
|
"@typescript-eslint/eslint-plugin": 5.58.0
|
||||||
"@typescript-eslint/parser": 5.59.1
|
"@typescript-eslint/parser": 5.59.1
|
||||||
|
callsites: ^3.1.0
|
||||||
discord.js: ^14.11.0
|
discord.js: ^14.11.0
|
||||||
esbuild: ^0.17.0
|
esbuild: ^0.17.0
|
||||||
eslint: 8.39.0
|
eslint: 8.39.0
|
||||||
@@ -1186,7 +1187,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"callsites@npm:^3.0.0":
|
"callsites@npm:^3.0.0, callsites@npm:^3.1.0":
|
||||||
version: 3.1.0
|
version: 3.1.0
|
||||||
resolution: "callsites@npm:3.1.0"
|
resolution: "callsites@npm:3.1.0"
|
||||||
checksum: 072d17b6abb459c2ba96598918b55868af677154bec7e73d222ef95a8fdb9bbf7dae96a8421085cdad8cd190d86653b5b6dc55a4484f2e5b2e27d5e0c3fc15b3
|
checksum: 072d17b6abb459c2ba96598918b55868af677154bec7e73d222ef95a8fdb9bbf7dae96a8421085cdad8cd190d86653b5b6dc55a4484f2e5b2e27d5e0c3fc15b3
|
||||||
|
|||||||
Reference in New Issue
Block a user