mirror of
https://github.com/tiramisulabs/seyfert.git
synced 2025-07-16 20:06:09 +00:00
Compare commits
63 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9ae4290ef2 | ||
20cca8a71b | |||
ab080fb89d | |||
b597d9fc69 | |||
83e8e2165b | |||
dd9859a102 | |||
6d5b162a2d | |||
a15eb2035f | |||
c4d1c1ce90 | |||
eadf63450b | |||
0720d0c170 | |||
798f648955 | |||
6e037ae964 | |||
0608c7ad85 | |||
db38f49ca9 | |||
325a39f1bf | |||
e810b6eb52 | |||
![]() |
b84d462ce2 | ||
61413181bb | |||
30a066e68d | |||
95619a8a89 | |||
84806f3c54 | |||
422cfb2a80 | |||
![]() |
3f6c6dc4d4 | ||
d6a405469d | |||
1903257e46 | |||
0b00e2d19b | |||
970ed980cf | |||
935cce99f6 | |||
5de23ffe58 | |||
e4f715515c | |||
7998577b07 | |||
05cdc20d7f | |||
e095edd20f | |||
d9aef4335d | |||
3350570334 | |||
c20f2fd0a3 | |||
0d8ad177b7 | |||
089cfab6da | |||
fb9c59a51b | |||
92ab65be7b | |||
23c9c2a710 | |||
b4324f9487 | |||
f74b75fcef | |||
9cbde76ad0 | |||
66b5ca34a9 | |||
4574ca018f | |||
34ca3e293e | |||
a358bb0a04 | |||
6cf75e9ad2 | |||
60108b4c42 | |||
e8c686a1df | |||
c5ae765263 | |||
e8e89e60a8 | |||
5a90b7edb4 | |||
f4bcaa58ec | |||
e3b6f57741 | |||
7baeedd67c | |||
![]() |
ecc007b438 | ||
53231465c0 | |||
faa222275f | |||
589a59c5f6 | |||
f03eb57ed5 |
11
.github/workflows/dev.yml
vendored
11
.github/workflows/dev.yml
vendored
@ -12,8 +12,10 @@ jobs:
|
||||
permissions:
|
||||
id-token: write
|
||||
if: github.repository == 'tiramisulabs/seyfert'
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
steps:
|
||||
- name: check out code
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Node
|
||||
@ -29,12 +31,13 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Verify npm token
|
||||
run: npm whoami
|
||||
|
||||
- name: Publish dev tag
|
||||
id: publish
|
||||
run: |
|
||||
new_version=$(npm version prerelease --preid dev-${{github.run_id}} --no-git-tag-version)
|
||||
echo "New version: $new_version"
|
||||
npm config set //registry.npmjs.org/:_authToken ${NODE_AUTH_TOKEN}
|
||||
npm publish --provenance --tag=dev
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
npm publish --provenance --tag=dev
|
80
.github/workflows/releases.yml
vendored
80
.github/workflows/releases.yml
vendored
@ -1,80 +0,0 @@
|
||||
name: Create Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- build
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: check out code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build project
|
||||
run: pnpm run build
|
||||
|
||||
- name: Get version from package.json
|
||||
id: get_version
|
||||
run: echo "::set-output name=version::$(node -p "require('./package.json').version")"
|
||||
|
||||
- name: Set repository variable
|
||||
run: echo "REPO=${{ github.repository }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Get and format commits
|
||||
run: |
|
||||
last_tag=$(git tag --sort=-v:refname | head -n 1)
|
||||
if [ -z "$last_tag" ]; then
|
||||
git log --pretty=format:"%h - %s" > commits.txt
|
||||
else
|
||||
git log ${last_tag}..HEAD --pretty=format:"%h - %s" > commits.txt
|
||||
fi
|
||||
sed -e "s|^\([a-f0-9]\+\) - \(.*\)|- [\1](https://github.com/$REPO/commit/\1) - \2|" commits.txt > formatted_commits.txt
|
||||
echo "Changes in this release:" > release_body.txt
|
||||
cat formatted_commits.txt >> release_body.txt
|
||||
|
||||
- name: Create tag
|
||||
run: |
|
||||
git tag v${{ steps.get_version.outputs.version }}
|
||||
git push origin v${{ steps.get_version.outputs.version }}
|
||||
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: v${{ steps.get_version.outputs.version }}
|
||||
release_name: Release v${{ steps.get_version.outputs.version }}
|
||||
body_path: release_body.txt
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
- name: Zip dist folder
|
||||
run: zip -r dist.zip src
|
||||
|
||||
- name: Upload Release Asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./dist.zip
|
||||
asset_name: dist.zip
|
||||
asset_content_type: application/zip
|
@ -1 +1 @@
|
||||
npx lint-staged
|
||||
npx biome check --write
|
||||
|
32
biome.json
32
biome.json
@ -1,5 +1,5 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
|
||||
"$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
|
||||
"vcs": {
|
||||
"enabled": true,
|
||||
"clientKind": "git",
|
||||
@ -8,7 +8,16 @@
|
||||
},
|
||||
"files": {
|
||||
"ignoreUnknown": true,
|
||||
"ignore": ["node_modules/", "build", "lib", "__test__", "package.json", "tsconfig.json", ".vscode"]
|
||||
"includes": [
|
||||
"**/src/**",
|
||||
"!/node_modules/",
|
||||
"!/build",
|
||||
"!/lib",
|
||||
"!/__test__",
|
||||
"!/package.json",
|
||||
"!/tsconfig.json",
|
||||
"!/.vscode"
|
||||
]
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
@ -18,14 +27,17 @@
|
||||
"lineEnding": "crlf",
|
||||
"formatWithErrors": true
|
||||
},
|
||||
"organizeImports": {
|
||||
"enabled": true
|
||||
"assist": {
|
||||
"actions": {
|
||||
"source": {
|
||||
"organizeImports": "on"
|
||||
}
|
||||
}
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": false,
|
||||
"all": true,
|
||||
"security": {
|
||||
"noGlobalEval": "off"
|
||||
},
|
||||
@ -41,9 +53,7 @@
|
||||
},
|
||||
"correctness": {
|
||||
"noNodejsModules": "off",
|
||||
"useImportExtensions": "off",
|
||||
"noUnusedFunctionParameters": "off",
|
||||
"noUnusedVariables": "off"
|
||||
"useImportExtensions": "off"
|
||||
},
|
||||
"style": {
|
||||
"noDefaultExport": "off",
|
||||
@ -56,8 +66,7 @@
|
||||
"noParameterAssign": "off",
|
||||
"useFilenamingConvention": "off",
|
||||
"useEnumInitializers": "off",
|
||||
"useExplicitLengthCheck": "off",
|
||||
"noNamespaceImport": "off"
|
||||
"useExplicitLengthCheck": "off"
|
||||
},
|
||||
"complexity": {
|
||||
"noForEach": "off",
|
||||
@ -69,7 +78,8 @@
|
||||
"noBarrelFile": "off",
|
||||
"noDelete": "off",
|
||||
"noReExportAll": "off",
|
||||
"useTopLevelRegex": "off"
|
||||
"useTopLevelRegex": "off",
|
||||
"noNamespaceImport": "off"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
22
package.json
22
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "seyfert",
|
||||
"version": "3.0.0",
|
||||
"version": "3.2.4",
|
||||
"description": "The most advanced framework for discord bots",
|
||||
"main": "./lib/index.js",
|
||||
"module": "./lib/index.js",
|
||||
@ -21,15 +21,14 @@
|
||||
"author": "MARCROCK22",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "1.9.4",
|
||||
"@changesets/cli": "^2.28.1",
|
||||
"@commitlint/cli": "^19.8.0",
|
||||
"@commitlint/config-conventional": "^19.8.0",
|
||||
"@types/node": "^22.14.0",
|
||||
"@biomejs/biome": "2.0.0",
|
||||
"@changesets/cli": "^2.29.4",
|
||||
"@commitlint/cli": "^19.8.1",
|
||||
"@commitlint/config-conventional": "^19.8.1",
|
||||
"@types/node": "^24.0.3",
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^15.5.0",
|
||||
"typescript": "^5.8.2",
|
||||
"vitest": "^3.1.1"
|
||||
"typescript": "^5.8.3",
|
||||
"vitest": "^3.2.4"
|
||||
},
|
||||
"homepage": "https://seyfert.dev",
|
||||
"repository": {
|
||||
@ -65,11 +64,6 @@
|
||||
"url": "https://github.com/Drylozu"
|
||||
}
|
||||
],
|
||||
"lint-staged": {
|
||||
"*.ts": [
|
||||
"biome check --write"
|
||||
]
|
||||
},
|
||||
"pnpm": {
|
||||
"onlyBuiltDependencies": [
|
||||
"@biomejs/biome",
|
||||
|
1311
pnpm-lock.yaml
generated
1311
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -71,7 +71,7 @@ export interface ApplicationRoutes {
|
||||
patch(
|
||||
args: RestArguments<RESTPatchAPIApplicationGuildCommandJSONBody>,
|
||||
): Promise<RESTPatchAPIApplicationGuildCommandResult>;
|
||||
delete(args?: RestArgumentsNoBody): Promise<never>;
|
||||
delete(args?: RestArgumentsNoBody): Promise<undefined>;
|
||||
permissions: {
|
||||
get(args?: RestArgumentsNoBody): Promise<RESTGetAPIGuildApplicationCommandsPermissionsResult>;
|
||||
put(
|
||||
@ -92,7 +92,7 @@ export interface ApplicationRoutes {
|
||||
patch(
|
||||
args: RestArguments<RESTPatchAPIApplicationCommandJSONBody>,
|
||||
): Promise<RESTPatchAPIApplicationCommandResult>;
|
||||
delete(args?: RestArgumentsNoBody): Promise<never>;
|
||||
delete(args?: RestArgumentsNoBody): Promise<undefined>;
|
||||
};
|
||||
};
|
||||
'role-connections': {
|
||||
@ -122,10 +122,10 @@ export interface ApplicationRoutes {
|
||||
(
|
||||
id: string,
|
||||
): {
|
||||
get(args?: RestArgumentsNoBody<never>): Promise<RESTGetAPIEntitlementResult>;
|
||||
delete(args?: RestArgumentsNoBody): Promise<never>;
|
||||
get(args?: RestArgumentsNoBody): Promise<RESTGetAPIEntitlementResult>;
|
||||
delete(args?: RestArgumentsNoBody): Promise<undefined>;
|
||||
consume: {
|
||||
post(args?: RestArgumentsNoBody): Promise<never>;
|
||||
post(args?: RestArgumentsNoBody): Promise<undefined>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -190,7 +190,7 @@ export interface ChannelRoutes {
|
||||
post(args: RestArguments<RESTPostAPIChannelWebhookJSONBody>): Promise<RESTPostAPIChannelWebhookResult>;
|
||||
};
|
||||
'voice-status': {
|
||||
put(args: RestArguments<{ status: string | null }>): Promise<never>;
|
||||
put(args: RestArguments<{ status: string | null }>): Promise<undefined>;
|
||||
};
|
||||
polls(messageId: string): {
|
||||
answers(id: ValidAnswerId): {
|
||||
@ -201,7 +201,7 @@ export interface ChannelRoutes {
|
||||
};
|
||||
};
|
||||
'send-soundboard-sound': {
|
||||
post(args: RestArguments<RESTPostAPISendSoundboardSound>): Promise<never>;
|
||||
post(args: RestArguments<RESTPostAPISendSoundboardSound>): Promise<undefined>;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -39,10 +39,10 @@ import type {
|
||||
RESTGetAPIGuildRolesResult,
|
||||
RESTGetAPIGuildScheduledEventQuery,
|
||||
RESTGetAPIGuildScheduledEventResult,
|
||||
RESTGetAPIGuildScheduledEventUsersQuery,
|
||||
RESTGetAPIGuildScheduledEventUsersResult,
|
||||
RESTGetAPIGuildScheduledEventsQuery,
|
||||
RESTGetAPIGuildScheduledEventsResult,
|
||||
RESTGetAPIGuildScheduledEventUsersQuery,
|
||||
RESTGetAPIGuildScheduledEventUsersResult,
|
||||
RESTGetAPIGuildSoundboardSoundsResult,
|
||||
RESTGetAPIGuildStickerResult,
|
||||
RESTGetAPIGuildStickersResult,
|
||||
@ -107,12 +107,12 @@ import type {
|
||||
RESTPostAPIGuildSoundboardSoundResult,
|
||||
RESTPostAPIGuildStickerFormDataBody,
|
||||
RESTPostAPIGuildStickerResult,
|
||||
RESTPostAPIGuildTemplatesJSONBody,
|
||||
RESTPostAPIGuildTemplatesResult,
|
||||
RESTPostAPIGuildsJSONBody,
|
||||
RESTPostAPIGuildsMFAJSONBody,
|
||||
RESTPostAPIGuildsMFAResult,
|
||||
RESTPostAPIGuildsResult,
|
||||
RESTPostAPIGuildTemplatesJSONBody,
|
||||
RESTPostAPIGuildTemplatesResult,
|
||||
RESTPostAPITemplateCreateGuildJSONBody,
|
||||
RESTPostAPITemplateCreateGuildResult,
|
||||
RESTPutAPIGuildBanJSONBody,
|
||||
@ -361,7 +361,7 @@ export interface GuildRoutes {
|
||||
patch(
|
||||
args?: RestArguments<RESTPatchAPIGuildSoundboardSound>,
|
||||
): Promise<RESTPatchAPIGuildSoundboardSoundResult>;
|
||||
delete(args?: RestArgumentsNoBody): Promise<never>;
|
||||
delete(args?: RestArgumentsNoBody): Promise<undefined>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -9,6 +9,7 @@ import type {
|
||||
RESTPatchAPIWebhookResult,
|
||||
RESTPatchAPIWebhookWithTokenJSONBody,
|
||||
RESTPatchAPIWebhookWithTokenMessageJSONBody,
|
||||
RESTPatchAPIWebhookWithTokenMessageQuery,
|
||||
RESTPatchAPIWebhookWithTokenMessageResult,
|
||||
RESTPatchAPIWebhookWithTokenResult,
|
||||
RESTPostAPIWebhookWithTokenGitHubQuery,
|
||||
@ -33,7 +34,9 @@ export interface WebhookRoutes {
|
||||
token: string,
|
||||
): {
|
||||
get(args?: RestArgumentsNoBody): Promise<RESTGetAPIWebhookWithTokenResult>;
|
||||
patch(args: RestArguments<RESTPatchAPIWebhookWithTokenJSONBody>): Promise<RESTPatchAPIWebhookWithTokenResult>;
|
||||
patch(
|
||||
args: RestArguments<RESTPatchAPIWebhookWithTokenJSONBody, RESTPatchAPIWebhookWithTokenMessageQuery>,
|
||||
): Promise<RESTPatchAPIWebhookWithTokenResult>;
|
||||
delete(args?: RestArgumentsNoBody): Promise<RESTDeleteAPIWebhookWithTokenResult>;
|
||||
post(
|
||||
args: RestArguments<RESTPostAPIWebhookWithTokenJSONBody, RESTPostAPIWebhookWithTokenQuery>,
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { type UUID, randomUUID } from 'node:crypto';
|
||||
import { type Awaitable, BASE_HOST, Logger, delay, lazyLoadPackage, snowflakeToTimestamp } from '../common';
|
||||
import { randomUUID, type UUID } from 'node:crypto';
|
||||
import { type Awaitable, BASE_HOST, delay, Logger, lazyLoadPackage, snowflakeToTimestamp } from '../common';
|
||||
import { toArrayBuffer, toBuffer } from '../common/it/utils';
|
||||
import type { WorkerData } from '../websocket';
|
||||
import type { WorkerSendApiRequest } from '../websocket/discord/worker';
|
||||
import { Bucket } from './bucket';
|
||||
import { CDNRouter, Router } from './Router';
|
||||
import type { APIRoutes } from './Routes';
|
||||
import { Bucket } from './bucket';
|
||||
import {
|
||||
type ApiHandlerInternalOptions,
|
||||
type ApiHandlerOptions,
|
||||
@ -98,13 +98,13 @@ export class ApiHandler {
|
||||
}
|
||||
}
|
||||
|
||||
#randomUUID(): UUID {
|
||||
randomUUID(): UUID {
|
||||
const uuid = randomUUID();
|
||||
if (this.workerPromises!.has(uuid)) return this.#randomUUID();
|
||||
if (this.workerPromises!.has(uuid)) return this.randomUUID();
|
||||
return uuid;
|
||||
}
|
||||
|
||||
private sendMessage(_body: WorkerSendApiRequest) {
|
||||
protected sendMessage(_body: WorkerSendApiRequest) {
|
||||
throw new Error('Function not implemented');
|
||||
}
|
||||
|
||||
@ -121,7 +121,7 @@ export class ApiHandler {
|
||||
{ auth = true, ...request }: ApiRequestOptions = {},
|
||||
): Promise<T> {
|
||||
if (this.options.workerProxy) {
|
||||
const nonce = this.#randomUUID();
|
||||
const nonce = this.randomUUID();
|
||||
return this.postMessage<T>({
|
||||
method,
|
||||
url,
|
||||
@ -291,17 +291,19 @@ export class ApiHandler {
|
||||
await this.onRatelimit?.(response, request);
|
||||
|
||||
const content = `${JSON.stringify(request)} `;
|
||||
let retryAfter =
|
||||
let retryAfter: number | undefined;
|
||||
|
||||
const data = JSON.parse(result);
|
||||
if (data.retry_after) retryAfter = Math.ceil(data.retry_after * 1000);
|
||||
|
||||
retryAfter ??=
|
||||
Number(response.headers.get('x-ratelimit-reset-after') || response.headers.get('retry-after')) * 1000;
|
||||
|
||||
if (Number.isNaN(retryAfter)) {
|
||||
try {
|
||||
retryAfter = JSON.parse(result).retry_after * 1000;
|
||||
} catch (err) {
|
||||
this.debugger?.warn(`Unexpected error: ${err}`);
|
||||
reject(err);
|
||||
return false;
|
||||
}
|
||||
this.debugger?.warn(`${route} Could not extract retry_after from 429 response. ${result}`);
|
||||
next();
|
||||
reject(new Error('Could not extract retry_after from 429 response.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
this.debugger?.info(
|
||||
@ -384,11 +386,7 @@ export class ApiHandler {
|
||||
}
|
||||
}
|
||||
|
||||
parseRequest(options: {
|
||||
url: string;
|
||||
headers: RequestHeaders;
|
||||
request: ApiRequestOptions;
|
||||
}) {
|
||||
parseRequest(options: { url: string; headers: RequestHeaders; request: ApiRequestOptions }) {
|
||||
let finalUrl = options.url;
|
||||
let data: string | FormData | undefined;
|
||||
if (options.request.auth) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
export * from './api';
|
||||
export * from './Router';
|
||||
export * from './Routes';
|
||||
export * from './api';
|
||||
export * from './shared';
|
||||
|
@ -7,13 +7,13 @@ import {
|
||||
} from '../types';
|
||||
import { BaseComponentBuilder } from './Base';
|
||||
import { fromComponent } from './index';
|
||||
import type { BuilderComponents, FixedComponents } from './types';
|
||||
import type { ActionBuilderComponents, FixedComponents } from './types';
|
||||
|
||||
/**
|
||||
* Represents an Action Row component in a message.
|
||||
* @template T - The type of components in the Action Row.
|
||||
*/
|
||||
export class ActionRow<T extends BuilderComponents> extends BaseComponentBuilder<
|
||||
export class ActionRow<T extends ActionBuilderComponents = ActionBuilderComponents> extends BaseComponentBuilder<
|
||||
APIActionRowComponent<APIActionRowComponentTypes>
|
||||
> {
|
||||
/**
|
||||
@ -50,8 +50,8 @@ export class ActionRow<T extends BuilderComponents> extends BaseComponentBuilder
|
||||
* @example
|
||||
* actionRow.setComponents([buttonComponent1, buttonComponent2]);
|
||||
*/
|
||||
setComponents(component: FixedComponents<T>[]): this {
|
||||
this.components = [...component];
|
||||
setComponents(...component: RestOrArray<FixedComponents<T>>): this {
|
||||
this.components = component.flat() as FixedComponents<T>[];
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -1,17 +1,14 @@
|
||||
import { type EmojiResolvable, resolvePartialEmoji } from '../common';
|
||||
import { type APIButtonComponent, type APIMessageComponentEmoji, type ButtonStyle, ComponentType } from '../types';
|
||||
import { BaseComponentBuilder } from './Base';
|
||||
|
||||
/**
|
||||
* Represents a button component.
|
||||
* @template Type - The type of the button component.
|
||||
*/
|
||||
export class Button {
|
||||
/**
|
||||
* Creates a new Button instance.
|
||||
* @param data - The initial data for the button.
|
||||
*/
|
||||
constructor(public data: Partial<APIButtonComponent> = {}) {
|
||||
this.data.type = ComponentType.Button;
|
||||
export class Button extends BaseComponentBuilder<APIButtonComponent> {
|
||||
constructor(data: Partial<APIButtonComponent> = {}) {
|
||||
super({ type: ComponentType.Button, ...data });
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,12 +73,4 @@ export class Button {
|
||||
(this.data as Extract<APIButtonComponent, { sku_id?: string }>).sku_id = skuId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the Button instance to its JSON representation.
|
||||
* @returns The JSON representation of the Button instance.
|
||||
*/
|
||||
toJSON() {
|
||||
return { ...this.data } as Partial<APIButtonComponent>;
|
||||
}
|
||||
}
|
||||
|
100
src/builders/Container.ts
Normal file
100
src/builders/Container.ts
Normal file
@ -0,0 +1,100 @@
|
||||
import { type ColorResolvable, type RestOrArray, resolveColor } from '../common';
|
||||
import { type APIContainerComponent, ComponentType } from '../types';
|
||||
import { type ActionRow, fromComponent } from '.';
|
||||
import { BaseComponentBuilder } from './Base';
|
||||
import type { File } from './File';
|
||||
import type { MediaGallery } from './MediaGallery';
|
||||
import type { Section } from './Section';
|
||||
import type { Separator } from './Separator';
|
||||
import type { TextDisplay } from './TextDisplay';
|
||||
|
||||
/**
|
||||
* Represents the possible component types that can be added to a Container.
|
||||
*/
|
||||
export type ContainerBuilderComponents = ActionRow | TextDisplay | Section | MediaGallery | Separator | File;
|
||||
|
||||
/**
|
||||
* Represents a container component builder.
|
||||
* Containers group other components together.
|
||||
* @example
|
||||
* ```ts
|
||||
* const container = new Container()
|
||||
* .addComponents(
|
||||
* new TextDisplay('This is text inside a container!'),
|
||||
* new ActionRow().addComponents(new Button().setLabel('Click me!'))
|
||||
* )
|
||||
* .setColor('Blue');
|
||||
* ```
|
||||
*/
|
||||
export class Container extends BaseComponentBuilder<APIContainerComponent> {
|
||||
/**
|
||||
* The components held within this container.
|
||||
*/
|
||||
components: ContainerBuilderComponents[];
|
||||
|
||||
/**
|
||||
* Constructs a new Container.
|
||||
* @param data Optional initial data for the container.
|
||||
*/
|
||||
constructor({ components, ...data }: Partial<APIContainerComponent> = {}) {
|
||||
super({ ...data, type: ComponentType.Container });
|
||||
this.components = (components?.map(fromComponent) ?? []) as ContainerBuilderComponents[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds components to the container.
|
||||
* @param components The components to add. Can be a single component, an array of components, or multiple components as arguments.
|
||||
* @returns The updated Container instance.
|
||||
*/
|
||||
addComponents(...components: RestOrArray<ContainerBuilderComponents>) {
|
||||
this.components = this.components.concat(components.flat());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the components for the container, replacing any existing components.
|
||||
* @param components The components to set. Can be a single component, an array of components, or multiple components as arguments.
|
||||
* @returns The updated Container instance.
|
||||
*/
|
||||
setComponents(...components: RestOrArray<ContainerBuilderComponents>) {
|
||||
this.components = components.flat();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the container's content should be visually marked as a spoiler.
|
||||
* @param spoiler Whether the content is a spoiler (defaults to true).
|
||||
* @returns The updated Container instance.
|
||||
*/
|
||||
setSpoiler(spoiler = true) {
|
||||
this.data.spoiler = spoiler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the accent color for the container.
|
||||
* @param color The color resolvable (e.g., hex code, color name, integer).
|
||||
* @returns The updated Container instance.
|
||||
*/
|
||||
setColor(color: ColorResolvable) {
|
||||
this.data.accent_color = resolveColor(color);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ID for the container.
|
||||
* @param id The ID to set.
|
||||
* @returns The updated Container instance.
|
||||
*/
|
||||
setId(id: number) {
|
||||
this.data.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
...this.data,
|
||||
components: this.components.map(c => c.toJSON()),
|
||||
} as APIContainerComponent;
|
||||
}
|
||||
}
|
52
src/builders/File.ts
Normal file
52
src/builders/File.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import { type APIFileComponent, ComponentType } from '../types';
|
||||
import { BaseComponentBuilder } from './Base';
|
||||
|
||||
/**
|
||||
* Represents a file component builder.
|
||||
* Used to display files within containers.
|
||||
* @example
|
||||
* ```ts
|
||||
* const file = new File()
|
||||
* .setMedia('https://example.com/image.png')
|
||||
* .setSpoiler();
|
||||
* ```
|
||||
*/
|
||||
export class File extends BaseComponentBuilder<APIFileComponent> {
|
||||
/**
|
||||
* Constructs a new File component.
|
||||
* @param data Optional initial data for the file component.
|
||||
*/
|
||||
constructor(data: Partial<APIFileComponent> = {}) {
|
||||
super({ type: ComponentType.File, ...data });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ID for the file component.
|
||||
* @param id The ID to set.
|
||||
* @returns The updated File instance.
|
||||
*/
|
||||
setId(id: number) {
|
||||
this.data.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the media URL for the file.
|
||||
* @param url The URL of the file to display.
|
||||
* @returns The updated File instance.
|
||||
*/
|
||||
setMedia(url: string) {
|
||||
this.data.file = { url };
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the file should be visually marked as a spoiler.
|
||||
* @param spoiler Whether the file is a spoiler (defaults to true).
|
||||
* @returns The updated File instance.
|
||||
*/
|
||||
setSpoiler(spoiler = true) {
|
||||
this.data.spoiler = spoiler;
|
||||
return this;
|
||||
}
|
||||
}
|
112
src/builders/MediaGallery.ts
Normal file
112
src/builders/MediaGallery.ts
Normal file
@ -0,0 +1,112 @@
|
||||
import type { RestOrArray } from '../common';
|
||||
import { type APIMediaGalleryComponent, type APIMediaGalleryItems, ComponentType } from '../types';
|
||||
import { BaseComponentBuilder } from './Base';
|
||||
|
||||
/**
|
||||
* Represents a media gallery component builder.
|
||||
* Used to display a collection of media items.
|
||||
* @example
|
||||
* ```ts
|
||||
* const gallery = new MediaGallery()
|
||||
* .addItems(
|
||||
* new MediaGalleryItem().setMedia('https://example.com/image1.png').setDescription('Image 1'),
|
||||
* new MediaGalleryItem().setMedia('https://example.com/image2.jpg').setSpoiler()
|
||||
* );
|
||||
* ```
|
||||
*/
|
||||
export class MediaGallery extends BaseComponentBuilder<APIMediaGalleryComponent> {
|
||||
items: MediaGalleryItem[];
|
||||
/**
|
||||
* Constructs a new MediaGallery.
|
||||
* @param data Optional initial data for the media gallery.
|
||||
*/
|
||||
constructor({ items, ...data }: Partial<APIMediaGalleryComponent> = {}) {
|
||||
super({ type: ComponentType.MediaGallery, ...data });
|
||||
this.items = (items?.map(i => new MediaGalleryItem(i)) ?? []) as MediaGalleryItem[];
|
||||
}
|
||||
/**
|
||||
* Sets the ID for the media gallery component.
|
||||
* @param id The ID to set.
|
||||
* @returns The updated MediaGallery instance.
|
||||
*/
|
||||
setId(id: number) {
|
||||
this.data.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds items to the media gallery.
|
||||
* @param items The items to add. Can be a single item, an array of items, or multiple items as arguments.
|
||||
* @returns The updated MediaGallery instance.
|
||||
*/
|
||||
addItems(...items: RestOrArray<MediaGalleryItem>) {
|
||||
this.items = this.items.concat(items.flat());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the items for the media gallery, replacing any existing items.
|
||||
* @param items The items to set. Can be a single item, an array of items, or multiple items as arguments.
|
||||
* @returns The updated MediaGallery instance.
|
||||
*/
|
||||
setItems(...items: RestOrArray<MediaGalleryItem>) {
|
||||
this.items = items.flat();
|
||||
return this;
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
...this.data,
|
||||
items: this.items.map(i => i.toJSON()),
|
||||
} as APIMediaGalleryComponent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an item within a MediaGallery.
|
||||
*/
|
||||
export class MediaGalleryItem {
|
||||
/**
|
||||
* Constructs a new MediaGalleryItem.
|
||||
* @param data Optional initial data for the media gallery item.
|
||||
*/
|
||||
constructor(public data: Partial<APIMediaGalleryItems> = {}) {}
|
||||
|
||||
/**
|
||||
* Sets the media URL for this gallery item.
|
||||
* @param url The URL of the media.
|
||||
* @returns The updated MediaGalleryItem instance.
|
||||
*/
|
||||
setMedia(url: string) {
|
||||
this.data.media = { url };
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the description for this gallery item.
|
||||
* @param desc The description text.
|
||||
* @returns The updated MediaGalleryItem instance.
|
||||
*/
|
||||
setDescription(desc: string) {
|
||||
this.data.description = desc;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this gallery item should be visually marked as a spoiler.
|
||||
* @param spoiler Whether the item is a spoiler (defaults to true).
|
||||
* @returns The updated MediaGalleryItem instance.
|
||||
*/
|
||||
setSpoiler(spoiler = true) {
|
||||
this.data.spoiler = spoiler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this MediaGalleryItem instance to its JSON representation.
|
||||
* @returns The JSON representation of the item data.
|
||||
*/
|
||||
toJSON() {
|
||||
return { ...this.data };
|
||||
}
|
||||
}
|
56
src/builders/Section.ts
Normal file
56
src/builders/Section.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import type { RestOrArray } from '../common';
|
||||
import { type APISectionComponent, ComponentType } from '../types';
|
||||
import { type Button, fromComponent } from '.';
|
||||
import { BaseComponentBuilder } from './Base';
|
||||
import type { TextDisplay } from './TextDisplay';
|
||||
import type { Thumbnail } from './Thumbnail';
|
||||
|
||||
export class Section<
|
||||
Ac extends Button | Thumbnail = Button | Thumbnail,
|
||||
> extends BaseComponentBuilder<APISectionComponent> {
|
||||
components: TextDisplay[];
|
||||
accessory?: Ac;
|
||||
constructor({ components, accessory, ...data }: Partial<APISectionComponent> = {}) {
|
||||
super({ type: ComponentType.Section, ...data });
|
||||
this.components = (components?.map(component => fromComponent(component)) ?? []) as TextDisplay[];
|
||||
if (accessory) this.accessory = fromComponent(accessory) as Ac;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds components to this section.
|
||||
* @param components The components to add
|
||||
* @example section.addComponents(new TextDisplay().content('Hello'));
|
||||
*/
|
||||
addComponents(...components: RestOrArray<TextDisplay>) {
|
||||
this.components = this.components.concat(components.flat());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the components for this section.
|
||||
* @param components The components to set
|
||||
* @example section.setComponents(new TextDisplay().content('Hello'));
|
||||
*/
|
||||
setComponents(...components: RestOrArray<TextDisplay>) {
|
||||
this.components = components.flat();
|
||||
return this;
|
||||
}
|
||||
|
||||
setAccessory(accessory: Ac) {
|
||||
this.accessory = accessory;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this section to JSON.
|
||||
* @returns The JSON representation of this section
|
||||
*/
|
||||
toJSON() {
|
||||
if (!this.accessory) throw new Error('Cannot convert to JSON without an accessory.');
|
||||
return {
|
||||
...this.data,
|
||||
components: this.components.map(component => component.toJSON()),
|
||||
accessory: this.accessory.toJSON(),
|
||||
} as APISectionComponent;
|
||||
}
|
||||
}
|
@ -161,7 +161,7 @@ export class RoleSelectMenu extends SelectMenu<APIRoleSelectComponent> {
|
||||
}
|
||||
}
|
||||
|
||||
export type MentionableDefaultElement = { id: string; type: keyof Omit<typeof SelectMenuDefaultValueType, 'Channel'> };
|
||||
export type MentionableDefaultElement = { id: string; type: keyof typeof SelectMenuDefaultValueType };
|
||||
|
||||
/**
|
||||
* Represents a Select Menu for selecting mentionable entities.
|
||||
|
54
src/builders/Separator.ts
Normal file
54
src/builders/Separator.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import { type APISeparatorComponent, ComponentType, type Spacing } from '../types';
|
||||
import { BaseComponentBuilder } from './Base';
|
||||
|
||||
/**
|
||||
* Represents a separator component builder.
|
||||
* Used to add visual spacing or dividers between components.
|
||||
* @example
|
||||
* ```ts
|
||||
* // A simple separator for spacing
|
||||
* const spacingSeparator = new Separator().setSpacing(Spacing.Small);
|
||||
*
|
||||
* // A separator acting as a visual divider
|
||||
* const dividerSeparator = new Separator().setDivider(true);
|
||||
* ```
|
||||
*/
|
||||
export class Separator extends BaseComponentBuilder<APISeparatorComponent> {
|
||||
/**
|
||||
* Constructs a new Separator component.
|
||||
* @param data Optional initial data for the separator component.
|
||||
*/
|
||||
constructor(data: Partial<APISeparatorComponent> = {}) {
|
||||
super({ type: ComponentType.Separator, ...data });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ID for the separator component.
|
||||
* @param id The ID to set.
|
||||
* @returns The updated Separator instance.
|
||||
*/
|
||||
setId(id: number) {
|
||||
this.data.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this separator should act as a visual divider.
|
||||
* @param divider Whether to render as a divider (defaults to false).
|
||||
* @returns The updated Separator instance.
|
||||
*/
|
||||
setDivider(divider = false) {
|
||||
this.data.divider = divider;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the amount of spacing this separator provides.
|
||||
* @param spacing The desired spacing level ('None', 'Small', 'Medium', 'Large').
|
||||
* @returns The updated Separator instance.
|
||||
*/
|
||||
setSpacing(spacing: Spacing) {
|
||||
this.data.spacing = spacing;
|
||||
return this;
|
||||
}
|
||||
}
|
40
src/builders/TextDisplay.ts
Normal file
40
src/builders/TextDisplay.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { type APITextDisplayComponent, ComponentType } from '../types';
|
||||
import { BaseComponentBuilder } from './Base';
|
||||
|
||||
/**
|
||||
* Represents a text display component builder.
|
||||
* Used to display simple text content.
|
||||
* @example
|
||||
* ```ts
|
||||
* const text = new TextDisplay().content('Hello, world!');
|
||||
* ```
|
||||
*/
|
||||
export class TextDisplay extends BaseComponentBuilder<APITextDisplayComponent> {
|
||||
/**
|
||||
* Constructs a new TextDisplay component.
|
||||
* @param data Optional initial data for the text display component.
|
||||
*/
|
||||
constructor(data: Partial<APITextDisplayComponent> = {}) {
|
||||
super({ type: ComponentType.TextDisplay, ...data });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ID for the text display component.
|
||||
* @param id The ID to set.
|
||||
* @returns The updated TextDisplay instance.
|
||||
*/
|
||||
setId(id: number) {
|
||||
this.data.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the text content to display.
|
||||
* @param content The text content.
|
||||
* @returns The updated TextDisplay instance.
|
||||
*/
|
||||
setContent(content: string) {
|
||||
this.data.content = content;
|
||||
return this;
|
||||
}
|
||||
}
|
62
src/builders/Thumbnail.ts
Normal file
62
src/builders/Thumbnail.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import { type APIThumbnailComponent, ComponentType } from '../types';
|
||||
import { BaseComponentBuilder } from './Base';
|
||||
|
||||
/**
|
||||
* Represents a thumbnail component builder.
|
||||
* Used to display a small image preview, often alongside other content.
|
||||
* @example
|
||||
* ```ts
|
||||
* const thumbnail = new Thumbnail()
|
||||
* .setMedia('https://example.com/thumbnail.jpg')
|
||||
* .setDescription('A cool thumbnail');
|
||||
* ```
|
||||
*/
|
||||
export class Thumbnail extends BaseComponentBuilder<APIThumbnailComponent> {
|
||||
/**
|
||||
* Constructs a new Thumbnail component.
|
||||
* @param data Optional initial data for the thumbnail component.
|
||||
*/
|
||||
constructor(data: Partial<APIThumbnailComponent> = {}) {
|
||||
super({ type: ComponentType.Thumbnail, ...data });
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the thumbnail should be visually marked as a spoiler.
|
||||
* @param spoiler Whether the thumbnail is a spoiler (defaults to true).
|
||||
* @returns The updated Thumbnail instance.
|
||||
*/
|
||||
setSpoiler(spoiler = true) {
|
||||
this.data.spoiler = spoiler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the description for the thumbnail.
|
||||
* @param description The description text. Can be undefined to remove the description.
|
||||
* @returns The updated Thumbnail instance.
|
||||
*/
|
||||
setDescription(description: string | undefined) {
|
||||
this.data.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ID for the thumbnail component.
|
||||
* @param id The ID to set.
|
||||
* @returns The updated Thumbnail instance.
|
||||
*/
|
||||
setId(id: number) {
|
||||
this.data.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the media URL for the thumbnail.
|
||||
* @param url The URL of the image to display as a thumbnail.
|
||||
* @returns The updated Thumbnail instance.
|
||||
*/
|
||||
setMedia(url: string) {
|
||||
this.data.media = { url };
|
||||
return this;
|
||||
}
|
||||
}
|
@ -1,7 +1,11 @@
|
||||
import { type APIActionRowComponent, type APIActionRowComponentTypes, ComponentType } from '../types';
|
||||
import { type APIComponents, ComponentType } from '../types';
|
||||
import { ActionRow } from './ActionRow';
|
||||
import { Button } from './Button';
|
||||
import { Container } from './Container';
|
||||
import { File } from './File';
|
||||
import { MediaGallery } from './MediaGallery';
|
||||
import { TextInput } from './Modal';
|
||||
import { Section } from './Section';
|
||||
import {
|
||||
ChannelSelectMenu,
|
||||
MentionableSelectMenu,
|
||||
@ -9,29 +13,32 @@ import {
|
||||
StringSelectMenu,
|
||||
UserSelectMenu,
|
||||
} from './SelectMenu';
|
||||
import { Separator } from './Separator';
|
||||
import { TextDisplay } from './TextDisplay';
|
||||
import { Thumbnail } from './Thumbnail';
|
||||
import type { BuilderComponents } from './types';
|
||||
|
||||
export * from './ActionRow';
|
||||
export * from './Attachment';
|
||||
export * from './Base';
|
||||
export * from './Button';
|
||||
export * from './Container';
|
||||
export * from './Embed';
|
||||
export * from './File';
|
||||
export * from './MediaGallery';
|
||||
export * from './Modal';
|
||||
export * from './SelectMenu';
|
||||
export * from './Poll';
|
||||
export * from './Section';
|
||||
export * from './SelectMenu';
|
||||
export * from './Separator';
|
||||
export * from './TextDisplay';
|
||||
export * from './Thumbnail';
|
||||
export * from './types';
|
||||
|
||||
export function fromComponent(
|
||||
data:
|
||||
| BuilderComponents
|
||||
| APIActionRowComponentTypes
|
||||
| APIActionRowComponent<APIActionRowComponentTypes>
|
||||
| ActionRow<BuilderComponents>,
|
||||
): BuilderComponents | ActionRow<BuilderComponents> {
|
||||
export function fromComponent(data: BuilderComponents | APIComponents): BuilderComponents {
|
||||
if ('toJSON' in data) {
|
||||
return data;
|
||||
}
|
||||
|
||||
switch (data.type) {
|
||||
case ComponentType.Button:
|
||||
return new Button(data);
|
||||
@ -49,5 +56,19 @@ export function fromComponent(
|
||||
return new ChannelSelectMenu(data);
|
||||
case ComponentType.ActionRow:
|
||||
return new ActionRow(data);
|
||||
case ComponentType.Section:
|
||||
return new Section(data);
|
||||
case ComponentType.TextDisplay:
|
||||
return new TextDisplay(data);
|
||||
case ComponentType.Thumbnail:
|
||||
return new Thumbnail(data);
|
||||
case ComponentType.Container:
|
||||
return new Container(data);
|
||||
case ComponentType.MediaGallery:
|
||||
return new MediaGallery(data);
|
||||
case ComponentType.Separator:
|
||||
return new Separator(data);
|
||||
case ComponentType.File:
|
||||
return new File(data);
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,17 @@ import type {
|
||||
ModalSubmitInteraction,
|
||||
StringSelectMenuInteraction,
|
||||
} from '../structures/Interaction';
|
||||
import type { ActionRow } from './ActionRow';
|
||||
import type { Button } from './Button';
|
||||
import type { Container } from './Container';
|
||||
import type { File } from './File';
|
||||
import type { MediaGallery } from './MediaGallery';
|
||||
import type { TextInput } from './Modal';
|
||||
import type { Section } from './Section';
|
||||
import type { BuilderSelectMenus } from './SelectMenu';
|
||||
import type { Separator } from './Separator';
|
||||
import type { TextDisplay } from './TextDisplay';
|
||||
import type { Thumbnail } from './Thumbnail';
|
||||
|
||||
export type ComponentCallback<
|
||||
T extends ComponentInteraction | StringSelectMenuInteraction = ComponentInteraction | StringSelectMenuInteraction,
|
||||
@ -25,7 +33,22 @@ export type ButtonID = Omit<Button, 'setURL'>;
|
||||
|
||||
export type MessageBuilderComponents = FixedComponents<Button> | BuilderSelectMenus;
|
||||
export type ModalBuilderComponents = TextInput;
|
||||
export type BuilderComponents = MessageBuilderComponents | TextInput;
|
||||
export type ActionBuilderComponents = MessageBuilderComponents | TextInput;
|
||||
|
||||
export type BuilderComponents =
|
||||
| ActionRow
|
||||
| ActionBuilderComponents
|
||||
| Section<Button | Thumbnail>
|
||||
| Thumbnail
|
||||
| TextDisplay
|
||||
| Container
|
||||
| Separator
|
||||
| MediaGallery
|
||||
| File
|
||||
| TextInput;
|
||||
|
||||
export type TopLevelBuilders = Exclude<BuilderComponents, Thumbnail | TextInput>;
|
||||
|
||||
export type FixedComponents<T = Button> = T extends Button ? ButtonLink | ButtonID : T;
|
||||
export interface ListenerOptions {
|
||||
timeout?: number;
|
||||
|
6
src/cache/adapters/limited.ts
vendored
6
src/cache/adapters/limited.ts
vendored
@ -94,7 +94,11 @@ export class LimitedMemoryAdapter<T> implements Adapter {
|
||||
}
|
||||
|
||||
private __set(key: string, data: any) {
|
||||
const __guildId = Array.isArray(data) ? data[0].guild_id : data.guild_id;
|
||||
const isArray = Array.isArray(data);
|
||||
if (isArray && data.length === 0) {
|
||||
return;
|
||||
}
|
||||
const __guildId = isArray ? data[0].guild_id : data.guild_id;
|
||||
const namespace = `${key.split('.')[0]}${__guildId ? `.${__guildId}` : ''}`;
|
||||
const self = this;
|
||||
if (!this.storage.has(namespace)) {
|
||||
|
12
src/cache/index.ts
vendored
12
src/cache/index.ts
vendored
@ -1,11 +1,5 @@
|
||||
import { type If, Logger } from '../common';
|
||||
|
||||
import type { Adapter } from './adapters';
|
||||
|
||||
import { Guilds } from './resources/guilds';
|
||||
import { Users } from './resources/users';
|
||||
|
||||
import type { InternalOptions, UsingClient } from '../commands';
|
||||
import { type If, Logger } from '../common';
|
||||
import {
|
||||
type APIChannel,
|
||||
type APIEmoji,
|
||||
@ -20,9 +14,11 @@ import {
|
||||
GuildMemberFlags,
|
||||
OverwriteType,
|
||||
} from '../types';
|
||||
import type { Adapter } from './adapters';
|
||||
import { Bans } from './resources/bans';
|
||||
import { Channels } from './resources/channels';
|
||||
import { Emojis } from './resources/emojis';
|
||||
import { Guilds } from './resources/guilds';
|
||||
import { Members } from './resources/members';
|
||||
import { Messages } from './resources/messages';
|
||||
import { Overwrites } from './resources/overwrites';
|
||||
@ -30,7 +26,9 @@ import { Presences } from './resources/presence';
|
||||
import { Roles } from './resources/roles';
|
||||
import { StageInstances } from './resources/stage-instances';
|
||||
import { Stickers } from './resources/stickers';
|
||||
import { Users } from './resources/users';
|
||||
import { VoiceStates } from './resources/voice-states';
|
||||
|
||||
export { BaseResource } from './resources/default/base';
|
||||
export { GuildBasedResource } from './resources/default/guild-based';
|
||||
export { GuildRelatedResource } from './resources/default/guild-related';
|
||||
|
8
src/cache/resources/guilds.ts
vendored
8
src/cache/resources/guilds.ts
vendored
@ -1,7 +1,7 @@
|
||||
import type { Cache, CacheFrom, ReturnCache } from '..';
|
||||
import { type GuildStructure, Transformers } from '../../client/transformers';
|
||||
import { fakePromise } from '../../common';
|
||||
import type { APIGuild, GatewayGuildCreateDispatchData } from '../../types';
|
||||
import type { Cache, CacheFrom, ReturnCache } from '..';
|
||||
import { BaseResource } from './default/base';
|
||||
|
||||
export class Guilds extends BaseResource<any, APIGuild | GatewayGuildCreateDispatchData> {
|
||||
@ -18,7 +18,7 @@ export class Guilds extends BaseResource<any, APIGuild | GatewayGuildCreateDispa
|
||||
);
|
||||
}
|
||||
|
||||
raw(id: string): ReturnCache<APIGuild | undefined> {
|
||||
raw(id: string): ReturnCache<(APIGuild & { member_count?: number }) | undefined> {
|
||||
return super.get(id);
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ export class Guilds extends BaseResource<any, APIGuild | GatewayGuildCreateDispa
|
||||
);
|
||||
}
|
||||
|
||||
bulkRaw(ids: string[]): ReturnCache<APIGuild[]> {
|
||||
bulkRaw(ids: string[]): ReturnCache<(APIGuild & { member_count?: number })[]> {
|
||||
return super.bulk(ids);
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ export class Guilds extends BaseResource<any, APIGuild | GatewayGuildCreateDispa
|
||||
);
|
||||
}
|
||||
|
||||
valuesRaw(): ReturnCache<APIGuild[]> {
|
||||
valuesRaw(): ReturnCache<(APIGuild & { member_count?: number })[]> {
|
||||
return super.values();
|
||||
}
|
||||
|
||||
|
36
src/cache/resources/members.ts
vendored
36
src/cache/resources/members.ts
vendored
@ -1,7 +1,7 @@
|
||||
import type { CacheFrom, ReturnCache } from '../..';
|
||||
import { type GuildMemberStructure, Transformers } from '../../client/transformers';
|
||||
import { fakePromise } from '../../common';
|
||||
import type { APIGuildMember } from '../../types';
|
||||
import type { APIGuildMember, APIUser } from '../../types';
|
||||
import { GuildBasedResource } from './default/guild-based';
|
||||
export class Members extends GuildBasedResource<any, APIGuildMember> {
|
||||
namespace = 'member';
|
||||
@ -39,14 +39,21 @@ export class Members extends GuildBasedResource<any, APIGuildMember> {
|
||||
|
||||
override bulk(ids: string[], guild: string): ReturnCache<GuildMemberStructure[]> {
|
||||
return fakePromise(super.bulk(ids, guild)).then(members =>
|
||||
fakePromise(this.client.cache.users?.bulkRaw(ids)).then(users =>
|
||||
members
|
||||
fakePromise(this.client.cache.users?.bulkRaw(ids)).then(users => {
|
||||
if (!users) return [];
|
||||
let usersRecord: null | Partial<Record<string, APIUser>> = {};
|
||||
for (const user of users) {
|
||||
usersRecord[user.id] = user;
|
||||
}
|
||||
const result = members
|
||||
.map(rawMember => {
|
||||
const user = users?.find(x => x.id === rawMember.id);
|
||||
const user = usersRecord![rawMember.id];
|
||||
return user ? Transformers.GuildMember(this.client, rawMember, user, guild) : undefined;
|
||||
})
|
||||
.filter(x => x !== undefined),
|
||||
),
|
||||
.filter(x => x !== undefined);
|
||||
usersRecord = null;
|
||||
return result;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@ -56,14 +63,21 @@ export class Members extends GuildBasedResource<any, APIGuildMember> {
|
||||
|
||||
override values(guild: string): ReturnCache<GuildMemberStructure[]> {
|
||||
return fakePromise(super.values(guild)).then(members =>
|
||||
fakePromise(this.client.cache.users?.valuesRaw()).then(users =>
|
||||
members
|
||||
fakePromise(this.client.cache.users?.bulkRaw(members.map(member => member.id))).then(users => {
|
||||
if (!users) return [];
|
||||
let usersRecord: null | Partial<Record<string, APIUser>> = {};
|
||||
for (const user of users) {
|
||||
usersRecord[user.id] = user;
|
||||
}
|
||||
const result = members
|
||||
.map(rawMember => {
|
||||
const user = users?.find(x => x.id === rawMember.id);
|
||||
const user = usersRecord![rawMember.id];
|
||||
return user ? Transformers.GuildMember(this.client, rawMember, user, rawMember.guild_id) : undefined;
|
||||
})
|
||||
.filter(x => x !== undefined),
|
||||
),
|
||||
.filter(x => x !== undefined);
|
||||
usersRecord = null;
|
||||
return result;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { promises } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { ApiHandler } from '../api';
|
||||
import { isBufferLike } from '../api/utils/utils';
|
||||
import type { Adapter, DisabledCache } from '../cache';
|
||||
import { Cache, MemoryAdapter } from '../cache';
|
||||
import type {
|
||||
@ -16,34 +18,31 @@ import type {
|
||||
UsingClient,
|
||||
} from '../commands';
|
||||
import { IgnoreCommand, type InferWithPrefix, type MiddlewareContext } from '../commands/applications/shared';
|
||||
import { HandleCommand } from '../commands/handle';
|
||||
import { CommandHandler } from '../commands/handler';
|
||||
import {
|
||||
ApplicationShorter,
|
||||
assertString,
|
||||
ChannelShorter,
|
||||
EmojiShorter,
|
||||
filterSplit,
|
||||
GuildShorter,
|
||||
InteractionShorter,
|
||||
InvitesShorter,
|
||||
LogLevels,
|
||||
Logger,
|
||||
LogLevels,
|
||||
type MakeRequired,
|
||||
MemberShorter,
|
||||
MergeOptions,
|
||||
MessageShorter,
|
||||
magicImport,
|
||||
ReactionShorter,
|
||||
RoleShorter,
|
||||
TemplateShorter,
|
||||
ThreadShorter,
|
||||
UsersShorter,
|
||||
WebhookShorter,
|
||||
assertString,
|
||||
filterSplit,
|
||||
magicImport,
|
||||
} from '../common';
|
||||
|
||||
import { promises } from 'node:fs';
|
||||
import { isBufferLike } from '../api/utils/utils';
|
||||
import { HandleCommand } from '../commands/handle';
|
||||
import { BanShorter } from '../common/shorters/bans';
|
||||
import { SoundboardShorter } from '../common/shorters/soundboard';
|
||||
import { VoiceStateShorter } from '../common/shorters/voiceStates';
|
||||
@ -180,15 +179,15 @@ export class BaseClient {
|
||||
this._botId = id;
|
||||
}
|
||||
|
||||
get botId() {
|
||||
return this._botId ?? BaseClient.getBotIdFromToken(this.rest.options.token);
|
||||
get botId(): string {
|
||||
return this._botId ?? BaseClient.getBotIdFromToken(this.rest.options.token) ?? '';
|
||||
}
|
||||
|
||||
set applicationId(id: string) {
|
||||
this._applicationId = id;
|
||||
}
|
||||
|
||||
get applicationId() {
|
||||
get applicationId(): string {
|
||||
return this._applicationId ?? this.botId;
|
||||
}
|
||||
|
||||
@ -470,6 +469,8 @@ export interface BaseClientOptions {
|
||||
globalMiddlewares?: readonly (keyof RegisteredMiddlewares)[];
|
||||
commands?: {
|
||||
defaults?: {
|
||||
onBeforeMiddlewares?: (context: CommandContext | MenuCommandContext<any, never>) => unknown;
|
||||
onBeforeOptions?: Command['onBeforeOptions'];
|
||||
onRunError?: (context: MenuCommandContext<any, never> | CommandContext, error: unknown) => unknown;
|
||||
onPermissionsFail?: Command['onPermissionsFail'];
|
||||
onBotPermissionsFail?: (
|
||||
@ -489,6 +490,7 @@ export interface BaseClientOptions {
|
||||
};
|
||||
components?: {
|
||||
defaults?: {
|
||||
onBeforeMiddlewares?: ComponentCommand['onBeforeMiddlewares'];
|
||||
onRunError?: ComponentCommand['onRunError'];
|
||||
onInternalError?: ComponentCommand['onInternalError'];
|
||||
onMiddlewaresError?: ComponentCommand['onMiddlewaresError'];
|
||||
@ -497,6 +499,7 @@ export interface BaseClientOptions {
|
||||
};
|
||||
modals?: {
|
||||
defaults?: {
|
||||
onBeforeMiddlewares?: ModalCommand['onBeforeMiddlewares'];
|
||||
onRunError?: ModalCommand['onRunError'];
|
||||
onInternalError?: ModalCommand['onInternalError'];
|
||||
onMiddlewaresError?: ModalCommand['onMiddlewaresError'];
|
||||
|
@ -1,17 +1,17 @@
|
||||
import type { CommandContext, Message } from '..';
|
||||
import {
|
||||
type Awaitable,
|
||||
assertString,
|
||||
type DeepPartial,
|
||||
type If,
|
||||
lazyLoadPackage,
|
||||
type PickPartial,
|
||||
type WatcherPayload,
|
||||
type WatcherSendToShard,
|
||||
assertString,
|
||||
lazyLoadPackage,
|
||||
When,
|
||||
} from '../common';
|
||||
import { EventHandler } from '../events';
|
||||
import type { GatewayDispatchPayload, GatewayPresenceUpdateData } from '../types';
|
||||
import { ShardManager, type ShardManagerOptions, properties } from '../websocket';
|
||||
import { properties, ShardManager, type ShardManagerOptions } from '../websocket';
|
||||
import { MemberUpdateHandler } from '../websocket/discord/events/memberUpdate';
|
||||
import { PresenceUpdateHandler } from '../websocket/discord/events/presenceUpdate';
|
||||
import type { BaseClientOptions, InternalRuntimeConfig, ServicesOptions, StartOptions } from './base';
|
||||
@ -23,7 +23,7 @@ let parentPort: import('node:worker_threads').MessagePort;
|
||||
|
||||
export class Client<Ready extends boolean = boolean> extends BaseClient {
|
||||
gateway!: ShardManager;
|
||||
me!: If<Ready, ClientUserStructure>;
|
||||
me!: When<Ready, ClientUserStructure>;
|
||||
declare options: Omit<ClientOptions, 'commands'> & {
|
||||
commands: NonNullable<ClientOptions['commands']>;
|
||||
};
|
||||
@ -36,8 +36,8 @@ export class Client<Ready extends boolean = boolean> extends BaseClient {
|
||||
super(options);
|
||||
}
|
||||
|
||||
get applicationId() {
|
||||
return this.me?.application.id ?? super.applicationId;
|
||||
get applicationId(): When<Ready, string, ''> {
|
||||
return (this.me?.application.id ?? super.applicationId) as never;
|
||||
}
|
||||
|
||||
set applicationId(id: string) {
|
||||
@ -219,8 +219,8 @@ export interface ClientOptions extends BaseClientOptions {
|
||||
};
|
||||
commands?: BaseClientOptions['commands'] & {
|
||||
prefix?: (message: MessageStructure) => Awaitable<string[]>;
|
||||
deferReplyResponse?: (ctx: CommandContext) => Parameters<Message['write']>[0];
|
||||
reply?: (ctx: CommandContext) => boolean;
|
||||
deferReplyResponse?: (ctx: CommandContext) => Awaitable<Parameters<Message['write']>[0]>;
|
||||
reply?: (ctx: CommandContext) => Awaitable<boolean>;
|
||||
};
|
||||
handlePayload?: ShardManagerOptions['handlePayload'];
|
||||
resharding?: PickPartial<NonNullable<ShardManagerOptions['resharding']>, 'getInfo'>;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { type UUID, randomUUID } from 'node:crypto';
|
||||
import { randomUUID, type UUID } from 'node:crypto';
|
||||
import type { UsingClient } from '../commands';
|
||||
import type { Awaitable, CamelCase } from '../common';
|
||||
import type { CallbackEventHandler, CustomEventsKeys, GatewayEvents } from '../events';
|
||||
|
@ -1,5 +1,5 @@
|
||||
export type { RuntimeConfig, RuntimeConfigHTTP } from './base';
|
||||
export * from './client';
|
||||
export * from './httpclient';
|
||||
export * from './workerclient';
|
||||
export * from './transformers';
|
||||
export * from './workerclient';
|
||||
|
@ -8,8 +8,8 @@ import {
|
||||
BaseGuildChannel,
|
||||
CategoryChannel,
|
||||
ClientUser,
|
||||
DMChannel,
|
||||
DirectoryChannel,
|
||||
DMChannel,
|
||||
Emoji,
|
||||
Entitlement,
|
||||
ForumChannel,
|
||||
|
@ -1,11 +1,24 @@
|
||||
import { type UUID, randomUUID } from 'node:crypto';
|
||||
import { randomUUID, type UUID } from 'node:crypto';
|
||||
import { ApiHandler, Logger } from '..';
|
||||
import { WorkerAdapter } from '../cache';
|
||||
import { type DeepPartial, LogLevels, type MakeRequired, type When, lazyLoadPackage } from '../common';
|
||||
import {
|
||||
type Awaitable,
|
||||
calculateShardId,
|
||||
type DeepPartial,
|
||||
LogLevels,
|
||||
lazyLoadPackage,
|
||||
type MakeRequired,
|
||||
type When,
|
||||
} from '../common';
|
||||
import { EventHandler } from '../events';
|
||||
import type { GatewayDispatchPayload, GatewaySendPayload } from '../types';
|
||||
import { Shard, type ShardManagerOptions, ShardSocketCloseCodes, type WorkerData, properties } from '../websocket';
|
||||
import { properties, Shard, type ShardManagerOptions, ShardSocketCloseCodes, type WorkerData } from '../websocket';
|
||||
import { MemberUpdateHandler } from '../websocket/discord/events/memberUpdate';
|
||||
import { PresenceUpdateHandler } from '../websocket/discord/events/presenceUpdate';
|
||||
import type { WorkerHeartbeaterMessages } from '../websocket/discord/heartbeater';
|
||||
import type { ShardData } from '../websocket/discord/shared';
|
||||
import type {
|
||||
ClientHeartbeaterMessages,
|
||||
WorkerDisconnectedAllShardsResharding,
|
||||
WorkerMessages,
|
||||
WorkerReady,
|
||||
@ -27,10 +40,6 @@ import type { ManagerMessages, ManagerSpawnShards } from '../websocket/discord/w
|
||||
import type { BaseClientOptions, ServicesOptions, StartOptions } from './base';
|
||||
import { BaseClient } from './base';
|
||||
import type { Client, ClientOptions } from './client';
|
||||
|
||||
import { MemberUpdateHandler } from '../websocket/discord/events/memberUpdate';
|
||||
import { PresenceUpdateHandler } from '../websocket/discord/events/presenceUpdate';
|
||||
import type { ShardData } from '../websocket/discord/shared';
|
||||
import { Collectors } from './collectors';
|
||||
import { type ClientUserStructure, Transformers } from './transformers';
|
||||
|
||||
@ -96,8 +105,8 @@ export class WorkerClient<Ready extends boolean = boolean> extends BaseClient {
|
||||
return acc / this.shards.size;
|
||||
}
|
||||
|
||||
get applicationId() {
|
||||
return this.me?.application.id ?? super.applicationId;
|
||||
get applicationId(): When<Ready, string, ''> {
|
||||
return (this.me?.application.id ?? super.applicationId) as never;
|
||||
}
|
||||
|
||||
set applicationId(id: string) {
|
||||
@ -166,13 +175,19 @@ export class WorkerClient<Ready extends boolean = boolean> extends BaseClient {
|
||||
}
|
||||
}
|
||||
|
||||
postMessage(body: WorkerMessages): unknown {
|
||||
postMessage(body: WorkerMessages | ClientHeartbeaterMessages): unknown {
|
||||
if (manager) return manager.postMessage(body);
|
||||
return process.send!(body);
|
||||
}
|
||||
|
||||
async handleManagerMessages(data: ManagerMessages) {
|
||||
async handleManagerMessages(data: ManagerMessages | WorkerHeartbeaterMessages) {
|
||||
switch (data.type) {
|
||||
case 'HEARTBEAT':
|
||||
this.postMessage({
|
||||
type: 'ACK_HEARTBEAT',
|
||||
workerId: workerData.workerId,
|
||||
});
|
||||
break;
|
||||
case 'CACHE_RESULT':
|
||||
if (this.cache.adapter instanceof WorkerAdapter && this.cache.adapter.promises.has(data.nonce)) {
|
||||
const cacheData = this.cache.adapter.promises.get(data.nonce)!;
|
||||
@ -377,12 +392,18 @@ export class WorkerClient<Ready extends boolean = boolean> extends BaseClient {
|
||||
return this.onPacket(packet, shardId);
|
||||
};
|
||||
}
|
||||
workerData.totalShards = data.totalShards;
|
||||
workerData.shards = [...this.shards.keys()];
|
||||
this.resharding.clear();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
calculateShardId(guildId: string) {
|
||||
return calculateShardId(guildId, this.workerData.totalShards);
|
||||
}
|
||||
|
||||
private generateNonce(): UUID {
|
||||
const uuid = randomUUID();
|
||||
if (this.promises.has(uuid)) return this.generateNonce();
|
||||
@ -420,7 +441,7 @@ export class WorkerClient<Ready extends boolean = boolean> extends BaseClient {
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
createShard(id: number, data: Pick<ManagerSpawnShards, 'info' | 'compress'>) {
|
||||
createShard(id: number, data: Pick<ManagerSpawnShards, 'info' | 'compress' | 'properties'>) {
|
||||
const onPacket = this.onPacket.bind(this);
|
||||
const handlePayload = this.options?.handlePayload?.bind(this);
|
||||
const self = this;
|
||||
@ -432,6 +453,7 @@ export class WorkerClient<Ready extends boolean = boolean> extends BaseClient {
|
||||
debugger: this.debugger,
|
||||
properties: {
|
||||
...properties,
|
||||
...data.properties,
|
||||
...this.options.gateway?.properties,
|
||||
},
|
||||
async handlePayload(shardId, payload) {
|
||||
@ -553,12 +575,12 @@ export function generateShardInfo(shard: Shard): WorkerShardInfo {
|
||||
};
|
||||
}
|
||||
|
||||
interface WorkerClientOptions extends BaseClientOptions {
|
||||
export interface WorkerClientOptions extends BaseClientOptions {
|
||||
commands?: NonNullable<Client['options']>['commands'];
|
||||
handlePayload?: ShardManagerOptions['handlePayload'];
|
||||
gateway?: ClientOptions['gateway'];
|
||||
postMessage?: (body: unknown) => unknown;
|
||||
postMessage?: (body: unknown) => Awaitable<unknown>;
|
||||
/** can have perfomance issues in big bots if the client sends every event, specially in startup (false by default) */
|
||||
sendPayloadToParent?: boolean;
|
||||
handleManagerMessages?(message: ManagerMessages): any;
|
||||
handleManagerMessages?(message: ManagerMessages | WorkerHeartbeaterMessages): Awaitable<unknown>;
|
||||
}
|
||||
|
@ -285,6 +285,8 @@ export class BaseCommand {
|
||||
Object.setPrototypeOf(this, __tempCommand.prototype);
|
||||
}
|
||||
|
||||
onBeforeMiddlewares?(context: CommandContext): any;
|
||||
onBeforeOptions?(context: CommandContext): any;
|
||||
run?(context: CommandContext): any;
|
||||
onAfterRun?(context: CommandContext, error: unknown | undefined): any;
|
||||
onRunError?(context: CommandContext, error: unknown): any;
|
||||
|
@ -79,7 +79,7 @@ export class CommandContext<
|
||||
if (this.interaction) return this.interaction.write(body, withResponse);
|
||||
const options = (this.client as Client | WorkerClient).options?.commands;
|
||||
return (this.messageResponse = await (this.message! as Message)[
|
||||
!this.messageResponse && options?.reply?.(this) ? 'reply' : 'write'
|
||||
!this.messageResponse && (await options?.reply?.(this)) ? 'reply' : 'write'
|
||||
](body)) as never;
|
||||
}
|
||||
|
||||
@ -97,8 +97,8 @@ export class CommandContext<
|
||||
return this.interaction.deferReply(ephemeral ? MessageFlags.Ephemeral : undefined, withResponse);
|
||||
this.__deferred = true;
|
||||
const options = (this.client as Client | WorkerClient).options?.commands;
|
||||
return (this.messageResponse = await (this.message! as Message)[options?.reply?.(this) ? 'reply' : 'write'](
|
||||
options?.deferReplyResponse?.(this) ?? { content: 'Thinking...' },
|
||||
return (this.messageResponse = await (this.message! as Message)[(await options?.reply?.(this)) ? 'reply' : 'write'](
|
||||
(await options?.deferReplyResponse?.(this)) ?? { content: 'Thinking...' },
|
||||
)) as never;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { type PermissionStrings, magicImport } from '../../common';
|
||||
import { magicImport, type PermissionStrings } from '../../common';
|
||||
import {
|
||||
ApplicationCommandType,
|
||||
type ApplicationIntegrationType,
|
||||
@ -54,6 +54,7 @@ export abstract class EntryPointCommand {
|
||||
Object.setPrototypeOf(this, __tempCommand.prototype);
|
||||
}
|
||||
|
||||
onBeforeMiddlewares?(context: EntryPointContext): any;
|
||||
abstract run?(context: EntryPointContext): any;
|
||||
onAfterRun?(context: EntryPointContext, error: unknown | undefined): any;
|
||||
onRunError(context: EntryPointContext<never>, error: unknown): any {
|
||||
|
@ -12,10 +12,11 @@ import type {
|
||||
MakeRequired,
|
||||
MessageWebhookCreateBodyRequest,
|
||||
ModalCreateBodyRequest,
|
||||
ModalCreateOptions,
|
||||
UnionToTuple,
|
||||
When,
|
||||
} from '../../common';
|
||||
import type { AllChannels, EntryPointInteraction } from '../../structures';
|
||||
import type { AllChannels, EntryPointInteraction, ModalSubmitInteraction } from '../../structures';
|
||||
import { MessageFlags, type RESTGetAPIGuildQuery } from '../../types';
|
||||
import { BaseContext } from '../basecontext';
|
||||
import type { RegisteredMiddlewares } from '../decorators';
|
||||
@ -52,8 +53,11 @@ export class EntryPointContext<M extends keyof RegisteredMiddlewares = never> ex
|
||||
return this.interaction.write<WR>(body, withResponse);
|
||||
}
|
||||
|
||||
modal(body: ModalCreateBodyRequest) {
|
||||
return this.interaction.modal(body);
|
||||
modal(body: ModalCreateBodyRequest, options?: undefined): Promise<undefined>;
|
||||
modal(body: ModalCreateBodyRequest, options: ModalCreateOptions): Promise<ModalSubmitInteraction | null>;
|
||||
modal(body: ModalCreateBodyRequest, options?: ModalCreateOptions | undefined) {
|
||||
if (options === undefined) return this.interaction.modal(body);
|
||||
return this.interaction.modal(body, options);
|
||||
}
|
||||
|
||||
deferReply<WR extends boolean = false>(
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { type PermissionStrings, magicImport } from '../../common';
|
||||
import { magicImport, type PermissionStrings } from '../../common';
|
||||
import type {
|
||||
ApplicationCommandType,
|
||||
ApplicationIntegrationType,
|
||||
@ -53,6 +53,7 @@ export abstract class ContextMenuCommand {
|
||||
Object.setPrototypeOf(this, __tempCommand.prototype);
|
||||
}
|
||||
|
||||
onBeforeMiddlewares?(context: MenuCommandContext<any>): any;
|
||||
abstract run?(context: MenuCommandContext<any>): any;
|
||||
onAfterRun?(context: MenuCommandContext<any>, error: unknown | undefined): any;
|
||||
onRunError?(context: MenuCommandContext<any, never>, error: unknown): any;
|
||||
|
@ -8,16 +8,22 @@ import {
|
||||
type WebhookMessageStructure,
|
||||
} from '../../client/transformers';
|
||||
import {
|
||||
type InteractionCreateBodyRequest,
|
||||
type InteractionMessageUpdateBodyRequest,
|
||||
type MakeRequired,
|
||||
type MessageWebhookCreateBodyRequest,
|
||||
type ModalCreateBodyRequest,
|
||||
type UnionToTuple,
|
||||
type When,
|
||||
InteractionCreateBodyRequest,
|
||||
InteractionMessageUpdateBodyRequest,
|
||||
MakeRequired,
|
||||
MessageWebhookCreateBodyRequest,
|
||||
ModalCreateBodyRequest,
|
||||
ModalCreateOptions,
|
||||
toSnakeCase,
|
||||
UnionToTuple,
|
||||
When,
|
||||
} from '../../common';
|
||||
import type { AllChannels, MessageCommandInteraction, UserCommandInteraction } from '../../structures';
|
||||
import {
|
||||
AllChannels,
|
||||
MessageCommandInteraction,
|
||||
ModalSubmitInteraction,
|
||||
UserCommandInteraction,
|
||||
} from '../../structures';
|
||||
import { type APIMessage, ApplicationCommandType, MessageFlags, type RESTGetAPIGuildQuery } from '../../types';
|
||||
import { BaseContext } from '../basecontext';
|
||||
import type { RegisteredMiddlewares } from '../decorators';
|
||||
@ -47,7 +53,6 @@ export class MenuCommandContext<
|
||||
metadata: CommandMetadata<UnionToTuple<M>> = {} as never;
|
||||
globalMetadata: GlobalMetadata = {};
|
||||
|
||||
// biome-ignore lint/suspicious/useGetterReturn: default don't exist.
|
||||
get target(): InteractionTarget<T> {
|
||||
switch (this.interaction.data.type) {
|
||||
case ApplicationCommandType.Message: {
|
||||
@ -76,8 +81,11 @@ export class MenuCommandContext<
|
||||
return this.interaction.write<WR>(body, withResponse);
|
||||
}
|
||||
|
||||
modal(body: ModalCreateBodyRequest) {
|
||||
return this.interaction.modal(body);
|
||||
modal(body: ModalCreateBodyRequest, options?: undefined): Promise<undefined>;
|
||||
modal(body: ModalCreateBodyRequest, options: ModalCreateOptions): Promise<ModalSubmitInteraction | null>;
|
||||
modal(body: ModalCreateBodyRequest, options?: ModalCreateOptions | undefined) {
|
||||
if (options === undefined) return this.interaction.modal(body);
|
||||
return this.interaction.modal(body, options);
|
||||
}
|
||||
|
||||
deferReply<WR extends boolean = false>(
|
||||
|
@ -1,10 +1,3 @@
|
||||
import type {
|
||||
AutocompleteCallback,
|
||||
EntryPointContext,
|
||||
MenuCommandContext,
|
||||
OnAutocompleteErrorCallback,
|
||||
ReturnOptionsTypes,
|
||||
} from '..';
|
||||
import type { Awaitable, FlatObjectKeys } from '../../common';
|
||||
import type { ModalContext } from '../../components';
|
||||
import type { ComponentContext } from '../../components/componentcontext';
|
||||
@ -15,6 +8,13 @@ import {
|
||||
ApplicationCommandOptionType,
|
||||
} from '../../types';
|
||||
import type { LocalizationMap } from '../../types/payloads';
|
||||
import type {
|
||||
AutocompleteCallback,
|
||||
EntryPointContext,
|
||||
MenuCommandContext,
|
||||
OnAutocompleteErrorCallback,
|
||||
ReturnOptionsTypes,
|
||||
} from '..';
|
||||
import type { CommandContext } from './chatcontext';
|
||||
import type { DefaultLocale, MiddlewareContext, OKFunction, SeyfertChannelMap, StopFunction } from './shared';
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import type {
|
||||
CategoryChannelStructure,
|
||||
DMChannelStructure,
|
||||
DirectoryChannelStructure,
|
||||
DMChannelStructure,
|
||||
ForumChannelStructure,
|
||||
MediaChannelStructure,
|
||||
NewsChannelStructure,
|
||||
|
@ -1,3 +1,32 @@
|
||||
import type { Client, WorkerClient } from '../client';
|
||||
import { type MessageStructure, type OptionResolverStructure, Transformers } from '../client/transformers';
|
||||
import type { MakeRequired } from '../common';
|
||||
import { INTEGER_OPTION_VALUE_LIMIT } from '../common/it/constants';
|
||||
import { ComponentContext, ModalContext } from '../components';
|
||||
import {
|
||||
type __InternalReplyFunction,
|
||||
AutocompleteInteraction,
|
||||
BaseInteraction,
|
||||
type ChatInputCommandInteraction,
|
||||
type ComponentInteraction,
|
||||
type EntryPointInteraction,
|
||||
type MessageCommandInteraction,
|
||||
type ModalSubmitInteraction,
|
||||
type UserCommandInteraction,
|
||||
} from '../structures';
|
||||
import type { PermissionsBitField } from '../structures/extra/Permissions';
|
||||
import {
|
||||
type APIApplicationCommandInteraction,
|
||||
type APIApplicationCommandInteractionDataOption,
|
||||
type APIInteraction,
|
||||
type APIInteractionDataResolvedChannel,
|
||||
ApplicationCommandOptionType,
|
||||
ApplicationCommandType,
|
||||
ChannelType,
|
||||
type GatewayMessageCreateDispatchData,
|
||||
InteractionContextType,
|
||||
InteractionType,
|
||||
} from '../types';
|
||||
import {
|
||||
BaseCommand,
|
||||
Command,
|
||||
@ -19,35 +48,6 @@ import {
|
||||
SubCommand,
|
||||
type UsingClient,
|
||||
} from '.';
|
||||
import type { Client, WorkerClient } from '../client';
|
||||
import { type MessageStructure, type OptionResolverStructure, Transformers } from '../client/transformers';
|
||||
import type { MakeRequired } from '../common';
|
||||
import { INTEGER_OPTION_VALUE_LIMIT } from '../common/it/constants';
|
||||
import { ComponentContext, ModalContext } from '../components';
|
||||
import {
|
||||
AutocompleteInteraction,
|
||||
BaseInteraction,
|
||||
type ChatInputCommandInteraction,
|
||||
type ComponentInteraction,
|
||||
type EntryPointInteraction,
|
||||
type MessageCommandInteraction,
|
||||
type ModalSubmitInteraction,
|
||||
type UserCommandInteraction,
|
||||
type __InternalReplyFunction,
|
||||
} from '../structures';
|
||||
import type { PermissionsBitField } from '../structures/extra/Permissions';
|
||||
import {
|
||||
type APIApplicationCommandInteraction,
|
||||
type APIApplicationCommandInteractionDataOption,
|
||||
type APIInteraction,
|
||||
type APIInteractionDataResolvedChannel,
|
||||
ApplicationCommandOptionType,
|
||||
ApplicationCommandType,
|
||||
ChannelType,
|
||||
type GatewayMessageCreateDispatchData,
|
||||
InteractionContextType,
|
||||
InteractionType,
|
||||
} from '../types';
|
||||
|
||||
export type CommandOptionWithType = CommandOption & {
|
||||
type: ApplicationCommandOptionType;
|
||||
@ -91,7 +91,7 @@ export class HandleCommand {
|
||||
await optionsResolver.getCommand()?.onInternalError?.(this.client, optionsResolver.getCommand()!, error);
|
||||
}
|
||||
} catch (error) {
|
||||
// pass
|
||||
this.client.logger.error(`[${optionsResolver.fullCommandName}] Internal error:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,17 +100,18 @@ export class HandleCommand {
|
||||
interaction: MessageCommandInteraction | UserCommandInteraction,
|
||||
context: MenuCommandContext<MessageCommandInteraction | UserCommandInteraction>,
|
||||
) {
|
||||
if (context.guildId && command.botPermissions) {
|
||||
const permissions = this.checkPermissions(interaction.appPermissions, command.botPermissions);
|
||||
if (permissions) return command.onBotPermissionsFail?.(context, permissions);
|
||||
}
|
||||
|
||||
const resultGlobal = await this.runGlobalMiddlewares(command, context);
|
||||
if (typeof resultGlobal === 'boolean') return;
|
||||
const resultMiddle = await this.runMiddlewares(command, context);
|
||||
if (typeof resultMiddle === 'boolean') return;
|
||||
|
||||
try {
|
||||
if (context.guildId && command.botPermissions) {
|
||||
const permissions = this.checkPermissions(interaction.appPermissions, command.botPermissions);
|
||||
if (permissions) return await command.onBotPermissionsFail?.(context, permissions);
|
||||
}
|
||||
|
||||
await command.onBeforeMiddlewares?.(context);
|
||||
const resultGlobal = await this.runGlobalMiddlewares(command, context);
|
||||
if (typeof resultGlobal === 'boolean') return;
|
||||
const resultMiddle = await this.runMiddlewares(command, context);
|
||||
if (typeof resultMiddle === 'boolean') return;
|
||||
|
||||
try {
|
||||
await command.run!(context);
|
||||
await command.onAfterRun?.(context, undefined);
|
||||
@ -121,8 +122,8 @@ export class HandleCommand {
|
||||
} catch (error) {
|
||||
try {
|
||||
await command.onInternalError?.(this.client, command, error);
|
||||
} catch {
|
||||
// pass
|
||||
} catch (err) {
|
||||
this.client.logger.error(`[${command.name}] Internal error:`, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -144,17 +145,18 @@ export class HandleCommand {
|
||||
}
|
||||
|
||||
async entryPoint(command: EntryPointCommand, interaction: EntryPointInteraction, context: EntryPointContext) {
|
||||
if (context.guildId && command.botPermissions) {
|
||||
const permissions = this.checkPermissions(interaction.appPermissions, command.botPermissions);
|
||||
if (permissions) return command.onBotPermissionsFail(context, permissions);
|
||||
}
|
||||
|
||||
const resultGlobal = await this.runGlobalMiddlewares(command, context);
|
||||
if (typeof resultGlobal === 'boolean') return;
|
||||
const resultMiddle = await this.runMiddlewares(command, context);
|
||||
if (typeof resultMiddle === 'boolean') return;
|
||||
|
||||
try {
|
||||
if (context.guildId && command.botPermissions) {
|
||||
const permissions = this.checkPermissions(interaction.appPermissions, command.botPermissions);
|
||||
if (permissions) return await command.onBotPermissionsFail(context, permissions);
|
||||
}
|
||||
|
||||
await command.onBeforeMiddlewares?.(context);
|
||||
const resultGlobal = await this.runGlobalMiddlewares(command, context);
|
||||
if (typeof resultGlobal === 'boolean') return;
|
||||
const resultMiddle = await this.runMiddlewares(command, context);
|
||||
if (typeof resultMiddle === 'boolean') return;
|
||||
|
||||
try {
|
||||
await command.run!(context);
|
||||
await command.onAfterRun?.(context, undefined);
|
||||
@ -165,8 +167,8 @@ export class HandleCommand {
|
||||
} catch (error) {
|
||||
try {
|
||||
await command.onInternalError(this.client, command, error);
|
||||
} catch {
|
||||
// pass
|
||||
} catch (err) {
|
||||
this.client.logger.error(`[${command.name}] Internal error:`, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -177,26 +179,28 @@ export class HandleCommand {
|
||||
resolver: OptionResolverStructure,
|
||||
context: CommandContext,
|
||||
) {
|
||||
if (context.guildId) {
|
||||
if (command.botPermissions) {
|
||||
const permissions = this.checkPermissions(interaction.appPermissions, command.botPermissions);
|
||||
if (permissions) return command.onBotPermissionsFail?.(context, permissions);
|
||||
}
|
||||
|
||||
if (command.defaultMemberPermissions) {
|
||||
const permissions = this.checkPermissions(interaction.member!.permissions, command.defaultMemberPermissions);
|
||||
if (permissions) return command.onPermissionsFail?.(context, permissions);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(await this.runOptions(command, context, resolver))) return;
|
||||
|
||||
const resultGlobal = await this.runGlobalMiddlewares(command, context);
|
||||
if (typeof resultGlobal === 'boolean') return;
|
||||
const resultMiddle = await this.runMiddlewares(command, context);
|
||||
if (typeof resultMiddle === 'boolean') return;
|
||||
|
||||
try {
|
||||
if (context.guildId) {
|
||||
if (command.botPermissions) {
|
||||
const permissions = this.checkPermissions(interaction.appPermissions, command.botPermissions);
|
||||
if (permissions) return await command.onBotPermissionsFail?.(context, permissions);
|
||||
}
|
||||
|
||||
if (command.defaultMemberPermissions) {
|
||||
const permissions = this.checkPermissions(interaction.member!.permissions, command.defaultMemberPermissions);
|
||||
if (permissions) return await command.onPermissionsFail?.(context, permissions);
|
||||
}
|
||||
}
|
||||
|
||||
await command.onBeforeOptions?.(context);
|
||||
if (!(await this.runOptions(command, context, resolver))) return;
|
||||
|
||||
await command.onBeforeMiddlewares?.(context);
|
||||
const resultGlobal = await this.runGlobalMiddlewares(command, context);
|
||||
if (typeof resultGlobal === 'boolean') return;
|
||||
const resultMiddle = await this.runMiddlewares(command, context);
|
||||
if (typeof resultMiddle === 'boolean') return;
|
||||
|
||||
try {
|
||||
await command.run!(context);
|
||||
await command.onAfterRun?.(context, undefined);
|
||||
@ -207,8 +211,8 @@ export class HandleCommand {
|
||||
} catch (error) {
|
||||
try {
|
||||
await command.onInternalError?.(this.client, command, error);
|
||||
} catch {
|
||||
// pass
|
||||
} catch (err) {
|
||||
this.client.logger.error(`[${command.name}] Internal error:`, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -350,17 +354,17 @@ export class HandleCommand {
|
||||
attachments: {},
|
||||
};
|
||||
|
||||
const args = this.argsParser(argsContent, command, message);
|
||||
const { options, errors } = await this.argsOptionsParser(command, rawMessage, args, resolved);
|
||||
const optionsResolver = this.makeResolver(self, options, parent as Command, rawMessage.guild_id, resolved);
|
||||
const context = new CommandContext(self, message, optionsResolver, shardId, command);
|
||||
//@ts-expect-error
|
||||
const extendContext = self.options?.context?.(message) ?? {};
|
||||
Object.assign(context, extendContext);
|
||||
|
||||
try {
|
||||
const args = this.argsParser(argsContent, command, message);
|
||||
const { options, errors } = await this.argsOptionsParser(command, rawMessage, args, resolved);
|
||||
const optionsResolver = this.makeResolver(self, options, parent as Command, rawMessage.guild_id, resolved);
|
||||
const context = new CommandContext(self, message, optionsResolver, shardId, command);
|
||||
//@ts-expect-error
|
||||
const extendContext = self.options?.context?.(message) ?? {};
|
||||
Object.assign(context, extendContext);
|
||||
|
||||
if (errors.length) {
|
||||
return command.onOptionsError?.(
|
||||
return await command.onOptionsError?.(
|
||||
context,
|
||||
Object.fromEntries(
|
||||
errors.map(x => {
|
||||
@ -383,7 +387,7 @@ export class HandleCommand {
|
||||
const permissions = this.checkPermissions(memberPermissions, command.defaultMemberPermissions);
|
||||
const guild = await this.client.guilds.raw(rawMessage.guild_id);
|
||||
if (permissions && guild.owner_id !== rawMessage.author.id) {
|
||||
return command.onPermissionsFail?.(context, memberPermissions.keys(permissions));
|
||||
return await command.onPermissionsFail?.(context, memberPermissions.keys(permissions));
|
||||
}
|
||||
}
|
||||
|
||||
@ -391,13 +395,15 @@ export class HandleCommand {
|
||||
const appPermissions = await self.members.permissions(rawMessage.guild_id, self.botId);
|
||||
const permissions = this.checkPermissions(appPermissions, command.botPermissions);
|
||||
if (permissions) {
|
||||
return command.onBotPermissionsFail?.(context, permissions);
|
||||
return await command.onBotPermissionsFail?.(context, permissions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await command.onBeforeOptions?.(context);
|
||||
if (!(await this.runOptions(command, context, optionsResolver))) return;
|
||||
|
||||
await command.onBeforeMiddlewares?.(context);
|
||||
const resultGlobal = await this.runGlobalMiddlewares(command, context);
|
||||
if (typeof resultGlobal === 'boolean') return;
|
||||
const resultMiddle = await this.runMiddlewares(command, context);
|
||||
@ -412,8 +418,8 @@ export class HandleCommand {
|
||||
} catch (error) {
|
||||
try {
|
||||
await command.onInternalError?.(this.client, command, error);
|
||||
} catch {
|
||||
// http 418
|
||||
} catch (err) {
|
||||
this.client.logger.error(`[${command.name}] Internal error:`, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -574,8 +580,8 @@ export class HandleCommand {
|
||||
} catch (e) {
|
||||
try {
|
||||
await command.onInternalError?.(this.client, command as never, e);
|
||||
} catch {
|
||||
// http 418
|
||||
} catch (err) {
|
||||
this.client.logger.error(`[${command.name}] Internal error:`, err);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@ -602,8 +608,8 @@ export class HandleCommand {
|
||||
} catch (e) {
|
||||
try {
|
||||
await command.onInternalError?.(this.client, command as never, e);
|
||||
} catch {
|
||||
// http 418
|
||||
} catch (err) {
|
||||
this.client.logger.error(`[${command.name}] Internal error:`, err);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@ -627,15 +633,7 @@ export class HandleCommand {
|
||||
async runOptions(command: Command | SubCommand, context: CommandContext, resolver: OptionResolverStructure) {
|
||||
const [erroredOptions, result] = await command.__runOptions(context, resolver);
|
||||
if (erroredOptions) {
|
||||
try {
|
||||
await command.onOptionsError?.(context, result);
|
||||
} catch (e) {
|
||||
try {
|
||||
await command.onInternalError?.(this.client, command, e);
|
||||
} catch {
|
||||
// http 418
|
||||
}
|
||||
}
|
||||
await command.onOptionsError?.(context, result);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { promises } from 'node:fs';
|
||||
import { basename, dirname } from 'node:path';
|
||||
import type { EntryPointCommand } from '.';
|
||||
import { dirname } from 'node:path';
|
||||
import type { Logger, NulleableCoalising, OmitInsert } from '../common';
|
||||
import { BaseHandler, isCloudfareWorker } from '../common';
|
||||
import { PermissionsBitField } from '../structures/extra/Permissions';
|
||||
@ -17,6 +16,7 @@ import {
|
||||
type LocaleString,
|
||||
type LocalizationMap,
|
||||
} from '../types';
|
||||
import type { EntryPointCommand } from '.';
|
||||
import { Command, type CommandOption, SubCommand } from './applications/chat';
|
||||
import { ContextMenuCommand } from './applications/menu';
|
||||
import { IgnoreCommand, type UsingClient } from './applications/shared';
|
||||
@ -299,7 +299,7 @@ export class CommandHandler extends BaseHandler {
|
||||
//@AutoLoad
|
||||
const options = await this.getFiles(dirname(file.path));
|
||||
for (const option of options) {
|
||||
if (file.name === basename(option)) {
|
||||
if (file.path === option) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
@ -466,6 +466,8 @@ export class CommandHandler extends BaseHandler {
|
||||
|
||||
stablishContextCommandDefaults(commandInstance: InstanceType<HandleableCommand>): ContextMenuCommand | false {
|
||||
if (!(commandInstance instanceof ContextMenuCommand)) return false;
|
||||
commandInstance.onBeforeMiddlewares ??= this.client.options.commands?.defaults?.onBeforeMiddlewares;
|
||||
|
||||
commandInstance.onAfterRun ??= this.client.options.commands?.defaults?.onAfterRun;
|
||||
|
||||
commandInstance.onBotPermissionsFail ??= this.client.options.commands?.defaults?.onBotPermissionsFail;
|
||||
@ -482,6 +484,8 @@ export class CommandHandler extends BaseHandler {
|
||||
commandInstance: InstanceType<HandleableCommand>,
|
||||
): OmitInsert<Command, 'options', { options: NonNullable<Command['options']> }> | false {
|
||||
if (!(commandInstance instanceof Command)) return false;
|
||||
commandInstance.onBeforeMiddlewares ??= this.client.options.commands?.defaults?.onBeforeMiddlewares;
|
||||
commandInstance.onBeforeOptions ??= this.client.options.commands?.defaults?.onBeforeOptions;
|
||||
commandInstance.onAfterRun ??= this.client.options.commands?.defaults?.onAfterRun;
|
||||
commandInstance.onBotPermissionsFail ??= this.client.options.commands?.defaults?.onBotPermissionsFail;
|
||||
commandInstance.onInternalError ??= this.client.options.commands?.defaults?.onInternalError;
|
||||
@ -495,6 +499,14 @@ export class CommandHandler extends BaseHandler {
|
||||
|
||||
stablishSubCommandDefaults(commandInstance: Command, option: SubCommand): SubCommand {
|
||||
option.middlewares = (commandInstance.middlewares ?? []).concat(option.middlewares ?? []);
|
||||
option.onBeforeMiddlewares =
|
||||
option.onBeforeMiddlewares?.bind(option) ??
|
||||
commandInstance.onBeforeMiddlewares?.bind(commandInstance) ??
|
||||
this.client.options.commands?.defaults?.onBeforeMiddlewares;
|
||||
option.onBeforeOptions =
|
||||
option.onBeforeOptions?.bind(option) ??
|
||||
commandInstance.onBeforeOptions?.bind(commandInstance) ??
|
||||
this.client.options.commands?.defaults?.onBeforeOptions;
|
||||
option.onMiddlewaresError =
|
||||
option.onMiddlewaresError?.bind(option) ??
|
||||
commandInstance.onMiddlewaresError?.bind(commandInstance) ??
|
||||
|
@ -1,11 +1,11 @@
|
||||
export * from './applications/shared';
|
||||
//
|
||||
export * from './applications/chat';
|
||||
export * from './applications/chatcontext';
|
||||
export * from './applications/entrycontext';
|
||||
export * from './applications/entryPoint';
|
||||
export * from './applications/menu';
|
||||
export * from './applications/menucontext';
|
||||
export * from './applications/options';
|
||||
export * from './applications/entryPoint';
|
||||
export * from './applications/entrycontext';
|
||||
export * from './applications/shared';
|
||||
export * from './decorators';
|
||||
export * from './optionresolver';
|
||||
|
@ -33,7 +33,7 @@ export class OptionResolver {
|
||||
readonly options: OptionResolved[];
|
||||
public hoistedOptions: OptionResolved[];
|
||||
private subCommand: string | null = null;
|
||||
private group: string | null = null;
|
||||
private group?: string;
|
||||
constructor(
|
||||
private client: UsingClient,
|
||||
options: APIApplicationCommandInteractionDataOption[],
|
||||
@ -63,7 +63,7 @@ export class OptionResolver {
|
||||
getCommand() {
|
||||
if (this.subCommand) {
|
||||
return (this.parent?.options as SubCommand[] | undefined)?.find(
|
||||
x => (this.group ? x.group === this.group : true) && x.name === this.subCommand,
|
||||
x => this.group === x.group && x.name === this.subCommand,
|
||||
);
|
||||
}
|
||||
return this.parent;
|
||||
|
@ -1,28 +1,28 @@
|
||||
export * from './it/constants';
|
||||
export * from './it/utils';
|
||||
//
|
||||
export * from './bot/watcher';
|
||||
export * from './it/colors';
|
||||
export { CustomizeLoggerCallback, AssignFilenameCallback, LogLevels, Logger, LoggerOptions } from './it/logger';
|
||||
export * from './it/constants';
|
||||
export * from './it/formatter';
|
||||
// circular lol
|
||||
export * from './shorters/invites';
|
||||
export { AssignFilenameCallback, CustomizeLoggerCallback, Logger, LoggerOptions, LogLevels } from './it/logger';
|
||||
export * from './it/utils';
|
||||
export * from './shorters/application';
|
||||
//
|
||||
export * from './shorters/channels';
|
||||
export * from './shorters/emojis';
|
||||
export * from './shorters/guilds';
|
||||
export * from './shorters/interaction';
|
||||
// circular lol
|
||||
export * from './shorters/invites';
|
||||
export * from './shorters/members';
|
||||
export * from './shorters/messages';
|
||||
export * from './shorters/reactions';
|
||||
export * from './shorters/roles';
|
||||
export * from './shorters/templates';
|
||||
export * from './shorters/users';
|
||||
export * from './shorters/threads';
|
||||
export * from './shorters/users';
|
||||
export * from './shorters/webhook';
|
||||
export * from './shorters/interaction';
|
||||
export * from './shorters/application';
|
||||
//
|
||||
export * from './types/options';
|
||||
export * from './types/resolvables';
|
||||
export * from './types/util';
|
||||
export * from './types/write';
|
||||
//
|
||||
export * from './bot/watcher';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { type WriteStream, createWriteStream, existsSync, mkdirSync, promises } from 'node:fs';
|
||||
import { createWriteStream, existsSync, mkdirSync, promises, type WriteStream } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { bgBrightWhite, black, bold, brightBlack, cyan, gray, italic, red, stripColor, yellow } from './colors';
|
||||
import { MergeOptions } from './utils';
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { promises } from 'node:fs';
|
||||
import { basename, join } from 'node:path';
|
||||
import type { Cache } from '../../cache';
|
||||
import { type APIPartialEmoji, FormattingPatterns, GatewayIntentBits } from '../../types';
|
||||
import {
|
||||
type ColorResolvable,
|
||||
DiscordEpoch,
|
||||
@ -10,8 +12,6 @@ import {
|
||||
type ObjectToSnake,
|
||||
type TypeArray,
|
||||
} from '..';
|
||||
import type { Cache } from '../../cache';
|
||||
import { type APIPartialEmoji, FormattingPatterns, GatewayIntentBits } from '../../types';
|
||||
|
||||
/**
|
||||
* Calculates the shard ID for a guild based on its ID.
|
||||
@ -304,8 +304,6 @@ export function lazyLoadPackage<T>(mod: string): T | undefined {
|
||||
try {
|
||||
return require(mod);
|
||||
} catch (e) {
|
||||
// biome-ignore lint/suspicious/noConsoleLog:
|
||||
// biome-ignore lint/suspicious/noConsole:
|
||||
console.log(`Cannot import ${mod}`, e);
|
||||
return;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { CacheFrom } from '../../cache';
|
||||
import type { Overwrites } from '../../cache/resources/overwrites';
|
||||
import { type MessageStructure, type ThreadChannelStructure, Transformers } from '../../client/transformers';
|
||||
import { type AllChannels, BaseChannel, type GuildMember, type GuildRole, channelFrom } from '../../structures';
|
||||
import { type AllChannels, BaseChannel, channelFrom, type GuildMember, type GuildRole } from '../../structures';
|
||||
import { PermissionsBitField } from '../../structures/extra/Permissions';
|
||||
import type {
|
||||
APIChannel,
|
||||
|
@ -14,8 +14,8 @@ import {
|
||||
type AllChannels,
|
||||
BaseChannel,
|
||||
type CreateStickerBodyRequest,
|
||||
type GuildChannelTypes,
|
||||
channelFrom,
|
||||
type GuildChannelTypes,
|
||||
} from '../../structures';
|
||||
import type {
|
||||
APIChannel,
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { BaseInteraction, Modal, type ReplyInteractionBody, resolveFiles } from '../..';
|
||||
import { Transformers, type WebhookMessageStructure } from '../../client/transformers';
|
||||
import type { RESTPostAPIWebhookWithTokenWaitResult } from '../../types';
|
||||
import type { InteractionMessageUpdateBodyRequest, MessageWebhookCreateBodyRequest } from '../types/write';
|
||||
import { BaseShorter } from './base';
|
||||
|
||||
@ -69,12 +70,12 @@ export class InteractionShorter extends BaseShorter {
|
||||
|
||||
async followup(token: string, { files, ...body }: MessageWebhookCreateBodyRequest): Promise<WebhookMessageStructure> {
|
||||
const parsedFiles = files ? await resolveFiles(files) : undefined;
|
||||
const apiMessage = await this.client.proxy
|
||||
const apiMessage = (await this.client.proxy
|
||||
.webhooks(this.client.applicationId)(token)
|
||||
.post({
|
||||
body: BaseInteraction.transformBody(body, parsedFiles, this.client),
|
||||
files: parsedFiles,
|
||||
});
|
||||
})) as RESTPostAPIWebhookWithTokenWaitResult;
|
||||
return Transformers.WebhookMessage(this.client, apiMessage, this.client.applicationId, token);
|
||||
}
|
||||
}
|
||||
|
@ -110,9 +110,10 @@ export class MemberShorter extends BaseShorter {
|
||||
async edit(
|
||||
guildId: string,
|
||||
memberId: string,
|
||||
body: RESTPatchAPIGuildMemberJSONBody,
|
||||
body: RESTPatchAPIGuildMemberJSONBody | { nick?: string | null },
|
||||
reason?: string,
|
||||
): Promise<GuildMemberStructure> {
|
||||
memberId = memberId === this.client.botId && 'nick' in body ? '@me' : memberId;
|
||||
const member = await this.client.proxy.guilds(guildId).members(memberId).patch({ body, reason });
|
||||
await this.client.cache.members?.setIfNI(CacheFrom.Rest, 'GuildMembers', memberId, guildId, member);
|
||||
return Transformers.GuildMember(this.client, member, member.user, guildId);
|
||||
|
@ -1,4 +1,7 @@
|
||||
import type { ValidAnswerId } from '../../api/Routes/channels';
|
||||
import { resolveFiles } from '../../builders';
|
||||
import { CacheFrom } from '../../cache';
|
||||
import { type MessageStructure, type ThreadChannelStructure, Transformers, type UserStructure } from '../../client';
|
||||
import { MessagesMethods } from '../../structures';
|
||||
import type {
|
||||
RESTGetAPIChannelMessagesQuery,
|
||||
@ -6,10 +9,6 @@ import type {
|
||||
RESTPostAPIChannelMessageJSONBody,
|
||||
RESTPostAPIChannelMessagesThreadsJSONBody,
|
||||
} from '../../types';
|
||||
|
||||
import type { ValidAnswerId } from '../../api/Routes/channels';
|
||||
import { CacheFrom } from '../../cache';
|
||||
import { type MessageStructure, type ThreadChannelStructure, Transformers, type UserStructure } from '../../client';
|
||||
import type { MessageCreateBodyRequest, MessageUpdateBodyRequest } from '../types/write';
|
||||
import { BaseShorter } from './base';
|
||||
|
||||
|
@ -92,10 +92,9 @@ export class RoleShorter extends BaseShorter {
|
||||
* @param reason The reason for deleting the role.
|
||||
* @returns A Promise that resolves when the role is deleted.
|
||||
*/
|
||||
async delete(guildId: string, roleId: string, reason?: string): Promise<GuildRoleStructure> {
|
||||
const res = await this.client.proxy.guilds(guildId).roles(roleId).delete({ reason });
|
||||
async delete(guildId: string, roleId: string, reason?: string) {
|
||||
await this.client.proxy.guilds(guildId).roles(roleId).delete({ reason });
|
||||
this.client.cache.roles?.removeIfNI('Guilds', roleId, guildId);
|
||||
return Transformers.GuildRole(this.client, res, guildId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,15 +1,16 @@
|
||||
import { CacheFrom } from '../..';
|
||||
import type { ThreadChannelStructure } from '../../client/transformers';
|
||||
import { channelFrom } from '../../structures';
|
||||
import type {
|
||||
APIThreadChannel,
|
||||
APIThreadMember,
|
||||
RESTGetAPIChannelThreadMembersQuery,
|
||||
RESTGetAPIChannelThreadsArchivedQuery,
|
||||
RESTPatchAPIChannelJSONBody,
|
||||
RESTPostAPIChannelMessagesThreadsJSONBody,
|
||||
RESTPostAPIChannelThreadsJSONBody,
|
||||
RESTPostAPIGuildForumThreadsJSONBody,
|
||||
import {
|
||||
type APIThreadChannel,
|
||||
type APIThreadMember,
|
||||
ChannelType,
|
||||
type RESTGetAPIChannelThreadMembersQuery,
|
||||
type RESTGetAPIChannelThreadsArchivedQuery,
|
||||
type RESTPatchAPIChannelJSONBody,
|
||||
type RESTPostAPIChannelMessagesThreadsJSONBody,
|
||||
type RESTPostAPIChannelThreadsJSONBody,
|
||||
type RESTPostAPIGuildForumThreadsJSONBody,
|
||||
} from '../../types';
|
||||
import type { MakeRequired, When } from '../types/util';
|
||||
import { BaseShorter } from './base';
|
||||
@ -44,27 +45,22 @@ export class ThreadShorter extends BaseShorter {
|
||||
);
|
||||
}
|
||||
|
||||
fromMessage(
|
||||
async fromMessage(
|
||||
channelId: string,
|
||||
messageId: string,
|
||||
options: RESTPostAPIChannelMessagesThreadsJSONBody & { reason?: string },
|
||||
): Promise<ThreadChannelStructure> {
|
||||
const { reason, ...body } = options;
|
||||
|
||||
return this.client.proxy
|
||||
.channels(channelId)
|
||||
.messages(messageId)
|
||||
.threads.post({ body, reason })
|
||||
.then(async thread => {
|
||||
await this.client.cache.channels?.setIfNI(
|
||||
CacheFrom.Rest,
|
||||
'Guilds',
|
||||
thread.id,
|
||||
(thread as APIThreadChannel).guild_id!,
|
||||
thread,
|
||||
);
|
||||
return channelFrom(thread, this.client) as ThreadChannelStructure;
|
||||
});
|
||||
const thread = await this.client.proxy.channels(channelId).messages(messageId).threads.post({ body, reason });
|
||||
await this.client.cache.channels?.setIfNI(
|
||||
CacheFrom.Rest,
|
||||
'Guilds',
|
||||
thread.id,
|
||||
(thread as APIThreadChannel).guild_id!,
|
||||
thread,
|
||||
);
|
||||
return await (channelFrom(thread, this.client) as ThreadChannelStructure);
|
||||
}
|
||||
|
||||
join(threadId: string) {
|
||||
@ -75,8 +71,9 @@ export class ThreadShorter extends BaseShorter {
|
||||
return this.client.proxy.channels(threadId)['thread-members']('@me').delete();
|
||||
}
|
||||
|
||||
lock(threadId: string, locked = true, reason?: string): Promise<ThreadChannelStructure> {
|
||||
return this.edit(threadId, { locked }, reason).then(x => channelFrom(x, this.client) as ThreadChannelStructure);
|
||||
async lock(threadId: string, locked = true, reason?: string): Promise<ThreadChannelStructure> {
|
||||
const x = await this.edit(threadId, { locked }, reason);
|
||||
return channelFrom(x, this.client) as ThreadChannelStructure;
|
||||
}
|
||||
|
||||
async edit(threadId: string, body: RESTPatchAPIChannelJSONBody, reason?: string): Promise<ThreadChannelStructure> {
|
||||
@ -110,7 +107,7 @@ export class ThreadShorter extends BaseShorter {
|
||||
return this.client.proxy.channels(threadId)['thread-members'].get({ query }) as never;
|
||||
}
|
||||
|
||||
async listArchivedThreads(
|
||||
async listArchived(
|
||||
channelId: string,
|
||||
type: 'public' | 'private',
|
||||
query?: RESTGetAPIChannelThreadsArchivedQuery,
|
||||
@ -128,6 +125,25 @@ export class ThreadShorter extends BaseShorter {
|
||||
};
|
||||
}
|
||||
|
||||
async listGuildActive(guildId: string, force = false): Promise<ThreadChannelStructure[]> {
|
||||
if (!force) {
|
||||
const cached = await this.client.cache.channels?.valuesRaw(guildId);
|
||||
if (cached)
|
||||
return cached
|
||||
.filter(x =>
|
||||
[ChannelType.PublicThread, ChannelType.PrivateThread, ChannelType.AnnouncementThread].includes(x.type),
|
||||
)
|
||||
.map(x => channelFrom(x, this.client) as ThreadChannelStructure);
|
||||
}
|
||||
const data = await this.client.proxy.guilds(guildId).threads.active.get();
|
||||
return Promise.all(
|
||||
data.threads.map(async thread => {
|
||||
await this.client.cache.channels?.setIfNI(CacheFrom.Rest, 'Guilds', thread.id, guildId, thread);
|
||||
return channelFrom(thread, this.client) as ThreadChannelStructure;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
async listJoinedArchivedPrivate(
|
||||
channelId: string,
|
||||
query?: RESTGetAPIChannelThreadsArchivedQuery,
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { resolveFiles } from '../../builders';
|
||||
import { Transformers, type WebhookMessageStructure, type WebhookStructure } from '../../client/transformers';
|
||||
import {
|
||||
MessagesMethods,
|
||||
type MessageWebhookMethodEditParams,
|
||||
type MessageWebhookMethodWriteParams,
|
||||
MessagesMethods,
|
||||
} from '../../structures';
|
||||
import type {
|
||||
APIWebhook,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { Identify } from '..';
|
||||
import type { CDNUrlOptions } from '../../api';
|
||||
import type { UsingClient } from '../../commands';
|
||||
import type { Identify } from '..';
|
||||
|
||||
export type ImageOptions = CDNUrlOptions;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import type { EmbedColors, OmitInsert } from '..';
|
||||
import type { Attachment, AttachmentDataType, AttachmentResolvable } from '../../builders';
|
||||
import type { GuildMember } from '../../structures';
|
||||
import type { APIGuildMember, APIPartialEmoji, RESTPostAPIApplicationEmojiJSONBody } from '../../types';
|
||||
import type { EmbedColors, OmitInsert } from '..';
|
||||
|
||||
export type EmojiResolvable = string | Partial<APIPartialEmoji> | `<${string | undefined}:${string}:${string}>`;
|
||||
export type GuildMemberResolvable = string | Partial<GuildMember> | APIGuildMember;
|
||||
|
@ -107,7 +107,7 @@ export type SnakeCase<S extends string> = S extends `${infer A}${infer Rest}`
|
||||
export type ObjectToLower<T> = T extends unknown[]
|
||||
? ObjectToLower<T[0]>[]
|
||||
: Identify<{
|
||||
[K in keyof T as CamelCase<Exclude<K, symbol | number>>]: T[K] extends unknown[]
|
||||
[K in keyof T as K extends number ? K : CamelCase<Exclude<K, symbol | number>>]: T[K] extends unknown[]
|
||||
? Identify<ObjectToLower<T[K][0]>[]>
|
||||
: T[K] extends object
|
||||
? Identify<ObjectToLower<T[K]>>
|
||||
@ -119,7 +119,7 @@ export type ObjectToLower<T> = T extends unknown[]
|
||||
export type ObjectToLowerUndefined<T> = T extends unknown[]
|
||||
? ObjectToLower<T[0]>[]
|
||||
: Identify<{
|
||||
[K in keyof T as CamelCase<Exclude<K, symbol | number>>]: T[K] extends unknown[]
|
||||
[K in keyof T as K extends number ? K : CamelCase<Exclude<K, symbol | number>>]: T[K] extends unknown[]
|
||||
? ObjectToLower<T[K][0]>[]
|
||||
: T[K] extends object
|
||||
? ObjectToLower<T[K]>
|
||||
@ -127,7 +127,7 @@ export type ObjectToLowerUndefined<T> = T extends unknown[]
|
||||
}>;
|
||||
|
||||
export type ObjectToSnake<T> = Identify<{
|
||||
[K in keyof T as SnakeCase<Exclude<K, symbol | number>>]: T[K] extends unknown[]
|
||||
[K in keyof T as K extends number ? K : SnakeCase<Exclude<K, symbol | number>>]: T[K] extends unknown[]
|
||||
? Identify<ObjectToSnake<T[K][0]>[]>
|
||||
: T[K] extends object
|
||||
? Identify<ObjectToSnake<T[K]>>
|
||||
@ -139,7 +139,7 @@ export type ObjectToSnake<T> = Identify<{
|
||||
export type ObjectToSnakeUndefined<T> = T extends unknown[]
|
||||
? ObjectToSnake<T[0]>[]
|
||||
: Identify<{
|
||||
[K in keyof T as SnakeCase<Exclude<K, symbol | number>>]: T[K] extends unknown[]
|
||||
[K in keyof T as K extends number ? K : SnakeCase<Exclude<K, symbol | number>>]: T[K] extends unknown[]
|
||||
? ObjectToSnake<T[K][0]>[]
|
||||
: T[K] extends object
|
||||
? ObjectToSnake<T[K]>
|
||||
@ -171,14 +171,10 @@ type OptionalizeAux<T extends object> = Identify<
|
||||
* it is recursive
|
||||
*/
|
||||
export type Optionalize<T> = T extends object
|
||||
? // biome-ignore lint/style/useShorthandArrayType: typescript things
|
||||
// biome-ignore lint/style/useConsistentArrayType: <explanation>
|
||||
T extends Array<unknown>
|
||||
? T extends Array<unknown>
|
||||
? number extends T['length']
|
||||
? T[number] extends object
|
||||
? // biome-ignore lint/style/useShorthandArrayType: <explanation>
|
||||
// biome-ignore lint/style/useConsistentArrayType: <explanation>
|
||||
Array<OptionalizeAux<T[number]>>
|
||||
? Array<OptionalizeAux<T[number]>>
|
||||
: T
|
||||
: Partial<T>
|
||||
: OptionalizeAux<T>
|
||||
|
@ -1,20 +1,11 @@
|
||||
import type { RawFile } from '../../api';
|
||||
import type { Attachment, AttachmentBuilder, Embed, Modal, PollBuilder, TopLevelBuilders } from '../../builders';
|
||||
import type {
|
||||
ActionRow,
|
||||
Attachment,
|
||||
AttachmentBuilder,
|
||||
BuilderComponents,
|
||||
Embed,
|
||||
Modal,
|
||||
PollBuilder,
|
||||
} from '../../builders';
|
||||
import type {
|
||||
APIActionRowComponent,
|
||||
APIEmbed,
|
||||
APIInteractionResponseCallbackData,
|
||||
APIInteractionResponseChannelMessageWithSource,
|
||||
APIMessageActionRowComponent,
|
||||
APIModalInteractionResponse,
|
||||
MessageFlags,
|
||||
RESTAPIPollCreate,
|
||||
RESTPatchAPIChannelMessageJSONBody,
|
||||
RESTPatchAPIWebhookWithTokenMessageJSONBody,
|
||||
@ -25,8 +16,9 @@ import type {
|
||||
import type { OmitInsert } from './util';
|
||||
|
||||
export interface ResolverProps {
|
||||
content?: string | undefined | null;
|
||||
embeds?: Embed[] | APIEmbed[] | undefined;
|
||||
components?: APIActionRowComponent<APIMessageActionRowComponent>[] | ActionRow<BuilderComponents>[] | undefined;
|
||||
components?: TopLevelBuilders[] | ReturnType<TopLevelBuilders['toJSON']>[];
|
||||
files?: AttachmentBuilder[] | Attachment[] | RawFile[] | undefined;
|
||||
}
|
||||
|
||||
@ -36,44 +28,50 @@ export interface SendResolverProps extends ResolverProps {
|
||||
|
||||
export type MessageCreateBodyRequest = OmitInsert<
|
||||
RESTPostAPIChannelMessageJSONBody,
|
||||
'components' | 'embeds' | 'poll',
|
||||
'components' | 'embeds' | 'poll' | 'content',
|
||||
SendResolverProps
|
||||
>;
|
||||
|
||||
export type MessageUpdateBodyRequest = OmitInsert<
|
||||
RESTPatchAPIChannelMessageJSONBody,
|
||||
'components' | 'embeds',
|
||||
'components' | 'embeds' | 'content',
|
||||
ResolverProps
|
||||
>;
|
||||
|
||||
export type MessageWebhookCreateBodyRequest = OmitInsert<
|
||||
RESTPostAPIWebhookWithTokenJSONBody,
|
||||
'components' | 'embeds' | 'poll',
|
||||
'components' | 'embeds' | 'poll' | 'content',
|
||||
SendResolverProps
|
||||
>;
|
||||
|
||||
export type MessageWebhookUpdateBodyRequest = OmitInsert<
|
||||
RESTPatchAPIWebhookWithTokenMessageJSONBody,
|
||||
'components' | 'embeds' | 'poll',
|
||||
'components' | 'embeds' | 'poll' | 'content',
|
||||
ResolverProps
|
||||
>;
|
||||
|
||||
export type InteractionMessageUpdateBodyRequest = OmitInsert<
|
||||
RESTPatchAPIWebhookWithTokenMessageJSONBody,
|
||||
'components' | 'embeds' | 'poll',
|
||||
'components' | 'embeds' | 'poll' | 'content',
|
||||
SendResolverProps
|
||||
>;
|
||||
> & {
|
||||
flags?: MessageFlags;
|
||||
};
|
||||
|
||||
export type ComponentInteractionMessageUpdate = OmitInsert<
|
||||
APIInteractionResponseCallbackData,
|
||||
'components' | 'embeds',
|
||||
'components' | 'embeds' | 'content',
|
||||
ResolverProps
|
||||
>;
|
||||
|
||||
export type InteractionCreateBodyRequest = OmitInsert<
|
||||
APIInteractionResponseChannelMessageWithSource['data'],
|
||||
'components' | 'embeds' | 'poll',
|
||||
'components' | 'embeds' | 'poll' | 'content',
|
||||
SendResolverProps
|
||||
>;
|
||||
|
||||
export type ModalCreateBodyRequest = APIModalInteractionResponse['data'] | Modal;
|
||||
|
||||
export interface ModalCreateOptions {
|
||||
waitFor?: number;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import type { ActionRowMessageComponents } from './index';
|
||||
import { componentFactory } from './index';
|
||||
|
||||
export class MessageActionRowComponent<
|
||||
T extends ActionRowMessageComponents,
|
||||
T extends ActionRowMessageComponents = ActionRowMessageComponents,
|
||||
> extends BaseComponent<ComponentType.ActionRow> {
|
||||
private ComponentsFactory: T[];
|
||||
constructor(data: {
|
||||
|
@ -1,13 +1,37 @@
|
||||
import { fromComponent } from '../builders';
|
||||
import {
|
||||
type ActionRow,
|
||||
type Button,
|
||||
type ChannelSelectMenu,
|
||||
type Container,
|
||||
type File,
|
||||
fromComponent,
|
||||
type MediaGallery,
|
||||
type MentionableSelectMenu,
|
||||
type RoleSelectMenu,
|
||||
type Section,
|
||||
type Separator,
|
||||
type StringSelectMenu,
|
||||
type TextDisplay,
|
||||
type TextInput,
|
||||
type Thumbnail,
|
||||
type UserSelectMenu,
|
||||
} from '../builders';
|
||||
import {
|
||||
type APIActionRowComponent,
|
||||
type APIActionRowComponentTypes,
|
||||
type APIButtonComponent,
|
||||
type APIChannelSelectComponent,
|
||||
type APIContainerComponent,
|
||||
type APIFileComponent,
|
||||
type APIMediaGalleryComponent,
|
||||
type APIMentionableSelectComponent,
|
||||
type APIRoleSelectComponent,
|
||||
type APISectionComponent,
|
||||
type APISeparatorComponent,
|
||||
type APIStringSelectComponent,
|
||||
type APITextDisplayComponent,
|
||||
type APITextInputComponent,
|
||||
type APIThumbnailComponent,
|
||||
type APIUserSelectComponent,
|
||||
ComponentType,
|
||||
} from '../types';
|
||||
@ -24,7 +48,7 @@ export class BaseComponent<T extends ComponentType> {
|
||||
}
|
||||
|
||||
toBuilder() {
|
||||
return fromComponent(this.data);
|
||||
return fromComponent(this.data) as BuilderComponentsMap[T];
|
||||
}
|
||||
}
|
||||
export interface APIComponentsMap {
|
||||
@ -36,4 +60,29 @@ export interface APIComponentsMap {
|
||||
[ComponentType.StringSelect]: APIStringSelectComponent;
|
||||
[ComponentType.UserSelect]: APIUserSelectComponent;
|
||||
[ComponentType.TextInput]: APITextInputComponent;
|
||||
[ComponentType.File]: APIFileComponent;
|
||||
[ComponentType.Thumbnail]: APIThumbnailComponent;
|
||||
[ComponentType.Section]: APISectionComponent;
|
||||
[ComponentType.Container]: APIContainerComponent;
|
||||
[ComponentType.MediaGallery]: APIMediaGalleryComponent;
|
||||
[ComponentType.Separator]: APISeparatorComponent;
|
||||
[ComponentType.TextDisplay]: APITextDisplayComponent;
|
||||
}
|
||||
|
||||
export interface BuilderComponentsMap {
|
||||
[ComponentType.ActionRow]: ActionRow;
|
||||
[ComponentType.Button]: Button;
|
||||
[ComponentType.ChannelSelect]: ChannelSelectMenu;
|
||||
[ComponentType.MentionableSelect]: MentionableSelectMenu;
|
||||
[ComponentType.RoleSelect]: RoleSelectMenu;
|
||||
[ComponentType.StringSelect]: StringSelectMenu;
|
||||
[ComponentType.UserSelect]: UserSelectMenu;
|
||||
[ComponentType.TextInput]: TextInput;
|
||||
[ComponentType.File]: File;
|
||||
[ComponentType.Thumbnail]: Thumbnail;
|
||||
[ComponentType.Section]: Section;
|
||||
[ComponentType.Container]: Container;
|
||||
[ComponentType.MediaGallery]: MediaGallery;
|
||||
[ComponentType.Separator]: Separator;
|
||||
[ComponentType.TextDisplay]: TextDisplay;
|
||||
}
|
||||
|
23
src/components/Container.ts
Normal file
23
src/components/Container.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import type { APIContainerComponent, ComponentType } from '../types';
|
||||
import { type ContainerComponents, componentFactory } from '.';
|
||||
import { BaseComponent } from './BaseComponent';
|
||||
|
||||
export class ContainerComponent extends BaseComponent<ComponentType.Container> {
|
||||
_components: ContainerComponents[];
|
||||
constructor(data: APIContainerComponent) {
|
||||
super(data);
|
||||
this._components = this.data.components.map(componentFactory) as ContainerComponents[];
|
||||
}
|
||||
|
||||
get components() {
|
||||
return this.data.components;
|
||||
}
|
||||
|
||||
get accentColor() {
|
||||
return this.data.accent_color;
|
||||
}
|
||||
|
||||
get spoiler() {
|
||||
return this.data.spoiler;
|
||||
}
|
||||
}
|
16
src/components/File.ts
Normal file
16
src/components/File.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import type { ComponentType } from '../types';
|
||||
import { BaseComponent } from './BaseComponent';
|
||||
|
||||
export class FileComponent extends BaseComponent<ComponentType.File> {
|
||||
get spoiler() {
|
||||
return this.data.spoiler;
|
||||
}
|
||||
|
||||
get file() {
|
||||
return this.data.file;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this.data.id;
|
||||
}
|
||||
}
|
12
src/components/MediaGallery.ts
Normal file
12
src/components/MediaGallery.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import type { ComponentType } from '../types';
|
||||
import { BaseComponent } from './BaseComponent';
|
||||
|
||||
export class MediaGalleryComponent extends BaseComponent<ComponentType.MediaGallery> {
|
||||
get items() {
|
||||
return this.data.items;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this.data.id;
|
||||
}
|
||||
}
|
23
src/components/Section.ts
Normal file
23
src/components/Section.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import type { APISectionComponent, ComponentType } from '../types';
|
||||
import { componentFactory } from '.';
|
||||
import { BaseComponent } from './BaseComponent';
|
||||
import type { ButtonComponent } from './ButtonComponent';
|
||||
import type { TextDisplayComponent } from './TextDisplay';
|
||||
import type { ThumbnailComponent } from './Thumbnail';
|
||||
|
||||
export class SectionComponent extends BaseComponent<ComponentType.Section> {
|
||||
protected _components: TextDisplayComponent[];
|
||||
protected _accessory: ThumbnailComponent | ButtonComponent;
|
||||
constructor(data: APISectionComponent) {
|
||||
super(data);
|
||||
this._components = data.components?.map(componentFactory) as TextDisplayComponent[];
|
||||
this._accessory = componentFactory(data.accessory) as ThumbnailComponent | ButtonComponent;
|
||||
}
|
||||
get components() {
|
||||
return this._components;
|
||||
}
|
||||
|
||||
get accessory() {
|
||||
return this._accessory;
|
||||
}
|
||||
}
|
16
src/components/Separator.ts
Normal file
16
src/components/Separator.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import type { ComponentType } from '../types';
|
||||
import { BaseComponent } from './BaseComponent';
|
||||
|
||||
export class SeparatorComponent extends BaseComponent<ComponentType.Separator> {
|
||||
get id() {
|
||||
return this.data.id;
|
||||
}
|
||||
|
||||
get spacing() {
|
||||
return this.data.spacing;
|
||||
}
|
||||
|
||||
get divider() {
|
||||
return this.data.divider;
|
||||
}
|
||||
}
|
8
src/components/TextDisplay.ts
Normal file
8
src/components/TextDisplay.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import type { ComponentType } from '../types';
|
||||
import { BaseComponent } from './BaseComponent';
|
||||
|
||||
export class TextDisplayComponent extends BaseComponent<ComponentType.TextDisplay> {
|
||||
get content() {
|
||||
return this.data.content;
|
||||
}
|
||||
}
|
20
src/components/Thumbnail.ts
Normal file
20
src/components/Thumbnail.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import type { ComponentType } from '../types';
|
||||
import { BaseComponent } from './BaseComponent';
|
||||
|
||||
export class ThumbnailComponent extends BaseComponent<ComponentType.Thumbnail> {
|
||||
get id() {
|
||||
return this.data.id;
|
||||
}
|
||||
|
||||
get media() {
|
||||
return this.data.media;
|
||||
}
|
||||
|
||||
get description() {
|
||||
return this.data.description;
|
||||
}
|
||||
|
||||
get spoiler() {
|
||||
return this.data.spoiler;
|
||||
}
|
||||
}
|
@ -14,13 +14,17 @@ export interface ComponentCommand {
|
||||
export abstract class ComponentCommand {
|
||||
type = InteractionCommandType.COMPONENT;
|
||||
abstract componentType: keyof ContextComponentCommandInteractionMap;
|
||||
customId?: string;
|
||||
customId?: string | RegExp;
|
||||
filter?(context: ComponentContext<typeof this.componentType>): Promise<boolean> | boolean;
|
||||
abstract run(context: ComponentContext<typeof this.componentType>): any;
|
||||
|
||||
/** @internal */
|
||||
_filter(context: ComponentContext) {
|
||||
if (this.customId && this.customId !== context.customId) return false;
|
||||
if (this.customId) {
|
||||
const matches =
|
||||
typeof this.customId === 'string' ? this.customId === context.customId : context.customId.match(this.customId);
|
||||
if (!matches) return false;
|
||||
}
|
||||
if (this.filter) return this.filter(context);
|
||||
return true;
|
||||
}
|
||||
@ -33,6 +37,7 @@ export abstract class ComponentCommand {
|
||||
return ComponentType[this.componentType];
|
||||
}
|
||||
|
||||
onBeforeMiddlewares?(context: ComponentContext): any;
|
||||
onAfterRun?(context: ComponentContext, error: unknown | undefined): any;
|
||||
onRunError?(context: ComponentContext, error: unknown): any;
|
||||
onMiddlewaresError?(context: ComponentContext, error: string): any;
|
||||
|
@ -18,16 +18,18 @@ import type {
|
||||
} from '../client/transformers';
|
||||
import type { CommandMetadata, ExtendContext, GlobalMetadata, RegisteredMiddlewares, UsingClient } from '../commands';
|
||||
import { BaseContext } from '../commands/basecontext';
|
||||
import type {
|
||||
import {
|
||||
ComponentInteractionMessageUpdate,
|
||||
InteractionCreateBodyRequest,
|
||||
InteractionMessageUpdateBodyRequest,
|
||||
MakeRequired,
|
||||
MessageWebhookCreateBodyRequest,
|
||||
ModalCreateBodyRequest,
|
||||
ModalCreateOptions,
|
||||
UnionToTuple,
|
||||
When,
|
||||
} from '../common';
|
||||
import { ModalSubmitInteraction } from '../structures';
|
||||
import { ComponentType, MessageFlags, type RESTGetAPIGuildQuery } from '../types';
|
||||
|
||||
export interface ComponentContext<
|
||||
@ -150,8 +152,11 @@ export class ComponentContext<
|
||||
return this.interaction.deleteResponse();
|
||||
}
|
||||
|
||||
modal(body: ModalCreateBodyRequest) {
|
||||
return this.interaction.modal(body);
|
||||
modal(body: ModalCreateBodyRequest, options?: undefined): Promise<undefined>;
|
||||
modal(body: ModalCreateBodyRequest, options: ModalCreateOptions): Promise<ModalSubmitInteraction | null>;
|
||||
modal(body: ModalCreateBodyRequest, options?: ModalCreateOptions | undefined) {
|
||||
if (options === undefined) return this.interaction.modal(body);
|
||||
return this.interaction.modal(body, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -9,7 +9,7 @@ import type {
|
||||
import { LimitedCollection } from '../collection';
|
||||
import { BaseCommand, type RegisteredMiddlewares, type UsingClient } from '../commands';
|
||||
import type { FileLoaded } from '../commands/handler';
|
||||
import { BaseHandler, type Logger, type OnFailCallback, isCloudfareWorker, magicImport } from '../common';
|
||||
import { BaseHandler, isCloudfareWorker, type Logger, magicImport, type OnFailCallback } from '../common';
|
||||
import type { ComponentInteraction, ModalSubmitInteraction, StringSelectMenuInteraction } from '../structures';
|
||||
import { ComponentCommand, InteractionCommandType } from './componentcommand';
|
||||
import type { ComponentContext } from './componentcontext';
|
||||
@ -38,6 +38,11 @@ export interface CreateComponentCollectorResult {
|
||||
callback: ComponentCallback<T>,
|
||||
): void;
|
||||
stop(reason?: string): void;
|
||||
waitFor<T extends CollectorInteraction = CollectorInteraction>(
|
||||
customId: UserMatches,
|
||||
timeout?: number,
|
||||
): Promise<T | null>;
|
||||
resetTimeouts(): void;
|
||||
}
|
||||
|
||||
export class ComponentHandler extends BaseHandler {
|
||||
@ -115,6 +120,28 @@ export class ComponentHandler extends BaseHandler {
|
||||
this.createComponentCollector(messageId, channelId, guildId, options, old.components);
|
||||
});
|
||||
},
|
||||
waitFor: (customId, timeout) =>
|
||||
new Promise(resolve => {
|
||||
const collector = this.values.get(messageId);
|
||||
if (!collector) return resolve(null);
|
||||
|
||||
let nodeTimeout: NodeJS.Timeout | undefined;
|
||||
|
||||
this.values.get(messageId)!.__run(customId, interaction => {
|
||||
clearTimeout(nodeTimeout);
|
||||
//@ts-expect-error generic
|
||||
resolve(interaction);
|
||||
});
|
||||
|
||||
if (timeout && timeout > 0)
|
||||
nodeTimeout = setTimeout(() => {
|
||||
resolve(null);
|
||||
// by default 15 seconds in case user don't do anything
|
||||
}, timeout);
|
||||
}),
|
||||
resetTimeouts: () => {
|
||||
this.resetTimeouts(messageId);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -204,6 +231,7 @@ export class ComponentHandler extends BaseHandler {
|
||||
component.onMiddlewaresError ??= this.client.options?.[is]?.defaults?.onMiddlewaresError;
|
||||
component.onRunError ??= this.client.options?.[is]?.defaults?.onRunError;
|
||||
component.onAfterRun ??= this.client.options?.[is]?.defaults?.onAfterRun;
|
||||
component.onBeforeMiddlewares ??= this.client.options?.[is]?.defaults?.onBeforeMiddlewares;
|
||||
}
|
||||
|
||||
set(instances: (new () => ComponentCommands)[]) {
|
||||
@ -289,6 +317,7 @@ export class ComponentHandler extends BaseHandler {
|
||||
|
||||
async execute(i: ComponentCommands, context: ComponentContext | ModalContext) {
|
||||
try {
|
||||
await i.onBeforeMiddlewares?.(context as never);
|
||||
const resultRunGlobalMiddlewares = await BaseCommand.__runMiddlewares(
|
||||
context,
|
||||
(context.client.options?.globalMiddlewares ?? []) as keyof RegisteredMiddlewares,
|
||||
@ -298,7 +327,7 @@ export class ComponentHandler extends BaseHandler {
|
||||
return;
|
||||
}
|
||||
if ('error' in resultRunGlobalMiddlewares) {
|
||||
return i.onMiddlewaresError?.(context as never, resultRunGlobalMiddlewares.error ?? 'Unknown error');
|
||||
return await i.onMiddlewaresError?.(context as never, resultRunGlobalMiddlewares.error ?? 'Unknown error');
|
||||
}
|
||||
|
||||
const resultRunMiddlewares = await BaseCommand.__runMiddlewares(context, i.middlewares, false);
|
||||
@ -306,7 +335,7 @@ export class ComponentHandler extends BaseHandler {
|
||||
return;
|
||||
}
|
||||
if ('error' in resultRunMiddlewares) {
|
||||
return i.onMiddlewaresError?.(context as never, resultRunMiddlewares.error ?? 'Unknown error');
|
||||
return await i.onMiddlewaresError?.(context as never, resultRunMiddlewares.error ?? 'Unknown error');
|
||||
}
|
||||
|
||||
try {
|
||||
@ -319,9 +348,8 @@ export class ComponentHandler extends BaseHandler {
|
||||
} catch (error) {
|
||||
try {
|
||||
await i.onInternalError?.(this.client, error);
|
||||
} catch (e) {
|
||||
// supress error
|
||||
this.logger.error(e);
|
||||
} catch (err) {
|
||||
this.client.logger.error(`[${i.customId ?? 'Component/Modal command'}] Internal error:`, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,19 @@
|
||||
import { type APIMessageActionRowComponent, ButtonStyle, ComponentType } from '../types';
|
||||
import { type APIComponents, type APITopLevelComponent, ButtonStyle, ComponentType } from '../types';
|
||||
import { MessageActionRowComponent } from './ActionRow';
|
||||
import { BaseComponent } from './BaseComponent';
|
||||
import { ButtonComponent, LinkButtonComponent, SKUButtonComponent } from './ButtonComponent';
|
||||
import { ChannelSelectMenuComponent } from './ChannelSelectMenuComponent';
|
||||
import { ContainerComponent } from './Container';
|
||||
import { FileComponent } from './File';
|
||||
import { MediaGalleryComponent } from './MediaGallery';
|
||||
import { MentionableSelectMenuComponent } from './MentionableSelectMenuComponent';
|
||||
import { RoleSelectMenuComponent } from './RoleSelectMenuComponent';
|
||||
import { SectionComponent } from './Section';
|
||||
import { SeparatorComponent } from './Separator';
|
||||
import { StringSelectMenuComponent } from './StringSelectMenuComponent';
|
||||
import type { TextInputComponent } from './TextInputComponent';
|
||||
import { TextDisplayComponent } from './TextDisplay';
|
||||
import { TextInputComponent } from './TextInputComponent';
|
||||
import { ThumbnailComponent } from './Thumbnail';
|
||||
import { UserSelectMenuComponent } from './UserSelectMenuComponent';
|
||||
|
||||
export type MessageComponents =
|
||||
@ -21,20 +29,37 @@ export type MessageComponents =
|
||||
|
||||
export type ActionRowMessageComponents = Exclude<MessageComponents, TextInputComponent>;
|
||||
|
||||
export type AllComponents = MessageComponents | TopLevelComponents | ContainerComponents | BaseComponent<ComponentType>;
|
||||
|
||||
export * from './componentcommand';
|
||||
export * from './componentcontext';
|
||||
export * from './modalcommand';
|
||||
export * from './modalcontext';
|
||||
|
||||
export type TopLevelComponents =
|
||||
| SectionComponent
|
||||
| ActionRowMessageComponents
|
||||
| TextDisplayComponent
|
||||
| ContainerComponent
|
||||
| FileComponent
|
||||
| MediaGalleryComponent
|
||||
| BaseComponent<APITopLevelComponent['type']>;
|
||||
|
||||
export type ContainerComponents =
|
||||
| MessageActionRowComponent
|
||||
| TextDisplayComponent
|
||||
| MediaGalleryComponent
|
||||
| SectionComponent
|
||||
| SeparatorComponent
|
||||
| FileComponent;
|
||||
|
||||
/**
|
||||
* Return a new component instance based on the component type.
|
||||
*
|
||||
* @param component The component to create.
|
||||
* @returns The component instance.
|
||||
*/
|
||||
export function componentFactory(
|
||||
component: APIMessageActionRowComponent,
|
||||
): ActionRowMessageComponents | BaseComponent<ActionRowMessageComponents['type']> {
|
||||
export function componentFactory(component: APIComponents): AllComponents {
|
||||
switch (component.type) {
|
||||
case ComponentType.Button: {
|
||||
if (component.style === ButtonStyle.Link) {
|
||||
@ -55,7 +80,25 @@ export function componentFactory(
|
||||
return new UserSelectMenuComponent(component);
|
||||
case ComponentType.MentionableSelect:
|
||||
return new MentionableSelectMenuComponent(component);
|
||||
case ComponentType.ActionRow:
|
||||
return new MessageActionRowComponent(component as any);
|
||||
case ComponentType.Container:
|
||||
return new ContainerComponent(component);
|
||||
case ComponentType.File:
|
||||
return new FileComponent(component);
|
||||
case ComponentType.MediaGallery:
|
||||
return new MediaGalleryComponent(component);
|
||||
case ComponentType.Section:
|
||||
return new SectionComponent(component);
|
||||
case ComponentType.TextDisplay:
|
||||
return new TextDisplayComponent(component);
|
||||
case ComponentType.Separator:
|
||||
return new SeparatorComponent(component);
|
||||
case ComponentType.Thumbnail:
|
||||
return new ThumbnailComponent(component);
|
||||
case ComponentType.TextInput:
|
||||
return new TextInputComponent(component);
|
||||
default:
|
||||
return new BaseComponent<ActionRowMessageComponents['type']>(component);
|
||||
return new BaseComponent<ComponentType>(component);
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ export abstract class ModalCommand {
|
||||
|
||||
props!: ExtraProps;
|
||||
|
||||
onBeforeMiddlewares?(context: ModalContext): any;
|
||||
onAfterRun?(context: ModalContext, error: unknown | undefined): any;
|
||||
onRunError?(context: ModalContext, error: unknown): any;
|
||||
onMiddlewaresError?(context: ModalContext, error: string): any;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { AllChannels, Interaction, ModalCommand, ModalSubmitInteraction, ReturnCache } from '..';
|
||||
import type { AllChannels, ModalCommand, ModalSubmitInteraction, ReturnCache } from '..';
|
||||
import type {
|
||||
GuildMemberStructure,
|
||||
GuildStructure,
|
||||
@ -8,12 +8,13 @@ import type {
|
||||
} from '../client/transformers';
|
||||
import type { CommandMetadata, ExtendContext, GlobalMetadata, RegisteredMiddlewares, UsingClient } from '../commands';
|
||||
import { BaseContext } from '../commands/basecontext';
|
||||
import type {
|
||||
import {
|
||||
InteractionCreateBodyRequest,
|
||||
InteractionMessageUpdateBodyRequest,
|
||||
MakeRequired,
|
||||
MessageWebhookCreateBodyRequest,
|
||||
ModalCreateBodyRequest,
|
||||
ModalCreateOptions,
|
||||
UnionToTuple,
|
||||
When,
|
||||
} from '../common';
|
||||
@ -119,9 +120,11 @@ export class ModalContext<M extends keyof RegisteredMiddlewares = never> extends
|
||||
return this.interaction.deleteResponse();
|
||||
}
|
||||
|
||||
modal(body: ModalCreateBodyRequest): ReturnType<Interaction['modal']> {
|
||||
//@ts-expect-error
|
||||
return this.interaction.modal(body);
|
||||
modal(body: ModalCreateBodyRequest, options?: undefined): Promise<undefined>;
|
||||
modal(body: ModalCreateBodyRequest, options: ModalCreateOptions): Promise<ModalSubmitInteraction | null>;
|
||||
modal(body: ModalCreateBodyRequest, options?: ModalCreateOptions | undefined) {
|
||||
// @ts-expect-error
|
||||
return this.interaction.modal(body, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4,11 +4,11 @@ import type { FileLoaded } from '../commands/handler';
|
||||
import {
|
||||
BaseHandler,
|
||||
type CamelCase,
|
||||
isCloudfareWorker,
|
||||
type MakeRequired,
|
||||
magicImport,
|
||||
ReplaceRegex,
|
||||
type SnakeCase,
|
||||
isCloudfareWorker,
|
||||
magicImport,
|
||||
} from '../common';
|
||||
import type { ClientEvents } from '../events/hooks';
|
||||
import * as RawEvents from '../events/hooks';
|
||||
|
@ -1,3 +1,6 @@
|
||||
import type { UsingClient } from '../../commands';
|
||||
import { toCamelCase } from '../../common';
|
||||
import { type AllChannels, channelFrom } from '../../structures';
|
||||
import type {
|
||||
GatewayChannelCreateDispatchData,
|
||||
GatewayChannelDeleteDispatchData,
|
||||
@ -5,10 +8,6 @@ import type {
|
||||
GatewayChannelUpdateDispatchData,
|
||||
} from '../../types';
|
||||
|
||||
import type { UsingClient } from '../../commands';
|
||||
import { toCamelCase } from '../../common';
|
||||
import { type AllChannels, channelFrom } from '../../structures';
|
||||
|
||||
export const CHANNEL_CREATE = (self: UsingClient, data: GatewayChannelCreateDispatchData): AllChannels => {
|
||||
return channelFrom(data, self);
|
||||
};
|
||||
|
@ -20,8 +20,8 @@ import type {
|
||||
GatewayGuildIntegrationsUpdateDispatchData,
|
||||
GatewayGuildMemberAddDispatchData,
|
||||
GatewayGuildMemberRemoveDispatchData,
|
||||
GatewayGuildMemberUpdateDispatchData,
|
||||
GatewayGuildMembersChunkDispatchData,
|
||||
GatewayGuildMemberUpdateDispatchData,
|
||||
GatewayGuildRoleCreateDispatchData,
|
||||
GatewayGuildRoleDeleteDispatchData,
|
||||
GatewayGuildRoleUpdateDispatchData,
|
||||
|
@ -10,13 +10,14 @@ export * from './interactions';
|
||||
export * from './invite';
|
||||
export * from './message';
|
||||
export * from './presence';
|
||||
export * from './soundboard';
|
||||
export * from './stage';
|
||||
export * from './subscriptions';
|
||||
export * from './thread';
|
||||
export * from './typing';
|
||||
export * from './user';
|
||||
export * from './voice';
|
||||
export * from './webhook';
|
||||
export * from './soundboard';
|
||||
|
||||
import type { CamelCase } from '../../common';
|
||||
import type * as RawEvents from './index';
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { type MessageStructure, Transformers } from '../../client/transformers';
|
||||
import type { UsingClient } from '../../commands';
|
||||
import { type ObjectToLower, type OmitInsert, fakePromise, toCamelCase } from '../../common';
|
||||
import { fakePromise, type ObjectToLower, type OmitInsert, toCamelCase } from '../../common';
|
||||
import type {
|
||||
GatewayMessageCreateDispatchData,
|
||||
GatewayMessageDeleteBulkDispatchData,
|
||||
|
@ -5,8 +5,8 @@ import type {
|
||||
APISoundBoard,
|
||||
GatewayGuildSoundboardSoundCreateDispatchData,
|
||||
GatewayGuildSoundboardSoundDeleteDispatchData,
|
||||
GatewayGuildSoundboardSoundUpdateDispatchData,
|
||||
GatewayGuildSoundboardSoundsUpdateDispatchData,
|
||||
GatewayGuildSoundboardSoundUpdateDispatchData,
|
||||
GatewaySoundboardSoundsDispatchData,
|
||||
} from '../../types';
|
||||
|
||||
|
@ -5,8 +5,8 @@ import type {
|
||||
GatewayThreadCreateDispatchData,
|
||||
GatewayThreadDeleteDispatchData,
|
||||
GatewayThreadListSyncDispatchData,
|
||||
GatewayThreadMemberUpdateDispatchData,
|
||||
GatewayThreadMembersUpdateDispatchData,
|
||||
GatewayThreadMemberUpdateDispatchData,
|
||||
GatewayThreadUpdateDispatchData,
|
||||
} from '../../types';
|
||||
|
||||
|
12
src/index.ts
12
src/index.ts
@ -1,4 +1,5 @@
|
||||
export * from './client';
|
||||
|
||||
import {
|
||||
BaseClient,
|
||||
type BaseClientOptions,
|
||||
@ -10,21 +11,22 @@ import {
|
||||
import { isCloudfareWorker } from './common';
|
||||
import type { ClientNameEvents, CustomEventsKeys, ResolveEventParams } from './events';
|
||||
import { GatewayIntentBits } from './types';
|
||||
export { Logger, PermissionStrings, Formatter } from './common';
|
||||
//
|
||||
export { Collection, LimitedCollection } from './collection';
|
||||
|
||||
//
|
||||
export * from './api';
|
||||
export * from './builders';
|
||||
export * from './cache';
|
||||
//
|
||||
export { Collection, LimitedCollection } from './collection';
|
||||
export * from './commands';
|
||||
export { Formatter, Logger, PermissionStrings } from './common';
|
||||
export * from './components';
|
||||
export * from './events';
|
||||
export * from './langs';
|
||||
//
|
||||
export { ShardManager, WorkerManager } from './websocket/discord';
|
||||
//
|
||||
export * from './structures';
|
||||
//
|
||||
export { ShardManager, WorkerManager } from './websocket/discord';
|
||||
|
||||
/**
|
||||
* Creates an event with the specified data and run function.
|
||||
|
@ -14,6 +14,7 @@ export const LangRouter = (userLocale: string, defaultLang: string, langs: Parti
|
||||
function getValue(locale?: string) {
|
||||
if (typeof locale === 'undefined') throw new Error('Undefined locale');
|
||||
let value = langs[locale] as Record<string, any>;
|
||||
if (typeof value === 'undefined') throw new Error(`Locale "${locale}" not found`);
|
||||
for (const i of route) value = value[i];
|
||||
return value;
|
||||
}
|
||||
@ -51,4 +52,4 @@ export type __InternalParseLocale<T extends Record<string, any>> = {
|
||||
};
|
||||
|
||||
export type ParseLocales<T extends Record<string, any>> = T;
|
||||
/**Idea inspiration from: FreeAoi */
|
||||
/**Idea inspiration from: FreeAoi | Fixed by: Drylozu */
|
||||
|
@ -1,18 +1,18 @@
|
||||
import type { GuildMemberStructure, GuildStructure } from '../client';
|
||||
import type { GuildMemberStructure, GuildStructure, ThreadChannelStructure } from '../client';
|
||||
import type { UsingClient } from '../commands';
|
||||
import type { CreateInviteFromChannel } from '../common';
|
||||
import type { ObjectToLower, StructPropState, StructStates, ToClass } from '../common/types/util';
|
||||
import type { APIGuild, APIPartialGuild, GatewayGuildCreateDispatchData, RESTPatchAPIGuildJSONBody } from '../types';
|
||||
import { AutoModerationRule } from './AutoModerationRule';
|
||||
import { BaseChannel, WebhookGuildMethods } from './channels';
|
||||
import { GuildEmoji } from './Emoji';
|
||||
import { BaseGuild } from './extra/BaseGuild';
|
||||
import type { DiscordBase } from './extra/DiscordBase';
|
||||
import { GuildBan } from './GuildBan';
|
||||
import { GuildMember } from './GuildMember';
|
||||
import { GuildRole } from './GuildRole';
|
||||
import { GuildTemplate } from './GuildTemplate';
|
||||
import { Sticker } from './Sticker';
|
||||
import { BaseChannel, WebhookGuildMethods } from './channels';
|
||||
import { BaseGuild } from './extra/BaseGuild';
|
||||
import type { DiscordBase } from './extra/DiscordBase';
|
||||
|
||||
export interface Guild extends ObjectToLower<Omit<APIGuild, 'stickers' | 'emojis' | 'roles'>>, DiscordBase {}
|
||||
export class Guild<State extends StructStates = 'api'> extends (BaseGuild as unknown as ToClass<
|
||||
@ -71,6 +71,10 @@ export class Guild<State extends StructStates = 'api'> extends (BaseGuild as unk
|
||||
return this.members.fetch(this.ownerId, force);
|
||||
}
|
||||
|
||||
listActiveThreads(force = false): Promise<ThreadChannelStructure[]> {
|
||||
return this.client.threads.listGuildActive(this.id, force);
|
||||
}
|
||||
|
||||
templates = GuildTemplate.methods({ client: this.client, guildId: this.id });
|
||||
stickers = Sticker.methods({ client: this.client, guildId: this.id });
|
||||
members = GuildMember.methods({ client: this.client, guildId: this.id });
|
||||
|
@ -3,7 +3,7 @@ import type { GuildBanStructure, GuildStructure } from '../client';
|
||||
import type { UsingClient } from '../commands';
|
||||
import { Formatter, type MethodContext, type ObjectToLower } from '../common';
|
||||
import type { BanShorter } from '../common/shorters/bans';
|
||||
import type { APIBan, ActuallyBan, RESTGetAPIGuildBansQuery } from '../types';
|
||||
import type { ActuallyBan, APIBan, RESTGetAPIGuildBansQuery } from '../types';
|
||||
import { DiscordBase } from './extra/DiscordBase';
|
||||
|
||||
export interface GuildBan extends DiscordBase, ObjectToLower<Omit<APIBan, 'id'>> {}
|
||||
|
@ -46,7 +46,7 @@ export class GuildRole extends DiscordBase {
|
||||
return this.client.roles.edit(this.guildId, this.id, body);
|
||||
}
|
||||
|
||||
delete(reason?: string): Promise<GuildRoleStructure> {
|
||||
delete(reason?: string) {
|
||||
return this.client.roles.delete(this.guildId, this.id, reason);
|
||||
}
|
||||
|
||||
@ -61,8 +61,7 @@ export class GuildRole extends DiscordBase {
|
||||
list: (force = false): Promise<GuildRoleStructure[]> => ctx.client.roles.list(ctx.guildId, force),
|
||||
edit: (roleId: string, body: RESTPatchAPIGuildRoleJSONBody, reason?: string): Promise<GuildRoleStructure> =>
|
||||
ctx.client.roles.edit(ctx.guildId, roleId, body, reason),
|
||||
delete: (roleId: string, reason?: string): Promise<GuildRoleStructure> =>
|
||||
ctx.client.roles.delete(ctx.guildId, roleId, reason),
|
||||
delete: (roleId: string, reason?: string) => ctx.client.roles.delete(ctx.guildId, roleId, reason),
|
||||
editPositions: (body: RESTPatchAPIGuildRolePositionsJSONBody): Promise<GuildRoleStructure[]> =>
|
||||
ctx.client.roles.editPositions(ctx.guildId, body),
|
||||
};
|
||||
|
@ -1,3 +1,34 @@
|
||||
import type { RawFile } from '../api';
|
||||
import { ActionRow, Embed, Modal, PollBuilder, resolveAttachment, resolveFiles } from '../builders';
|
||||
import type { ReturnCache } from '../cache';
|
||||
import {
|
||||
type EntitlementStructure,
|
||||
type GuildRoleStructure,
|
||||
type GuildStructure,
|
||||
type InteractionGuildMemberStructure,
|
||||
type MessageStructure,
|
||||
type OptionResolverStructure,
|
||||
Transformers,
|
||||
type UserStructure,
|
||||
type WebhookMessageStructure,
|
||||
} from '../client/transformers';
|
||||
import type { ContextOptionsResolved, UsingClient } from '../commands';
|
||||
import {
|
||||
type ComponentInteractionMessageUpdate,
|
||||
type InteractionCreateBodyRequest,
|
||||
type InteractionMessageUpdateBodyRequest,
|
||||
type MessageCreateBodyRequest,
|
||||
type MessageUpdateBodyRequest,
|
||||
type MessageWebhookCreateBodyRequest,
|
||||
type ModalCreateBodyRequest,
|
||||
ModalCreateOptions,
|
||||
type ObjectToLower,
|
||||
type OmitInsert,
|
||||
type ToClass,
|
||||
toCamelCase,
|
||||
type When,
|
||||
} from '../common';
|
||||
import { mix } from '../deps/mixer';
|
||||
import {
|
||||
type APIActionRowComponent,
|
||||
type APIApplicationCommandAutocompleteInteraction,
|
||||
@ -41,37 +72,6 @@ import {
|
||||
type RESTPostAPIInteractionCallbackJSONBody,
|
||||
type RESTPostAPIInteractionCallbackResult,
|
||||
} from '../types';
|
||||
|
||||
import type { RawFile } from '../api';
|
||||
import { ActionRow, Embed, Modal, PollBuilder, resolveAttachment, resolveFiles } from '../builders';
|
||||
import type { ReturnCache } from '../cache';
|
||||
import {
|
||||
type EntitlementStructure,
|
||||
type GuildRoleStructure,
|
||||
type GuildStructure,
|
||||
type InteractionGuildMemberStructure,
|
||||
type MessageStructure,
|
||||
type OptionResolverStructure,
|
||||
Transformers,
|
||||
type UserStructure,
|
||||
type WebhookMessageStructure,
|
||||
} from '../client/transformers';
|
||||
import type { ContextOptionsResolved, UsingClient } from '../commands';
|
||||
import {
|
||||
type ComponentInteractionMessageUpdate,
|
||||
type InteractionCreateBodyRequest,
|
||||
type InteractionMessageUpdateBodyRequest,
|
||||
type MessageCreateBodyRequest,
|
||||
type MessageUpdateBodyRequest,
|
||||
type MessageWebhookCreateBodyRequest,
|
||||
type ModalCreateBodyRequest,
|
||||
type ObjectToLower,
|
||||
type OmitInsert,
|
||||
type ToClass,
|
||||
type When,
|
||||
toCamelCase,
|
||||
} from '../common';
|
||||
import { mix } from '../deps/mixer';
|
||||
import { type AllChannels, channelFrom } from './';
|
||||
import { DiscordBase } from './extra/DiscordBase';
|
||||
import { PermissionsBitField } from './extra/Permissions';
|
||||
@ -148,6 +148,7 @@ export class BaseInteraction<
|
||||
//@ts-ignore
|
||||
return {
|
||||
type: body.type,
|
||||
// @ts-expect-error
|
||||
data: BaseInteraction.transformBody(body.data ?? {}, files, self),
|
||||
};
|
||||
}
|
||||
@ -195,7 +196,7 @@ export class BaseInteraction<
|
||||
poll: poll ? (poll instanceof PollBuilder ? poll.toJSON() : poll) : undefined,
|
||||
};
|
||||
|
||||
if ('attachments' in body) {
|
||||
if (Array.isArray(body.attachments)) {
|
||||
payload.attachments =
|
||||
body.attachments?.map((x, i) => ({
|
||||
id: x.id ?? i.toString(),
|
||||
@ -314,7 +315,6 @@ export class BaseInteraction<
|
||||
switch (gateway.type) {
|
||||
case InteractionType.ApplicationCommandAutocomplete:
|
||||
return new AutocompleteInteraction(client, gateway, undefined, __reply);
|
||||
// biome-ignore lint/suspicious/noFallthroughSwitchClause: bad interaction between biome and ts-server
|
||||
case InteractionType.ApplicationCommand:
|
||||
switch (gateway.data.type) {
|
||||
case ApplicationCommandType.ChatInput:
|
||||
@ -330,7 +330,6 @@ export class BaseInteraction<
|
||||
case ApplicationCommandType.PrimaryEntryPoint:
|
||||
return new EntryPointInteraction(client, gateway as APIEntryPointCommandInteraction, __reply);
|
||||
}
|
||||
// biome-ignore lint/suspicious/noFallthroughSwitchClause: bad interaction between biome and ts-server
|
||||
case InteractionType.MessageComponent:
|
||||
switch (gateway.data.component_type) {
|
||||
case ComponentType.Button:
|
||||
@ -357,6 +356,8 @@ export class BaseInteraction<
|
||||
gateway as APIMessageComponentSelectMenuInteraction,
|
||||
__reply,
|
||||
);
|
||||
default:
|
||||
return;
|
||||
}
|
||||
case InteractionType.ModalSubmit:
|
||||
return new ModalSubmitInteraction(client, gateway);
|
||||
@ -472,11 +473,37 @@ export class Interaction<
|
||||
) as never;
|
||||
}
|
||||
|
||||
modal(body: ModalCreateBodyRequest) {
|
||||
return this.reply({
|
||||
modal(body: ModalCreateBodyRequest, options?: undefined): Promise<undefined>;
|
||||
modal(body: ModalCreateBodyRequest, options: ModalCreateOptions): Promise<ModalSubmitInteraction | null>;
|
||||
async modal(body: ModalCreateBodyRequest, options?: ModalCreateOptions | undefined) {
|
||||
if (options !== undefined && !(body instanceof Modal)) {
|
||||
body = new Modal(body);
|
||||
}
|
||||
|
||||
if (options === undefined)
|
||||
return this.reply({
|
||||
type: InteractionResponseType.Modal,
|
||||
data: body,
|
||||
});
|
||||
|
||||
const promise = new Promise<ModalSubmitInteraction | null>(res => {
|
||||
let nodeTimeout: NodeJS.Timeout | undefined;
|
||||
// body is always a modal here, so we can safely cast it
|
||||
(body as Modal).__exec = (interaction: ModalSubmitInteraction) => {
|
||||
res(interaction);
|
||||
clearTimeout(nodeTimeout);
|
||||
};
|
||||
if (options?.waitFor && options?.waitFor > 0) {
|
||||
nodeTimeout = setTimeout(() => {
|
||||
res(null);
|
||||
}, options.waitFor);
|
||||
}
|
||||
});
|
||||
await this.reply({
|
||||
type: InteractionResponseType.Modal,
|
||||
data: body,
|
||||
});
|
||||
return promise;
|
||||
}
|
||||
|
||||
async editOrReply<FR extends boolean = false>(
|
||||
@ -488,8 +515,8 @@ export class Interaction<
|
||||
fetchReply?: FR,
|
||||
): Promise<WebhookMessageStructure> {
|
||||
if (await this.replied) {
|
||||
const { content, embeds, allowed_mentions, components, files, attachments, poll } = body;
|
||||
return this.editResponse({ content, embeds, allowed_mentions, components, files, attachments, poll });
|
||||
const { content, embeds, allowed_mentions, components, files, attachments, poll, flags } = body;
|
||||
return this.editResponse({ content, embeds, allowed_mentions, components, files, attachments, poll, flags });
|
||||
}
|
||||
return this.write(body as InteractionCreateBodyRequest, fetchReply);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { type AllChannels, Embed, type ReturnCache } from '..';
|
||||
import { type AllChannels, componentFactory, Embed, type ReturnCache } from '..';
|
||||
import type { ListenerOptions } from '../builders';
|
||||
import {
|
||||
type GuildMemberStructure,
|
||||
@ -11,12 +11,10 @@ import {
|
||||
type WebhookStructure,
|
||||
} from '../client/transformers';
|
||||
import type { UsingClient } from '../commands';
|
||||
import { type ObjectToLower, toCamelCase } from '../common';
|
||||
import { Formatter } from '../common';
|
||||
import { Formatter, type ObjectToLower, toCamelCase } from '../common';
|
||||
import type { EmojiResolvable } from '../common/types/resolvables';
|
||||
import type { MessageCreateBodyRequest, MessageUpdateBodyRequest } from '../common/types/write';
|
||||
import type { ActionRowMessageComponents } from '../components';
|
||||
import { MessageActionRowComponent } from '../components/ActionRow';
|
||||
import type { TopLevelComponents } from '../components';
|
||||
import type {
|
||||
APIChannelMention,
|
||||
APIEmbed,
|
||||
@ -25,8 +23,8 @@ import type {
|
||||
APIUser,
|
||||
GatewayMessageCreateDispatchData,
|
||||
} from '../types';
|
||||
import type { MessageWebhookMethodEditParams, MessageWebhookMethodWriteParams } from './Webhook';
|
||||
import { DiscordBase } from './extra/DiscordBase';
|
||||
import type { MessageWebhookMethodEditParams, MessageWebhookMethodWriteParams } from './Webhook';
|
||||
|
||||
export type MessageData = APIMessage | GatewayMessageCreateDispatchData;
|
||||
|
||||
@ -37,7 +35,7 @@ export interface BaseMessage
|
||||
guildId?: string;
|
||||
author: UserStructure;
|
||||
member?: GuildMemberStructure;
|
||||
components: MessageActionRowComponent<ActionRowMessageComponents>[];
|
||||
components: TopLevelComponents[];
|
||||
poll?: PollStructure;
|
||||
mentions: {
|
||||
roles: string[];
|
||||
@ -55,7 +53,7 @@ export class BaseMessage extends DiscordBase {
|
||||
channels: data.mention_channels ?? [],
|
||||
users: [],
|
||||
};
|
||||
this.components = data.components?.map(x => new MessageActionRowComponent(x)) ?? [];
|
||||
this.components = (data.components?.map(componentFactory) as TopLevelComponents[]) ?? [];
|
||||
this.embeds = data.embeds.map(embed => new InMessageEmbed(embed));
|
||||
this.patch(data);
|
||||
}
|
||||
|
@ -21,9 +21,9 @@ import type {
|
||||
*/
|
||||
import type {
|
||||
APIWebhook,
|
||||
RESTGetAPIWebhookWithTokenMessageQuery,
|
||||
RESTPatchAPIWebhookJSONBody,
|
||||
RESTPatchAPIWebhookWithTokenJSONBody,
|
||||
RESTPatchAPIWebhookWithTokenMessageQuery,
|
||||
RESTPostAPIWebhookWithTokenQuery,
|
||||
} from '../types';
|
||||
import type { AllChannels } from './channels';
|
||||
@ -181,7 +181,7 @@ export class Webhook extends DiscordBase {
|
||||
/** Type definition for parameters of editing a message through a webhook. */
|
||||
export type MessageWebhookMethodEditParams = MessageWebhookPayload<
|
||||
MessageWebhookUpdateBodyRequest,
|
||||
{ messageId: string; query?: RESTGetAPIWebhookWithTokenMessageQuery }
|
||||
{ messageId: string; query?: RESTPatchAPIWebhookWithTokenMessageQuery }
|
||||
>;
|
||||
/** Type definition for parameters of writing a message through a webhook. */
|
||||
export type MessageWebhookMethodWriteParams = MessageWebhookPayload<
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { Collection, Formatter, type RawFile, type ReturnCache } from '..';
|
||||
import { ActionRow, Embed, PollBuilder, resolveAttachment } from '../builders';
|
||||
import { Embed, PollBuilder, resolveAttachment } from '../builders';
|
||||
import type { Overwrites } from '../cache/resources/overwrites';
|
||||
import {
|
||||
type BaseChannelStructure,
|
||||
type BaseGuildChannelStructure,
|
||||
type CategoryChannelStructure,
|
||||
type DMChannelStructure,
|
||||
type DirectoryChannelStructure,
|
||||
type DMChannelStructure,
|
||||
type ForumChannelStructure,
|
||||
type GuildMemberStructure,
|
||||
type GuildStructure,
|
||||
@ -26,13 +26,13 @@ import type { SeyfertChannelMap, UsingClient } from '../commands';
|
||||
import {
|
||||
type CreateInviteFromChannel,
|
||||
type EmojiResolvable,
|
||||
fakePromise,
|
||||
type MessageCreateBodyRequest,
|
||||
type MessageUpdateBodyRequest,
|
||||
type MethodContext,
|
||||
type ObjectToLower,
|
||||
type StringToNumber,
|
||||
type ToClass,
|
||||
fakePromise,
|
||||
} from '../common';
|
||||
import { mix } from '../deps/mixer';
|
||||
import {
|
||||
@ -63,9 +63,9 @@ import {
|
||||
type ThreadAutoArchiveDuration,
|
||||
VideoQualityMode,
|
||||
} from '../types';
|
||||
import { DiscordBase } from './extra/DiscordBase';
|
||||
import type { GuildMember } from './GuildMember';
|
||||
import type { GuildRole } from './GuildRole';
|
||||
import { DiscordBase } from './extra/DiscordBase';
|
||||
|
||||
export class BaseNoEditableChannel<T extends ChannelType> extends DiscordBase<APIChannelBase<ChannelType>> {
|
||||
declare type: T;
|
||||
@ -353,8 +353,8 @@ export class MessagesMethods extends DiscordBase {
|
||||
const payload = {
|
||||
allowed_mentions: self.options?.allowedMentions,
|
||||
...body,
|
||||
components: body.components?.map(x => (x instanceof ActionRow ? x.toJSON() : x)) ?? undefined,
|
||||
embeds: body.embeds?.map(x => (x instanceof Embed ? x.toJSON() : x)) ?? undefined,
|
||||
embeds: body.embeds?.map(x => (x instanceof Embed ? x.toJSON() : x)),
|
||||
components: body.components?.map(x => ('toJSON' in x ? x.toJSON() : x)) ?? undefined,
|
||||
poll: poll ? (poll instanceof PollBuilder ? poll.toJSON() : poll) : undefined,
|
||||
};
|
||||
|
||||
@ -581,13 +581,15 @@ export class ForumChannel extends BaseGuildChannel {
|
||||
|
||||
export interface ThreadChannel
|
||||
extends ObjectToLower<Omit<APIThreadChannel, 'permission_overwrites' | 'guild_id'>>,
|
||||
Omit<TextBaseGuildChannel, 'edit' | 'parentId'> {}
|
||||
Omit<TextBaseGuildChannel, 'edit' | 'parentId'> {
|
||||
parentId: string;
|
||||
}
|
||||
@mix(TextBaseGuildChannel)
|
||||
export class ThreadChannel extends BaseChannel<
|
||||
ChannelType.PublicThread | ChannelType.AnnouncementThread | ChannelType.PrivateThread
|
||||
> {
|
||||
parentId!: string;
|
||||
declare type: ChannelType.PublicThread | ChannelType.AnnouncementThread | ChannelType.PrivateThread;
|
||||
|
||||
webhooks = WebhookChannelMethods.channel({
|
||||
client: this.client,
|
||||
channelId: this.parentId,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { ReturnCache, WorkerClient } from '../..';
|
||||
import type { GuildStructure } from '../../client';
|
||||
import { type ObjectToLower, calculateShardId } from '../../common';
|
||||
import { calculateShardId, type ObjectToLower } from '../../common';
|
||||
import type { ImageOptions } from '../../common/types/options';
|
||||
import { type APIPartialGuild, GuildFeature } from '../../types';
|
||||
import type { ShardManager } from '../../websocket';
|
||||
|
@ -1,19 +1,19 @@
|
||||
export * from './AnonymousGuild';
|
||||
export * from './AutoModerationRule';
|
||||
export * from './ClientUser';
|
||||
export * from './Guild';
|
||||
export * from './channels';
|
||||
export * from './Emoji';
|
||||
export * from './Entitlement';
|
||||
export * from './Guild';
|
||||
export * from './GuildBan';
|
||||
export * from './GuildMember';
|
||||
export * from './GuildPreview';
|
||||
export * from './GuildRole';
|
||||
export * from './GuildTemplate';
|
||||
export * from './Interaction';
|
||||
export * from './Message';
|
||||
export * from './Poll';
|
||||
export * from './Sticker';
|
||||
export * from './User';
|
||||
export * from './VoiceState';
|
||||
export * from './Webhook';
|
||||
export * from './channels';
|
||||
export * from './Poll';
|
||||
export * from './GuildBan';
|
||||
export * from './Entitlement';
|
||||
|
@ -23,9 +23,9 @@
|
||||
*/
|
||||
|
||||
export * from './gateway';
|
||||
export * from './rest';
|
||||
export * from './payloads';
|
||||
export * from './rest';
|
||||
export * from './rest';
|
||||
export * from './utils';
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,6 @@
|
||||
import type { ApplicationIntegrationType, InteractionContextType } from '..';
|
||||
import type { ChannelType, Permissions, Snowflake } from '../..';
|
||||
|
||||
import type { LocaleString } from '../../rest';
|
||||
import type { ApplicationIntegrationType, InteractionContextType } from '..';
|
||||
import type {
|
||||
APIAttachment,
|
||||
APIChannel,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { Snowflake } from '../../index';
|
||||
import type { ComponentType } from '../channel';
|
||||
import type { ComponentType, Snowflake } from '../../index';
|
||||
|
||||
import type { APIBaseInteraction, InteractionType } from '../interactions';
|
||||
import type {
|
||||
APIDMInteractionWrapper,
|
||||
|
@ -1,8 +1,9 @@
|
||||
import type { APIActionRowComponent, APIModalActionRowComponent } from '../channel';
|
||||
import type {
|
||||
APIActionRowComponent,
|
||||
APIBaseInteraction,
|
||||
APIDMInteractionWrapper,
|
||||
APIGuildInteractionWrapper,
|
||||
APIModalActionRowComponent,
|
||||
ComponentType,
|
||||
InteractionType,
|
||||
} from '../index';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import type { MakeRequired } from '../../../common';
|
||||
import type { RESTPostAPIWebhookWithTokenJSONBody } from '../../index';
|
||||
import type { APIActionRowComponent, APIModalActionRowComponent } from '../channel';
|
||||
import type { MessageFlags } from '../index';
|
||||
|
||||
import type { APIActionRowComponent, APIModalActionRowComponent, MessageFlags } from '../index';
|
||||
import type { APIApplicationCommandOptionChoice } from './applicationCommands';
|
||||
|
||||
/**
|
||||
|
@ -2,9 +2,9 @@
|
||||
* Types extracted from https://discord.com/developers/docs/resources/application
|
||||
*/
|
||||
|
||||
import type { APIEmoji, LocalizationMap } from '.';
|
||||
import type { Permissions, Snowflake } from '..';
|
||||
import type { MakeRequired } from '../../common';
|
||||
import type { Permissions, Snowflake } from '..';
|
||||
import type { APIEmoji, LocalizationMap } from '.';
|
||||
import type { APIPartialGuild } from './guild';
|
||||
import type { ApplicationIntegrationType } from './interactions';
|
||||
import type { OAuth2Scopes } from './oauth2';
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user