mirror of
https://github.com/Vendicated/Vencord.git
synced 2024-09-20 06:30:35 +00:00
Merge 702aad0ca7
into 640d99dcda
This commit is contained in:
commit
7b7c386940
489 changed files with 21033 additions and 10654 deletions
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
|
@ -20,13 +20,13 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v3 # Install pnpm using packageManager key in package.json
|
||||
- uses: pnpm/action-setup@v4 # Install pnpm using packageManager key in package.json
|
||||
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "pnpm"
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
|
68
.github/workflows/change-reporter.yml
vendored
Normal file
68
.github/workflows/change-reporter.yml
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
name: Change Reporter
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# Every day at midnight
|
||||
- cron: 0 0 * * *
|
||||
|
||||
jobs:
|
||||
change-reporter:
|
||||
if: github.repository == 'Vendicated/Vencord'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
if: ${{ github.event_name == 'schedule' }}
|
||||
with:
|
||||
ref: dev
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
|
||||
- uses: pnpm/action-setup@v4 # Install pnpm using packageManager key in package.json
|
||||
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ^20.11.0
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Install Google Chrome
|
||||
id: setup-chrome
|
||||
uses: browser-actions/setup-chrome@v1
|
||||
with:
|
||||
chrome-version: stable
|
||||
install-dependencies: true
|
||||
|
||||
- name: Build Vencord web standalone
|
||||
run: pnpm buildWebStandalone --skip-extension
|
||||
|
||||
- name: Create Report (Stable)
|
||||
timeout-minutes: 10
|
||||
run: |
|
||||
cd packages/discord-types
|
||||
pnpm change-reporter
|
||||
env:
|
||||
CHANNEL: stable
|
||||
CHROMIUM_BIN: ${{ steps.setup-chrome.outputs.chrome-path }}
|
||||
CHROMIUM_VERSION: ${{ steps.setup-chrome.outputs.chrome-version }}
|
||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
VENCORD_DIST: ../../dist/browser.js
|
||||
|
||||
- name: Create Report (Canary)
|
||||
timeout-minutes: 10
|
||||
if: ${{ !cancelled() }} # run even if previous one failed
|
||||
run: |
|
||||
cd packages/discord-types
|
||||
pnpm change-reporter
|
||||
env:
|
||||
CHANNEL: canary
|
||||
CHROMIUM_BIN: ${{ steps.setup-chrome.outputs.chrome-path }}
|
||||
CHROMIUM_VERSION: ${{ steps.setup-chrome.outputs.chrome-version }}
|
||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
VENCORD_DIST: ../../dist/browser.js
|
6
.github/workflows/publish.yml
vendored
6
.github/workflows/publish.yml
vendored
|
@ -20,13 +20,13 @@ jobs:
|
|||
exit 1
|
||||
fi
|
||||
|
||||
- uses: pnpm/action-setup@v3 # Install pnpm using packageManager key in package.json
|
||||
- uses: pnpm/action-setup@v4 # Install pnpm using packageManager key in package.json
|
||||
|
||||
- name: Use Node.js 19
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "pnpm"
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
|
4
.github/workflows/reportBrokenPlugins.yml
vendored
4
.github/workflows/reportBrokenPlugins.yml
vendored
|
@ -19,13 +19,13 @@ jobs:
|
|||
- uses: actions/checkout@v4
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
|
||||
- uses: pnpm/action-setup@v3 # Install pnpm using packageManager key in package.json
|
||||
- uses: pnpm/action-setup@v4 # Install pnpm using packageManager key in package.json
|
||||
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "pnpm"
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
|
|
34
.github/workflows/test-packages-discord-types.yml
vendored
Normal file
34
.github/workflows/test-packages-discord-types.yml
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
name: Test packages/discord-types
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- packages/discord-types/**
|
||||
push:
|
||||
paths:
|
||||
- packages/discord-types/**
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v4 # Install pnpm using packageManager key in package.json
|
||||
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ^20.9.0
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Check packages/discord-types for TypeScript errors and lint
|
||||
run: | # https://github.com/microsoft/TypeScript/issues/40431
|
||||
pnpm tspc --emitDeclarationOnly
|
||||
cd packages/discord-types
|
||||
pnpm test
|
||||
|
||||
- name: Check if packages/discord-types is compatible with Vencord
|
||||
run: pnpm testTsc && pnpm lint
|
33
.github/workflows/test-scripts.yml
vendored
Normal file
33
.github/workflows/test-scripts.yml
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
name: Test scripts
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- scripts/**
|
||||
- eslint.config.mjs
|
||||
push:
|
||||
paths:
|
||||
- scripts/**
|
||||
- eslint.config.mjs
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v4 # Install pnpm using packageManager key in package.json
|
||||
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ^20.9.0
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Check scripts for TypeScript errors
|
||||
run: | # https://github.com/microsoft/TypeScript/issues/40431
|
||||
pnpm tspc --emitDeclarationOnly
|
||||
cd scripts
|
||||
pnpm tsc --noEmit
|
10
.github/workflows/test.yml
vendored
10
.github/workflows/test.yml
vendored
|
@ -1,23 +1,27 @@
|
|||
name: test
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- packages/discord-types
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
paths-ignore:
|
||||
- packages/discord-types
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v3 # Install pnpm using packageManager key in package.json
|
||||
- uses: pnpm/action-setup@v4 # Install pnpm using packageManager key in package.json
|
||||
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "pnpm"
|
||||
node-version: ^20.9.0
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
{
|
||||
"extends": "stylelint-config-standard",
|
||||
"extends": [
|
||||
"stylelint-config-standard",
|
||||
"@stylistic/stylelint-config"
|
||||
],
|
||||
"plugins": [
|
||||
"@stylistic/stylelint-plugin"
|
||||
],
|
||||
"rules": {
|
||||
"@stylistic/indentation": 4,
|
||||
"selector-class-pattern": [
|
||||
"^[a-z][a-zA-Z0-9]*(-[a-z0-9][a-zA-Z0-9]*)*$",
|
||||
{
|
||||
|
|
8
.vscode/settings.json
vendored
8
.vscode/settings.json
vendored
|
@ -1,5 +1,4 @@
|
|||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
|
@ -9,6 +8,8 @@
|
|||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||
},
|
||||
"files.eol": "\n",
|
||||
"files.insertFinalNewline": true,
|
||||
"javascript.format.semicolons": "insert",
|
||||
"typescript.format.semicolons": "insert",
|
||||
"typescript.preferences.quoteStyle": "double",
|
||||
|
@ -19,5 +20,8 @@
|
|||
"domain": "codeberg.org",
|
||||
"type": "Gitea"
|
||||
}
|
||||
]
|
||||
],
|
||||
|
||||
"typescript.tsdk": "./node_modules/typescript/lib",
|
||||
"typescript.enablePromptUseWorkspaceTsdk": true
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ const cssListeners = new Set<(css: string) => void>();
|
|||
const NOOP = () => { };
|
||||
const NOOP_ASYNC = async () => { };
|
||||
|
||||
const setCssDebounced = debounce((css: string) => VencordNative.quickCss.set(css));
|
||||
const setCssDebounced = debounce((css: string) => { VencordNative.quickCss.set(css); });
|
||||
|
||||
const themeStore = DataStore.createStore("VencordThemes", "VencordThemeData");
|
||||
|
||||
|
@ -46,9 +46,8 @@ window.VencordNative = {
|
|||
uploadTheme: (fileName: string, fileData: string) => DataStore.set(fileName, fileData, themeStore),
|
||||
deleteTheme: (fileName: string) => DataStore.del(fileName, themeStore),
|
||||
getThemesDir: async () => "",
|
||||
getThemesList: () => DataStore.entries(themeStore).then(entries =>
|
||||
entries.map(([name, css]) => getThemeInfo(css, name.toString()))
|
||||
),
|
||||
getThemesList: async () => (await DataStore.entries(themeStore))
|
||||
.map(([name, css]) => getThemeInfo(css, name.toString())),
|
||||
getThemeData: (fileName: string) => DataStore.get(fileName, themeStore),
|
||||
getSystemValues: async () => ({}),
|
||||
},
|
||||
|
@ -66,10 +65,10 @@ window.VencordNative = {
|
|||
},
|
||||
|
||||
quickCss: {
|
||||
get: () => DataStore.get("VencordQuickCss").then(s => s ?? ""),
|
||||
get: async () => await DataStore.get("VencordQuickCss") ?? "",
|
||||
set: async (css: string) => {
|
||||
await DataStore.set("VencordQuickCss", css);
|
||||
cssListeners.forEach(l => l(css));
|
||||
cssListeners.forEach(l => { l(css); });
|
||||
},
|
||||
addChangeListener(cb) {
|
||||
cssListeners.add(cb);
|
||||
|
@ -109,5 +108,5 @@ window.VencordNative = {
|
|||
getSettingsDir: async () => "LocalStorage"
|
||||
},
|
||||
|
||||
pluginHelpers: {} as any,
|
||||
pluginHelpers: {},
|
||||
};
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
import "./patch-worker";
|
||||
|
||||
// @ts-expect-error
|
||||
import * as monaco from "monaco-editor/esm/vs/editor/editor.main.js";
|
||||
declare const monaco: typeof import("monaco-editor");
|
||||
|
||||
declare global {
|
||||
const baseUrl: string;
|
||||
|
|
|
@ -1,126 +1,221 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
// @ts-check
|
||||
|
||||
import stylistic from "@stylistic/eslint-plugin";
|
||||
// @ts-expect-error: No types
|
||||
import pathAlias from "eslint-plugin-path-alias";
|
||||
import header from "eslint-plugin-simple-header";
|
||||
// @ts-expect-error: https://github.com/jsx-eslint/eslint-plugin-react/issues/3776
|
||||
import eslintPluginReact from "eslint-plugin-react";
|
||||
import simpleHeader from "eslint-plugin-simple-header";
|
||||
import simpleImportSort from "eslint-plugin-simple-import-sort";
|
||||
import unusedImports from "eslint-plugin-unused-imports";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
export default tseslint.config(
|
||||
{ ignores: ["dist", "browser", "packages/vencord-types"] },
|
||||
{ ignores: ["browser", "dist", "packages", "src/**/*.?(c|m)js?(x)", "*.*"] },
|
||||
{
|
||||
files: ["src/**/*.{tsx,ts,mts,mjs,js,jsx}", "eslint.config.mjs"],
|
||||
plugins: {
|
||||
"simple-header": header,
|
||||
"@stylistic": stylistic,
|
||||
"@typescript-eslint": tseslint.plugin,
|
||||
"simple-import-sort": simpleImportSort,
|
||||
"unused-imports": unusedImports,
|
||||
"path-alias": pathAlias,
|
||||
},
|
||||
settings: {
|
||||
"import/resolver": {
|
||||
map: [
|
||||
["@webpack", "./src/webpack"],
|
||||
["@webpack/common", "./src/webpack/common"],
|
||||
["@utils", "./src/utils"],
|
||||
["@api", "./src/api"],
|
||||
["@components", "./src/components"]
|
||||
]
|
||||
}
|
||||
},
|
||||
files: ["**/*.?(c|m)[jt]s?(x)"],
|
||||
languageOptions: {
|
||||
parser: tseslint.parser,
|
||||
parserOptions: {
|
||||
project: ["./tsconfig.json"],
|
||||
tsconfigRootDir: import.meta.dirname
|
||||
projectService: true,
|
||||
warnOnUnsupportedTypeScriptVersion: false
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
// @ts-expect-error: https://github.com/eslint-stylistic/eslint-stylistic/issues/398#issuecomment-2178212946
|
||||
"@stylistic": stylistic,
|
||||
"@typescript-eslint": tseslint.plugin,
|
||||
"path-alias": pathAlias,
|
||||
"react": eslintPluginReact,
|
||||
"simple-header": simpleHeader,
|
||||
"simple-import-sort": simpleImportSort,
|
||||
"unused-imports": unusedImports,
|
||||
},
|
||||
settings: {
|
||||
react: { version: "18.2" },
|
||||
},
|
||||
rules: {
|
||||
/*
|
||||
* Since it's only been a month and Vencord has already been stolen
|
||||
* by random skids who rebranded it to "AlphaCord" and erased all license
|
||||
* information
|
||||
*/
|
||||
"simple-header/header": [
|
||||
"error",
|
||||
{
|
||||
"files": ["scripts/header-new.txt", "scripts/header-old.txt"],
|
||||
"templates": { "author": [".*", "Vendicated and contributors"] }
|
||||
}
|
||||
],
|
||||
|
||||
// Style Rules
|
||||
"@stylistic/jsx-quotes": ["error", "prefer-double"],
|
||||
"@stylistic/quotes": ["error", "double", { "avoidEscape": true }],
|
||||
"@stylistic/no-mixed-spaces-and-tabs": "error",
|
||||
// Since it's only been a month and Vencord has already been stolen
|
||||
// by random skids who rebranded it to "AlphaCord" and erased all license
|
||||
// information
|
||||
"simple-header/header": ["error", {
|
||||
files: ["scripts/header-new.txt", "scripts/header-old.txt"],
|
||||
templates: { author: [".*", "Vendicated and contributors"] }
|
||||
}],
|
||||
"@stylistic/array-bracket-spacing": "error",
|
||||
"@stylistic/arrow-parens": ["error", "as-needed"],
|
||||
"@stylistic/eol-last": ["error", "always"],
|
||||
"@stylistic/no-multi-spaces": "error",
|
||||
"@stylistic/arrow-spacing": "error",
|
||||
"@stylistic/block-spacing": "error",
|
||||
"@stylistic/brace-style": ["error", "1tbs", { allowSingleLine: true }],
|
||||
"@stylistic/comma-spacing": "error",
|
||||
"@stylistic/comma-style": "error",
|
||||
"@stylistic/computed-property-spacing": "error",
|
||||
"@stylistic/dot-location": ["error", "property"],
|
||||
"@stylistic/eol-last": "error",
|
||||
"@stylistic/func-call-spacing": "error",
|
||||
"@stylistic/generator-star-spacing": ["error", { before: false, after: true }],
|
||||
"@stylistic/indent": ["error", 4, {
|
||||
SwitchCase: 1,
|
||||
flatTernaryExpressions: true
|
||||
}],
|
||||
"@stylistic/jsx-closing-bracket-location": "error",
|
||||
"@stylistic/jsx-closing-tag-location": "error",
|
||||
"@stylistic/jsx-curly-brace-presence": ["error", { propElementValues: "always" }],
|
||||
"@stylistic/jsx-curly-spacing": ["error", { children: true }],
|
||||
"@stylistic/jsx-equals-spacing": "error",
|
||||
"@stylistic/jsx-first-prop-new-line": ["error", "multiline"],
|
||||
"@stylistic/jsx-quotes": "error",
|
||||
"@stylistic/jsx-self-closing-comp": "error",
|
||||
"@stylistic/jsx-tag-spacing": ["error", { beforeClosing: "never" }],
|
||||
"@stylistic/jsx-wrap-multilines": ["error", {
|
||||
declaration: "parens-new-line",
|
||||
assignment: "parens-new-line",
|
||||
return: "parens-new-line",
|
||||
arrow: "parens-new-line",
|
||||
condition: "parens-new-line",
|
||||
logical: "parens-new-line",
|
||||
propertyValue: "parens-new-line"
|
||||
}],
|
||||
"@stylistic/key-spacing": "error",
|
||||
"@stylistic/keyword-spacing": "error",
|
||||
"@stylistic/linebreak-style": "error",
|
||||
"@stylistic/member-delimiter-style": ["error", { singleline: { requireLast: true } }],
|
||||
"@stylistic/new-parens": "error",
|
||||
"@stylistic/no-extra-semi": "error",
|
||||
"@stylistic/no-floating-decimal": "error",
|
||||
"@stylistic/no-multi-spaces": ["error", { exceptions: { Property: false } }],
|
||||
"@stylistic/no-tabs": "error",
|
||||
"@stylistic/no-trailing-spaces": "error",
|
||||
"@stylistic/no-whitespace-before-property": "error",
|
||||
"@stylistic/semi": ["error", "always"],
|
||||
"@stylistic/semi-style": ["error", "last"],
|
||||
"@stylistic/space-in-parens": ["error", "never"],
|
||||
"@stylistic/block-spacing": ["error", "always"],
|
||||
"@stylistic/object-curly-spacing": ["error", "always"],
|
||||
"@stylistic/spaced-comment": ["error", "always", { "markers": ["!"] }],
|
||||
"@stylistic/no-extra-semi": "error",
|
||||
|
||||
// TS Rules
|
||||
"@stylistic/func-call-spacing": ["error", "never"],
|
||||
|
||||
// ESLint Rules
|
||||
"yoda": "error",
|
||||
"eqeqeq": ["error", "always", { "null": "ignore" }],
|
||||
"prefer-destructuring": ["error", {
|
||||
"VariableDeclarator": { "array": false, "object": true },
|
||||
"AssignmentExpression": { "array": false, "object": false }
|
||||
"@stylistic/padded-blocks": ["error", "never"],
|
||||
"@stylistic/quotes": ["error", "double", { avoidEscape: true }],
|
||||
"@stylistic/rest-spread-spacing": "error",
|
||||
"@stylistic/semi": "error",
|
||||
"@stylistic/semi-spacing": "error",
|
||||
"@stylistic/semi-style": "error",
|
||||
"@stylistic/space-before-blocks": "error",
|
||||
"@stylistic/space-before-function-paren": ["error", { named: "never" }],
|
||||
"@stylistic/space-in-parens": "error",
|
||||
"@stylistic/space-infix-ops": "error",
|
||||
"@stylistic/space-unary-ops": "error",
|
||||
"@stylistic/spaced-comment": ["error", "always", { markers: ["!"] }],
|
||||
"@stylistic/switch-colon-spacing": "error",
|
||||
"@stylistic/template-curly-spacing": "error",
|
||||
"@stylistic/template-tag-spacing": "error",
|
||||
"@stylistic/type-annotation-spacing": "error",
|
||||
"@stylistic/type-generic-spacing": "error",
|
||||
"@stylistic/type-named-tuple-spacing": "error",
|
||||
"@stylistic/yield-star-spacing": "error",
|
||||
"@typescript-eslint/array-type": "error",
|
||||
"@typescript-eslint/await-thenable": "error",
|
||||
"@typescript-eslint/consistent-generic-constructors": "error",
|
||||
"@typescript-eslint/consistent-type-assertions": ["error", {
|
||||
assertionStyle: "as",
|
||||
objectLiteralTypeAssertions: "allow-as-parameter"
|
||||
}],
|
||||
"operator-assignment": ["error", "always"],
|
||||
"no-useless-computed-key": "error",
|
||||
"no-unneeded-ternary": ["error", { "defaultAssignment": false }],
|
||||
"no-invalid-regexp": "error",
|
||||
"no-constant-condition": ["error", { "checkLoops": false }],
|
||||
"no-duplicate-imports": "error",
|
||||
"dot-notation": "error",
|
||||
"no-useless-escape": [
|
||||
"error",
|
||||
{
|
||||
"extra": "i"
|
||||
}
|
||||
],
|
||||
"no-fallthrough": "error",
|
||||
"@typescript-eslint/consistent-type-exports": ["error", {
|
||||
fixMixedExportsWithInlineTypeSpecifier: true
|
||||
}],
|
||||
"@typescript-eslint/consistent-type-imports": ["error", {
|
||||
disallowTypeAnnotations: false,
|
||||
fixStyle: "inline-type-imports"
|
||||
}],
|
||||
"@typescript-eslint/dot-notation": "error",
|
||||
"@typescript-eslint/method-signature-style": "error",
|
||||
"@typescript-eslint/no-confusing-void-expression": "error",
|
||||
"@typescript-eslint/no-duplicate-type-constituents": "error",
|
||||
"@typescript-eslint/no-extra-non-null-assertion": "error",
|
||||
"@typescript-eslint/no-import-type-side-effects": "error",
|
||||
"@typescript-eslint/no-misused-promises": ["error", { checksVoidReturn: false }],
|
||||
"@typescript-eslint/no-non-null-asserted-nullish-coalescing": "error",
|
||||
"@typescript-eslint/no-non-null-asserted-optional-chain": "error",
|
||||
"@typescript-eslint/no-unnecessary-condition": ["error", { allowConstantLoopConditions: true }],
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
||||
"@typescript-eslint/no-unnecessary-type-parameters": "error",
|
||||
"@typescript-eslint/no-unsafe-function-type": "error",
|
||||
"@typescript-eslint/no-unused-expressions": ["error", { enforceForJSX: true }],
|
||||
"@typescript-eslint/no-wrapper-object-types": "error",
|
||||
"@typescript-eslint/non-nullable-type-assertion-style": "error",
|
||||
"@typescript-eslint/prefer-as-const": "error",
|
||||
"@typescript-eslint/prefer-destructuring": "error",
|
||||
"@typescript-eslint/prefer-find": "error",
|
||||
"@typescript-eslint/prefer-function-type": "error",
|
||||
"@typescript-eslint/prefer-includes": "error",
|
||||
"@typescript-eslint/prefer-reduce-type-parameter": "error",
|
||||
"@typescript-eslint/require-await": "error",
|
||||
"@typescript-eslint/return-await": "error",
|
||||
"eqeqeq": ["error", "always", { null: "ignore" }],
|
||||
"for-direction": "error",
|
||||
"no-array-constructor": "error",
|
||||
"no-async-promise-executor": "error",
|
||||
"no-cond-assign": "error",
|
||||
"no-dupe-else-if": "error",
|
||||
"no-duplicate-case": "error",
|
||||
"no-duplicate-imports": "error",
|
||||
"no-eval": ["error", { allowIndirect: true }],
|
||||
"no-extra-boolean-cast": "error",
|
||||
"no-extra-label": "error",
|
||||
"no-fallthrough": "error",
|
||||
"no-invalid-regexp": "error",
|
||||
"no-irregular-whitespace": "error",
|
||||
"no-lone-blocks": "error",
|
||||
"no-lonely-if": "error",
|
||||
"no-loss-of-precision": "error",
|
||||
"no-misleading-character-class": "error",
|
||||
"no-new-wrappers": "error",
|
||||
"no-object-constructor": "error",
|
||||
"no-prototype-builtins": "error",
|
||||
"no-regex-spaces": "error",
|
||||
"no-restricted-globals": ["error", "_", "Diff", "JSX", "React", "ReactDOM"],
|
||||
"no-restricted-imports": ["error", {
|
||||
patterns: [{
|
||||
regex: "^discord-types(/|$)",
|
||||
message: "Use @vencord/discord-types instead."
|
||||
}]
|
||||
}],
|
||||
"no-restricted-syntax": ["error",
|
||||
"SequenceExpression:not(.update):matches(:not(.callee), [expressions.length!=2])",
|
||||
"SequenceExpression:not(.update) > :first-child:not(Literal)",
|
||||
],
|
||||
"no-shadow-restricted-names": "error",
|
||||
"no-undef-init": "error",
|
||||
"no-unexpected-multiline": "error",
|
||||
"no-unsafe-optional-chaining": "error",
|
||||
"no-unneeded-ternary": ["error", { defaultAssignment: false }],
|
||||
"no-unreachable": "error",
|
||||
"no-unreachable-loop": "error",
|
||||
"no-unused-labels": "error",
|
||||
"no-useless-backreference": "error",
|
||||
"use-isnan": "error",
|
||||
"no-useless-catch": "error",
|
||||
"no-useless-computed-key": "error",
|
||||
"no-useless-escape": ["error", { extra: "i" }],
|
||||
"no-useless-rename": "error",
|
||||
"no-void": "error",
|
||||
"operator-assignment": "error",
|
||||
"path-alias/no-relative": "error",
|
||||
"prefer-const": "error",
|
||||
"prefer-numeric-literals": "error",
|
||||
"prefer-object-spread": "error",
|
||||
"prefer-regex-literals": ["error", { disallowRedundantWrapping: true }],
|
||||
"prefer-spread": "error",
|
||||
|
||||
// Plugin Rules
|
||||
"simple-import-sort/imports": "error",
|
||||
"react/forbid-dom-props": ["error", {
|
||||
forbid: ["version", "xlinkActuate", "xlinkArcrole", "xlinkHref", "xlinkRole", "xlinkShow", "xlinkTitle", "xlinkType", "xmlBase", "xmlLang", "xmlns", "xmlnsXlink", "xmlSpace"]
|
||||
}],
|
||||
"react/jsx-fragments": "error",
|
||||
"react/jsx-no-useless-fragment": "error",
|
||||
"simple-import-sort/exports": "error",
|
||||
"simple-import-sort/imports": "error",
|
||||
"unused-imports/no-unused-imports": "error",
|
||||
"path-alias/no-relative": "error"
|
||||
"use-isnan": "error",
|
||||
"yoda": "error",
|
||||
}
|
||||
},
|
||||
// Declarations are not emitted for '.d.ts' files: https://github.com/microsoft/TypeScript/issues/38146
|
||||
{
|
||||
files: ["src/webpack/common/types/**"],
|
||||
rules: {
|
||||
"no-restricted-syntax": ["error", {
|
||||
selector: ":expression:not([declare=true] *, [type=/^TS/] *, ExportAllDeclaration *, ExportNamedDeclaration *, ImportDeclaration *)",
|
||||
message: "This file is intended to contain only types."
|
||||
}],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
106
package.json
106
package.json
|
@ -23,16 +23,16 @@
|
|||
"watch": "pnpm build --watch",
|
||||
"dev": "pnpm watch",
|
||||
"watchWeb": "pnpm buildWeb --watch",
|
||||
"generatePluginJson": "tsx scripts/generatePluginList.ts",
|
||||
"generatePluginJson": "tsx scripts/generatePluginList.mts",
|
||||
"generateTypes": "tspc --emitDeclarationOnly --declaration --outDir packages/vencord-types",
|
||||
"inject": "node scripts/runInstaller.mjs",
|
||||
"uninject": "node scripts/runInstaller.mjs",
|
||||
"lint": "eslint",
|
||||
"lint": "eslint . --ignore-pattern src/userplugins",
|
||||
"lint-styles": "stylelint \"src/**/*.css\" --ignore-pattern src/userplugins",
|
||||
"lint:fix": "pnpm lint --fix",
|
||||
"test": "pnpm buildStandalone && pnpm lint && pnpm lint-styles && pnpm testTsc && pnpm generatePluginJson",
|
||||
"testWeb": "pnpm lint && pnpm buildWeb && pnpm testTsc",
|
||||
"testTsc": "tsc --noEmit"
|
||||
"testTsc": "tsc --noEmit --emitDeclarationOnly false"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sapphi-red/web-noise-suppressor": "0.3.5",
|
||||
|
@ -40,61 +40,91 @@
|
|||
"@vap/shiki": "0.10.5",
|
||||
"fflate": "^0.8.2",
|
||||
"gifenc": "github:mattdesl/gifenc#64842fca317b112a8590f8fef2bf3825da8f6fe3",
|
||||
"monaco-editor": "^0.50.0",
|
||||
"nanoid": "^5.0.7",
|
||||
"virtual-merge": "^1.0.1"
|
||||
"monaco-editor": "^0.51.0",
|
||||
"nanoid": "^5.0.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@stylistic/eslint-plugin": "^2.6.1",
|
||||
"@types/chrome": "^0.0.269",
|
||||
"@types/diff": "^5.2.1",
|
||||
"@types/lodash": "^4.17.7",
|
||||
"@types/node": "^22.0.3",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@stylistic/eslint-plugin": "^2.8.0",
|
||||
"@stylistic/stylelint-config": "^2.0.0",
|
||||
"@stylistic/stylelint-plugin": "^3.0.1",
|
||||
"@types/chrome": "^0.0.271",
|
||||
"@types/diff": "^5.2.2",
|
||||
"@types/html-minifier-terser": "^7.0.2",
|
||||
"@types/lodash": "~4.17.7",
|
||||
"@types/node": "^18.19.50",
|
||||
"@types/react": "~18.2.79",
|
||||
"@types/react-dom": "~18.2.25",
|
||||
"@types/yazl": "^2.4.5",
|
||||
"diff": "^5.2.0",
|
||||
"discord-types": "^1.3.26",
|
||||
"esbuild": "^0.15.18",
|
||||
"eslint": "^9.8.0",
|
||||
"eslint-import-resolver-alias": "^1.1.2",
|
||||
"eslint-plugin-path-alias": "2.1.0",
|
||||
"eslint-plugin-simple-header": "^1.1.1",
|
||||
"@vencord/discord-types": "workspace:^",
|
||||
"diff": "^7.0.0",
|
||||
"discord-types": "latest",
|
||||
"esbuild": "^0.23.1",
|
||||
"eslint": "^9.10.0",
|
||||
"eslint-plugin-path-alias": "^2.1.0",
|
||||
"eslint-plugin-react": "^7.36.1",
|
||||
"eslint-plugin-simple-header": "^1.2.1",
|
||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||
"eslint-plugin-unused-imports": "^4.0.1",
|
||||
"highlight.js": "10.7.3",
|
||||
"eslint-plugin-unused-imports": "^4.1.4",
|
||||
"highlight.js": "11.8.0",
|
||||
"html-minifier-terser": "^7.2.0",
|
||||
"moment": "^2.30.1",
|
||||
"puppeteer-core": "^22.15.0",
|
||||
"moment": "2.22.2",
|
||||
"puppeteer-core": "^23.3.0",
|
||||
"standalone-electron-types": "^1.0.0",
|
||||
"stylelint": "^16.8.1",
|
||||
"stylelint": "^16.9.0",
|
||||
"stylelint-config-standard": "^36.0.1",
|
||||
"ts-patch": "^3.2.1",
|
||||
"ts-pattern": "^5.3.1",
|
||||
"tsx": "^4.16.5",
|
||||
"type-fest": "^4.23.0",
|
||||
"typescript": "^5.5.4",
|
||||
"typescript-eslint": "^8.0.0",
|
||||
"typescript-transform-paths": "^3.4.7",
|
||||
"ts-pattern": "5.0.4",
|
||||
"tsx": "^4.19.1",
|
||||
"type-fest": "^4.26.1",
|
||||
"typescript": "^5.6.2",
|
||||
"typescript-eslint": "^8.5.0",
|
||||
"typescript-transform-paths": "^3.5.1",
|
||||
"zip-local": "^0.3.5"
|
||||
},
|
||||
"packageManager": "pnpm@9.1.0",
|
||||
"packageManager": "pnpm@9.10.0",
|
||||
"pnpm": {
|
||||
"patchedDependencies": {
|
||||
"eslint@9.8.0": "patches/eslint@9.8.0.patch",
|
||||
"eslint-plugin-path-alias@2.1.0": "patches/eslint-plugin-path-alias@2.1.0.patch"
|
||||
"@stylistic/eslint-plugin@2.8.0": "patches/@stylistic__eslint-plugin@2.8.0.patch",
|
||||
"eslint-plugin-path-alias@2.1.0": "patches/eslint-plugin-path-alias@2.1.0.patch",
|
||||
"eslint@9.10.0": "patches/eslint@9.10.0.patch",
|
||||
"standalone-electron-types@1.0.0": "patches/standalone-electron-types@1.0.0.patch",
|
||||
"typescript-transform-paths@3.5.1": "patches/typescript-transform-paths@3.5.1.patch"
|
||||
},
|
||||
"packageExtensions": {
|
||||
"eslint": {
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.5",
|
||||
"@types/json-schema": "^7.0.15"
|
||||
}
|
||||
}
|
||||
},
|
||||
"peerDependencyRules": {
|
||||
"ignoreMissing": [
|
||||
"eslint-plugin-import",
|
||||
"eslint"
|
||||
]
|
||||
"allowedVersions": {
|
||||
"eslint": "9"
|
||||
}
|
||||
},
|
||||
"allowedDeprecatedVersions": {
|
||||
"source-map-resolve": "*",
|
||||
"resolve-url": "*",
|
||||
"source-map-url": "*",
|
||||
"urix": "*"
|
||||
},
|
||||
"overrides": {
|
||||
"array-includes": "npm:@nolyfill/array-includes@^1",
|
||||
"array.prototype.findlast": "npm:@nolyfill/array.prototype.findlast@^1",
|
||||
"array.prototype.flat": "npm:@nolyfill/array.prototype.flat@^1",
|
||||
"array.prototype.flatmap": "npm:@nolyfill/array.prototype.flatmap@^1",
|
||||
"array.prototype.tosorted": "npm:@nolyfill/array.prototype.tosorted@^1",
|
||||
"es-iterator-helpers": "npm:@nolyfill/es-iterator-helpers@^1",
|
||||
"hasown": "npm:@nolyfill/hasown@^1",
|
||||
"is-core-module": "npm:@nolyfill/is-core-module@^1",
|
||||
"isarray": "npm:@nolyfill/isarray@^1",
|
||||
"object.assign": "npm:@nolyfill/object.assign@^1",
|
||||
"object.entries": "npm:@nolyfill/object.entries@^1",
|
||||
"object.fromentries": "npm:@nolyfill/object.fromentries@^1",
|
||||
"object.values": "npm:@nolyfill/object.values@^1",
|
||||
"string.prototype.matchall": "npm:@nolyfill/string.prototype.matchall@^1",
|
||||
"string.prototype.repeat": "npm:@nolyfill/string.prototype.repeat@^1"
|
||||
}
|
||||
},
|
||||
"webExt": {
|
||||
|
|
674
packages/discord-types/LICENSE
Normal file
674
packages/discord-types/LICENSE
Normal file
|
@ -0,0 +1,674 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
1
packages/discord-types/README.md
Normal file
1
packages/discord-types/README.md
Normal file
|
@ -0,0 +1 @@
|
|||
discord-types
|
257
packages/discord-types/eslint.config.mjs
Normal file
257
packages/discord-types/eslint.config.mjs
Normal file
|
@ -0,0 +1,257 @@
|
|||
import stylistic from "@stylistic/eslint-plugin";
|
||||
// @ts-expect-error: No types
|
||||
import checkFile from "eslint-plugin-check-file";
|
||||
import eslintPluginImport from "eslint-plugin-import-x";
|
||||
import simpleHeader from "eslint-plugin-simple-header";
|
||||
import simpleImportSort from "eslint-plugin-simple-import-sort";
|
||||
import eslintPluginUnicorn from "eslint-plugin-unicorn";
|
||||
import unusedImports from "eslint-plugin-unused-imports";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
export default tseslint.config(
|
||||
{
|
||||
files: ["**/*.?(c|m)[jt]s?(x)"],
|
||||
languageOptions: {
|
||||
parser: tseslint.parser,
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
warnOnUnsupportedTypeScriptVersion: false
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
// @ts-expect-error: https://github.com/eslint-stylistic/eslint-stylistic/issues/398#issuecomment-2178212946
|
||||
"@stylistic": stylistic,
|
||||
"@typescript-eslint": tseslint.plugin,
|
||||
"check-file": checkFile,
|
||||
import: eslintPluginImport,
|
||||
"simple-header": simpleHeader,
|
||||
"simple-import-sort": simpleImportSort,
|
||||
unicorn: eslintPluginUnicorn,
|
||||
"unused-imports": unusedImports,
|
||||
},
|
||||
rules: {
|
||||
"@stylistic/array-bracket-newline": ["error", "consistent"],
|
||||
"@stylistic/array-bracket-spacing": "error",
|
||||
"@stylistic/array-element-newline": ["error", "consistent"],
|
||||
"@stylistic/arrow-parens": ["error", "as-needed"],
|
||||
"@stylistic/block-spacing": "error",
|
||||
"@stylistic/brace-style": ["error", "1tbs", { allowSingleLine: true }],
|
||||
"@stylistic/comma-dangle": ["error", "only-multiline"],
|
||||
"@stylistic/comma-spacing": "error",
|
||||
"@stylistic/comma-style": "error",
|
||||
"@stylistic/computed-property-spacing": "error",
|
||||
"@stylistic/dot-location": ["error", "property"],
|
||||
"@stylistic/eol-last": "error",
|
||||
"@stylistic/function-call-argument-newline": ["error", "consistent"],
|
||||
"@stylistic/function-call-spacing": "error",
|
||||
"@stylistic/function-paren-newline": ["error", "consistent"],
|
||||
"@stylistic/indent": ["error", 4, {
|
||||
SwitchCase: 1,
|
||||
flatTernaryExpressions: true
|
||||
}],
|
||||
"@stylistic/key-spacing": "error",
|
||||
"@stylistic/keyword-spacing": "error",
|
||||
"@stylistic/linebreak-style": "error",
|
||||
"@stylistic/member-delimiter-style": ["error", { singleline: { requireLast: true } }],
|
||||
"@stylistic/new-parens": "error",
|
||||
"@stylistic/no-extra-semi": "error",
|
||||
"@stylistic/no-floating-decimal": "error",
|
||||
"@stylistic/no-multi-spaces": ["error", { exceptions: { Property: false } }],
|
||||
"@stylistic/no-multiple-empty-lines": ["error", { max: 1, maxBOF: 0, maxEOF: 0 }],
|
||||
"@stylistic/no-trailing-spaces": "error",
|
||||
"@stylistic/no-whitespace-before-property": "error",
|
||||
"@stylistic/object-curly-newline": "error",
|
||||
"@stylistic/object-curly-spacing": ["error", "always"],
|
||||
"@stylistic/quote-props": ["error", "as-needed"],
|
||||
"@stylistic/quotes": ["error", "double", { avoidEscape: true }],
|
||||
"@stylistic/rest-spread-spacing": "error",
|
||||
"@stylistic/semi": "error",
|
||||
"@stylistic/semi-spacing": "error",
|
||||
"@stylistic/semi-style": "error",
|
||||
"@stylistic/space-before-blocks": "error",
|
||||
"@stylistic/space-before-function-paren": ["error", { named: "never" }],
|
||||
"@stylistic/space-in-parens": "error",
|
||||
"@stylistic/space-infix-ops": "error",
|
||||
"@stylistic/space-unary-ops": "error",
|
||||
"@stylistic/spaced-comment": "error",
|
||||
"@stylistic/switch-colon-spacing": "error",
|
||||
"@stylistic/template-curly-spacing": "error",
|
||||
"@stylistic/template-tag-spacing": "error",
|
||||
"@stylistic/type-annotation-spacing": "error",
|
||||
"@stylistic/type-generic-spacing": "error",
|
||||
"@stylistic/type-named-tuple-spacing": "error",
|
||||
"@typescript-eslint/adjacent-overload-signatures": "error",
|
||||
"@typescript-eslint/array-type": "error",
|
||||
"@typescript-eslint/await-thenable": "error",
|
||||
"@typescript-eslint/ban-ts-comment": "error",
|
||||
"@typescript-eslint/class-literal-property-style": "error",
|
||||
"@typescript-eslint/consistent-generic-constructors": "error",
|
||||
"@typescript-eslint/consistent-type-assertions": ["error", {
|
||||
assertionStyle: "as",
|
||||
objectLiteralTypeAssertions: "allow-as-parameter"
|
||||
}],
|
||||
"@typescript-eslint/consistent-type-definitions": "error",
|
||||
"@typescript-eslint/consistent-type-exports": ["error", { fixMixedExportsWithInlineTypeSpecifier: true }],
|
||||
"@typescript-eslint/consistent-type-imports": ["error", { fixStyle: "inline-type-imports" }],
|
||||
"@typescript-eslint/dot-notation": "error",
|
||||
"@typescript-eslint/method-signature-style": "error",
|
||||
"@typescript-eslint/naming-convention": ["error", {
|
||||
selector: "typeLike",
|
||||
format: ["PascalCase"]
|
||||
}],
|
||||
"@typescript-eslint/no-confusing-void-expression": "error",
|
||||
"@typescript-eslint/no-duplicate-enum-values": "error",
|
||||
"@typescript-eslint/no-duplicate-type-constituents": "error",
|
||||
"@typescript-eslint/no-extra-non-null-assertion": "error",
|
||||
"@typescript-eslint/no-import-type-side-effects": "error",
|
||||
"@typescript-eslint/no-invalid-void-type": "error",
|
||||
"@typescript-eslint/no-misused-new": "error",
|
||||
"@typescript-eslint/no-misused-promises": ["error", { checksVoidReturn: false }],
|
||||
"@typescript-eslint/no-non-null-asserted-nullish-coalescing": "error",
|
||||
"@typescript-eslint/no-non-null-asserted-optional-chain": "error",
|
||||
"@typescript-eslint/no-redundant-type-constituents": "error",
|
||||
"@typescript-eslint/no-require-imports": "error",
|
||||
"@typescript-eslint/no-unnecessary-condition": ["error", { allowConstantLoopConditions: true }],
|
||||
"@typescript-eslint/no-unnecessary-qualifier": "error",
|
||||
"@typescript-eslint/no-unnecessary-type-arguments": "error",
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
||||
"@typescript-eslint/no-unnecessary-type-constraint": "error",
|
||||
"@typescript-eslint/no-unsafe-declaration-merging": "error",
|
||||
"@typescript-eslint/no-unsafe-function-type": "error",
|
||||
"@typescript-eslint/no-unused-expressions": "error",
|
||||
"@typescript-eslint/no-useless-empty-export": "error",
|
||||
"@typescript-eslint/non-nullable-type-assertion-style": "error",
|
||||
"@typescript-eslint/prefer-as-const": "error",
|
||||
"@typescript-eslint/prefer-find": "error",
|
||||
"@typescript-eslint/prefer-function-type": "error",
|
||||
"@typescript-eslint/prefer-includes": "error",
|
||||
"@typescript-eslint/prefer-reduce-type-parameter": "error",
|
||||
"@typescript-eslint/require-await": "error",
|
||||
"@typescript-eslint/return-await": "error",
|
||||
"@typescript-eslint/triple-slash-reference": "error",
|
||||
"@typescript-eslint/unified-signatures": ["error", { ignoreDifferentlyNamedParameters: true }],
|
||||
"check-file/filename-naming-convention": ["error", { "**/*": "+([.0-9A-Za-z])" }],
|
||||
"check-file/folder-naming-convention": ["error", { "**/": "CAMEL_CASE" }],
|
||||
"import/first": "error",
|
||||
// https://github.com/import-js/eslint-plugin-import/issues/2913
|
||||
// "import/newline-after-import": ["error", { considerComments: true }],
|
||||
"import/no-absolute-path": "error",
|
||||
"import/no-duplicates": "error",
|
||||
"import/no-empty-named-blocks": "error",
|
||||
"import/no-extraneous-dependencies": ["error", { includeTypes: true }],
|
||||
"import/no-relative-packages": "error",
|
||||
"import/no-self-import": "error",
|
||||
"import/no-unassigned-import": "error",
|
||||
"import/no-useless-path-segments": "error",
|
||||
"no-useless-computed-key": "error",
|
||||
"simple-import-sort/exports": "error",
|
||||
"simple-import-sort/imports": ["error", { groups: [["^[^.]"]] }],
|
||||
"unicorn/escape-case": "error",
|
||||
"unicorn/no-hex-escape": "error",
|
||||
"unicorn/no-zero-fractions": "error",
|
||||
"unicorn/number-literal-case": "error",
|
||||
"unicorn/prefer-export-from": ["error", { ignoreUsedVariables: true }],
|
||||
"unused-imports/no-unused-imports": "error",
|
||||
"unused-imports/no-unused-vars": ["error", {
|
||||
args: "all",
|
||||
argsIgnorePattern: "^_",
|
||||
destructuredArrayIgnorePattern: "^_",
|
||||
varsIgnorePattern: "^_"
|
||||
}],
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ["**/*"],
|
||||
ignores: ["src/**"],
|
||||
rules: {
|
||||
"@typescript-eslint/no-unnecessary-type-parameters": "error",
|
||||
"simple-import-sort/imports": ["error", {
|
||||
groups: [
|
||||
["^((node:)?(assert(/strict)?|async_hooks|buffer|child_process|cluster|console|constants|crypto|dgram|diagnostics_channel|dns(/promises)?|domain|events|fs(/promises)?|http|http2|https|module|net|os|path(/(posix|win32))?|perf_hooks|process|punycode|querystring|readline(/promises)?|repl|stream(/(consumers|promises|web))?|string_decoder|timers(/promises)?|tls|trace_events|tty|url|util(/types)?|v8|vm|wasi|worker_threads|zlib)|node:test(/reporters)?)$"],
|
||||
["^[^.]"]
|
||||
]
|
||||
}],
|
||||
"unicorn/prefer-node-protocol": "error",
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ["scripts/**", "src/**"],
|
||||
rules: {
|
||||
"simple-header/header": ["error", {
|
||||
text: [
|
||||
"discord-types",
|
||||
"Copyright (C) {year} Vencord project contributors",
|
||||
"SPDX-License-Identifier: GPL-3.0-or-later"
|
||||
],
|
||||
templates: {
|
||||
year: ["\\d+(-\\d+)?(, \\d+(-\\d+)?)*", `${new Date().getFullYear()}`]
|
||||
}
|
||||
}],
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ["src/**"],
|
||||
rules: {
|
||||
"@typescript-eslint/ban-ts-comment": ["error", { "ts-expect-error": true }],
|
||||
"@typescript-eslint/member-ordering": ["error", {
|
||||
default: {
|
||||
memberTypes: [
|
||||
"call-signature",
|
||||
"constructor",
|
||||
["static-accessor", "static-field", "static-get", "static-method", "static-set"],
|
||||
["accessor", "get", "method", "set"],
|
||||
"signature",
|
||||
"field"
|
||||
],
|
||||
order: "alphabetically-case-insensitive"
|
||||
}
|
||||
}],
|
||||
"@typescript-eslint/prefer-enum-initializers": "error",
|
||||
// Disallow .d.ts files so that package consumers can use exported enums
|
||||
"check-file/filename-blocklist": ["error", { "!**/!(*.d).ts": "!(*.d).ts" }],
|
||||
"import/extensions": "error",
|
||||
// Does not work with ESLint 9
|
||||
// "import/no-default-export": "error",
|
||||
"import/no-extraneous-dependencies": ["error", {
|
||||
devDependencies: false,
|
||||
includeTypes: true
|
||||
}],
|
||||
"import/no-unassigned-import": "error",
|
||||
"no-restricted-globals": ["error", "_", "IntlMessageFormat", "JSX", "NodeJS", "React", "SimpleMarkdown"],
|
||||
"no-restricted-syntax": [
|
||||
"error",
|
||||
`:expression:not(${[
|
||||
// Allow ambient classes
|
||||
"[declare=true] *",
|
||||
// Allow enums, interfaces, and type aliases
|
||||
"[type=/^TS/] *",
|
||||
// Allow re-exporting of all named exports
|
||||
"ExportAllDeclaration *",
|
||||
// Allow imports
|
||||
"ImportDeclaration *",
|
||||
].join(", ")})`,
|
||||
// Prefer naming function parameters instead of destructuring them
|
||||
":matches(ArrayPattern, ObjectPattern).params",
|
||||
// Prefer getters and setters
|
||||
"[type=/^(TSAbstract)?AccessorProperty$/]",
|
||||
// Disallow default exports
|
||||
"ExportDefaultDeclaration",
|
||||
// Disallow redundant constructor definitions
|
||||
"ClassDeclaration[superClass=null] MethodDefinition[kind=constructor][value.params.length=0]",
|
||||
// Disallow enums that are const or ambient since package consumers cannot use them
|
||||
"TSEnumDeclaration:matches([const=true], [declare=true])",
|
||||
// Disallow variance annotations
|
||||
"TSTypeParameter:matches([in=true], [out=true])",
|
||||
],
|
||||
"unicorn/numeric-separators-style": ["error", { number: { minimumDigits: 0 } }],
|
||||
}
|
||||
},
|
||||
{
|
||||
// https://github.com/import-js/eslint-plugin-import/issues/2414
|
||||
files: ["src/**"],
|
||||
ignores: ["src/**/index.ts"],
|
||||
rules: {
|
||||
"import/no-unused-modules": ["error", { missingExports: true }],
|
||||
}
|
||||
},
|
||||
);
|
50
packages/discord-types/package.json
Normal file
50
packages/discord-types/package.json
Normal file
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"name": "@vencord/discord-types",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"author": "Vencord",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Vendicated/Vencord.git",
|
||||
"directory": "packages/discord-types"
|
||||
},
|
||||
"main": "./src/index.ts",
|
||||
"files": ["src/**/!(tsconfig?(.*).json)"],
|
||||
"scripts": {
|
||||
"change-reporter": "tsx ./scripts/changeReporter/index.mts",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix",
|
||||
"test": "tsc --noEmit && eslint .",
|
||||
"test-ts": "tsc --noEmit"
|
||||
},
|
||||
"sideEffects": false,
|
||||
"dependencies": {
|
||||
"@types/events": "~3.0.3",
|
||||
"@types/intl-messageformat": "~1.3.1",
|
||||
"@types/lodash": "~4.17.7",
|
||||
"@types/react": "~18.2.79",
|
||||
"dependency-graph": "0.9.0",
|
||||
"moment": "2.22.2",
|
||||
"simple-markdown": "0.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@stylistic/eslint-plugin": "^2.8.0",
|
||||
"@types/node": "^20.16.5",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@typescript-eslint/typescript-estree": "^8.5.0",
|
||||
"eslint": "^9.10.0",
|
||||
"eslint-plugin-check-file": "^2.8.0",
|
||||
"eslint-plugin-import-x": "^4.2.1",
|
||||
"eslint-plugin-simple-header": "^1.2.1",
|
||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||
"eslint-plugin-unicorn": "^55.0.0",
|
||||
"eslint-plugin-unused-imports": "^4.1.4",
|
||||
"puppeteer-core": "^23.3.0",
|
||||
"semver": "^7.6.3",
|
||||
"tsx": "^4.19.1",
|
||||
"type-fest": "^4.26.1",
|
||||
"typescript": "^5.6.2",
|
||||
"typescript-eslint": "^8.5.0"
|
||||
}
|
||||
}
|
774
packages/discord-types/scripts/changeReporter/config.mts
Normal file
774
packages/discord-types/scripts/changeReporter/config.mts
Normal file
|
@ -0,0 +1,774 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { join } from "node:path";
|
||||
|
||||
import type { CR } from "./types.mts";
|
||||
|
||||
export default {
|
||||
rootDir: join(import.meta.dirname, "../../src"),
|
||||
deps: {
|
||||
"../package.json": {
|
||||
"@types/lodash": {
|
||||
find() {
|
||||
return this.Webpack.Common.lodash.VERSION;
|
||||
},
|
||||
overrides: [["4.17.x", "4.17.x"]],
|
||||
},
|
||||
"@types/react": {
|
||||
find() {
|
||||
return this.Webpack.Common.React.version;
|
||||
},
|
||||
overrides: [["18.2.x", "18.2.x"]],
|
||||
},
|
||||
moment: {
|
||||
find() {
|
||||
return this.Webpack.Common.moment.version;
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
src: {
|
||||
"./flux/ActionHandlersGraph.ts": {
|
||||
ActionHandlersGraph: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./flux/ActionLog.ts": {
|
||||
ActionLog: {
|
||||
type: "class",
|
||||
find() {
|
||||
return this.Webpack.Common.FluxDispatcher.actionLogger.log(
|
||||
{ type: Math.random().toString() as any },
|
||||
() => {}
|
||||
).constructor;
|
||||
},
|
||||
},
|
||||
},
|
||||
"./flux/ActionLogger.ts": {
|
||||
ActionLogger: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./flux/BatchedStoreListener.ts": {
|
||||
BatchedStoreListener: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./flux/ChangeListeners.ts": {
|
||||
ChangeListeners: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./flux/Dispatcher.ts": {
|
||||
Dispatcher: {
|
||||
type: "class",
|
||||
},
|
||||
DispatchBand: {
|
||||
type: "enum",
|
||||
// Screaming snake case to pascal case (source enum's keys have no underscores)
|
||||
keyMapper: key => key.replace(/(?<=^.).+/, s => s.toLowerCase()),
|
||||
},
|
||||
SeverityLevel: {
|
||||
type: "enum",
|
||||
},
|
||||
},
|
||||
"./flux/Emitter.ts": {
|
||||
Emitter: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./flux/PersistedStore.ts": {
|
||||
PersistedStore: {
|
||||
type: "class",
|
||||
ignoredAdditions: {
|
||||
// Overrides
|
||||
staticMethodsAndFields: ["destroy"],
|
||||
methods: ["initializeIfNeeded"],
|
||||
},
|
||||
},
|
||||
},
|
||||
"./flux/SnapshotStore.ts": {
|
||||
SnapshotStore: {
|
||||
type: "class",
|
||||
ignoredRemovals: {
|
||||
// Exists on type to enforce that subclasses have `displayName`
|
||||
staticMethodsAndFields: ["displayName"],
|
||||
},
|
||||
},
|
||||
},
|
||||
"./flux/Store.ts": {
|
||||
Store: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./flux/UserAgnosticStore.ts": {
|
||||
UserAgnosticStore: {
|
||||
type: "class",
|
||||
find() {
|
||||
return Object.getPrototypeOf(this.Webpack.Common.Flux.DeviceSettingsStore);
|
||||
},
|
||||
ignoredAdditions: {
|
||||
// Overrides
|
||||
methods: ["initializeFromState", "initializeIfNeeded", "getState"],
|
||||
},
|
||||
},
|
||||
},
|
||||
"./general/channels/ChannelRecord.ts": {
|
||||
ChannelRecordBase: {
|
||||
type: "class",
|
||||
},
|
||||
ChannelRecordProperties: {
|
||||
type: "class",
|
||||
find() {
|
||||
const { findByCode } = this.Webpack;
|
||||
const constructor = findByCode("}isGroupDM(") ?? findByCode("{isGroupDM(");
|
||||
return constructor && Object.getPrototypeOf(constructor);
|
||||
},
|
||||
includeOptional: true,
|
||||
ignoredRemovals: {
|
||||
// Seems to have been removed
|
||||
fields: ["voiceBackgroundDisplay"],
|
||||
},
|
||||
},
|
||||
ForumLayout: {
|
||||
type: "enum",
|
||||
},
|
||||
ThreadSortOrder: {
|
||||
type: "enum",
|
||||
},
|
||||
ChannelFlags: {
|
||||
type: "enum",
|
||||
},
|
||||
ThreadMemberFlags: {
|
||||
type: "enum",
|
||||
},
|
||||
SafetyWarningType: {
|
||||
type: "enum",
|
||||
find() {
|
||||
let key: string;
|
||||
return new Promise<CR.EnumMembers>(res => {
|
||||
this.Webpack.waitFor(exps => {
|
||||
for (const k in exps) {
|
||||
try {
|
||||
if (typeof exps[k]?.STRANGER_DANGER === "number") {
|
||||
key = k;
|
||||
return true;
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
return false;
|
||||
}, exps => { res(exps[key]); });
|
||||
});
|
||||
},
|
||||
},
|
||||
ChannelType: {
|
||||
type: "enum",
|
||||
},
|
||||
VideoQualityMode: {
|
||||
type: "enum",
|
||||
},
|
||||
/*
|
||||
// This seems to have been removed
|
||||
VoiceCallBackgroundType: {
|
||||
type: "enum",
|
||||
},
|
||||
*/
|
||||
},
|
||||
"./general/channels/ForumChannelRecord.ts": {
|
||||
ForumChannelRecord: {
|
||||
type: "class",
|
||||
find() {
|
||||
const castChannelRecord = this.Webpack.findByCode(".GUILD_TEXT]", "return(");
|
||||
return castChannelRecord({ type: /* GUILD_FORUM */ 15 }).constructor;
|
||||
},
|
||||
ignoredRemovals: {
|
||||
fields: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
"./general/channels/GuildTextualChannelRecord.ts": {
|
||||
GuildTextualChannelRecordBase: {
|
||||
type: "class",
|
||||
find() {
|
||||
const castChannelRecord = this.Webpack.findByCode(".GUILD_TEXT]", "return(");
|
||||
return Object.getPrototypeOf(castChannelRecord({ type: /* GUILD_TEXT */ 0 }).constructor);
|
||||
},
|
||||
ignoredRemovals: {
|
||||
fields: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
"./general/channels/GuildVocalChannelRecord.ts": {
|
||||
GuildVocalChannelRecordBase: {
|
||||
type: "class",
|
||||
find() {
|
||||
const castChannelRecord = this.Webpack.findByCode(".GUILD_TEXT]", "return(");
|
||||
return Object.getPrototypeOf(castChannelRecord({ type: /* GUILD_VOICE */ 2 }).constructor);
|
||||
},
|
||||
ignoredRemovals: {
|
||||
fields: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
"./general/channels/PrivateChannelRecord.ts": {
|
||||
PrivateChannelRecordBase: {
|
||||
type: "class",
|
||||
find() {
|
||||
const castChannelRecord = this.Webpack.findByCode(".GUILD_TEXT]", "return(");
|
||||
return Object.getPrototypeOf(castChannelRecord({ type: /* GROUP_DM */ 3 }).constructor);
|
||||
},
|
||||
ignoredAdditions: {
|
||||
// Overrides
|
||||
methods: ["isSystemDM"],
|
||||
},
|
||||
ignoredRemovals: {
|
||||
fields: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
"./general/channels/ThreadChannelRecord.ts": {
|
||||
ThreadChannelRecord: {
|
||||
type: "class",
|
||||
find() {
|
||||
const castChannelRecord = this.Webpack.findByCode(".GUILD_TEXT]", "return(");
|
||||
return castChannelRecord({ type: /* PUBLIC_THREAD */ 11 }).constructor;
|
||||
},
|
||||
ignoredRemovals: {
|
||||
fields: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
"./general/channels/UnknownChannelRecord.ts": {
|
||||
UnknownChannelRecord: {
|
||||
type: "class",
|
||||
find() {
|
||||
return this.Webpack.findByCode(".UNKNOWN", "static fromServer(");
|
||||
},
|
||||
ignoredRemovals: {
|
||||
fields: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
"./general/emojis/Emoji.ts": {
|
||||
UnicodeEmoji: {
|
||||
type: "class",
|
||||
},
|
||||
EmojiType: {
|
||||
type: "enum",
|
||||
},
|
||||
},
|
||||
"./general/emojis/EmojiDisambiguations.ts": {
|
||||
EmojiDisambiguations: {
|
||||
type: "class",
|
||||
find() {
|
||||
return this.Webpack.Common.EmojiStore.getDisambiguatedEmojiContext().constructor;
|
||||
},
|
||||
},
|
||||
},
|
||||
"./general/emojis/GuildEmojis.ts": {
|
||||
GuildEmojis: {
|
||||
type: "class",
|
||||
async find() {
|
||||
const { Common } = this.Webpack;
|
||||
let values = Object.values(Common.EmojiStore.getGuilds());
|
||||
if (values.length <= 0)
|
||||
await new Promise<void>(res => {
|
||||
Common.EmojiStore.addConditionalChangeListener(() => {
|
||||
values = Object.values(Common.EmojiStore.getGuilds());
|
||||
if (values.length > 0) {
|
||||
res();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
Common.InstantInviteActionCreators.acceptInvite({
|
||||
inviteKey: "discord-townhall"
|
||||
}).catch(() => {});
|
||||
});
|
||||
return values[0]?.constructor;
|
||||
},
|
||||
},
|
||||
},
|
||||
"./general/messages/ChannelMessages.ts": {
|
||||
ChannelMessages: {
|
||||
type: "class",
|
||||
},
|
||||
JumpType: {
|
||||
type: "enum",
|
||||
},
|
||||
},
|
||||
"./general/messages/InteractionRecord.ts": {
|
||||
InteractionRecord: {
|
||||
type: "class",
|
||||
},
|
||||
InteractionType: {
|
||||
type: "enum",
|
||||
// From the API documentation
|
||||
ignoredRemovals: [["PING"]],
|
||||
},
|
||||
},
|
||||
"./general/messages/MessageCache.ts": {
|
||||
MessageCache: {
|
||||
type: "class",
|
||||
find() {
|
||||
return this.Webpack.Common.MessageStore.getMessages("")._after.constructor;
|
||||
},
|
||||
},
|
||||
},
|
||||
"./general/messages/MessageRecord.ts": {
|
||||
MessageRecord: {
|
||||
type: "class",
|
||||
},
|
||||
ActivityActionType: {
|
||||
type: "enum",
|
||||
// From the API documentation
|
||||
ignoredRemovals: [["SPECTATE"]],
|
||||
},
|
||||
MessageReferenceType: {
|
||||
type: "enum",
|
||||
},
|
||||
PollLayoutType: {
|
||||
type: "enum",
|
||||
},
|
||||
PurchaseNotificationType: {
|
||||
type: "enum",
|
||||
},
|
||||
ReactionType: {
|
||||
type: "enum",
|
||||
},
|
||||
MessageState: {
|
||||
type: "enum",
|
||||
},
|
||||
},
|
||||
"./general/messages/MessageSnapshotRecord.ts": {
|
||||
MessageSnapshotRecord: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./general/messages/MinimalMessageRecord.ts": {
|
||||
MinimalMessageRecord: {
|
||||
type: "class",
|
||||
},
|
||||
MessageAttachmentFlags: {
|
||||
type: "enum",
|
||||
},
|
||||
CodedLinkType: {
|
||||
type: "enum",
|
||||
},
|
||||
MessageButtonComponentStyle: {
|
||||
type: "enum",
|
||||
},
|
||||
MessageSelectComponentOptionType: {
|
||||
type: "enum",
|
||||
},
|
||||
MessageSelectComponentDefaultValueType: {
|
||||
type: "enum",
|
||||
find() {
|
||||
let key: string;
|
||||
return new Promise<CR.EnumMembers>(res => {
|
||||
this.Webpack.waitFor(exps => {
|
||||
for (const k in exps) {
|
||||
try {
|
||||
if (exps[k]?.ROLE === "role") {
|
||||
key = k;
|
||||
return true;
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
return false;
|
||||
}, exps => { res(exps[key]); });
|
||||
});
|
||||
},
|
||||
},
|
||||
MessageTextInputComponentStyle: {
|
||||
type: "enum",
|
||||
},
|
||||
ContentScanFlags: {
|
||||
type: "enum",
|
||||
},
|
||||
SeparatorSpacingSize: {
|
||||
type: "enum",
|
||||
},
|
||||
MessageComponentType: {
|
||||
type: "enum",
|
||||
},
|
||||
MessageEmbedFlags: {
|
||||
type: "enum",
|
||||
},
|
||||
MessageEmbedType: {
|
||||
type: "enum",
|
||||
},
|
||||
MessageFlags: {
|
||||
type: "enum",
|
||||
},
|
||||
StickerFormat: {
|
||||
type: "enum",
|
||||
},
|
||||
MetaStickerType: {
|
||||
type: "enum"
|
||||
},
|
||||
MessageType: {
|
||||
type: "enum",
|
||||
},
|
||||
},
|
||||
"./general/Activity.ts": {
|
||||
ActivityFlags: {
|
||||
type: "enum",
|
||||
},
|
||||
ActivityGamePlatform: {
|
||||
type: "enum",
|
||||
},
|
||||
ActivityPlatform: {
|
||||
type: "enum",
|
||||
},
|
||||
ActivityType: {
|
||||
type: "enum",
|
||||
},
|
||||
},
|
||||
"./general/ApplicationCommand.ts": {
|
||||
InteractionContextType: {
|
||||
type: "enum",
|
||||
},
|
||||
ApplicationCommandType: {
|
||||
type: "enum",
|
||||
},
|
||||
ApplicationCommandOptionType: {
|
||||
type: "enum",
|
||||
},
|
||||
},
|
||||
"./general/ApplicationRecord.ts": {
|
||||
ApplicationRecord: {
|
||||
type: "class",
|
||||
},
|
||||
EmbeddedActivitySupportedPlatform: {
|
||||
type: "enum",
|
||||
},
|
||||
EmbeddedActivityLabelType: {
|
||||
type: "enum",
|
||||
},
|
||||
OrientationLockState: {
|
||||
type: "enum",
|
||||
},
|
||||
ApplicationIntegrationType: {
|
||||
type: "enum",
|
||||
},
|
||||
OAuth2Scope: {
|
||||
type: "enum",
|
||||
},
|
||||
ApplicationFlags: {
|
||||
type: "enum",
|
||||
},
|
||||
ApplicationOverlayMethodFlags: {
|
||||
type: "enum",
|
||||
},
|
||||
ApplicationType: {
|
||||
type: "enum",
|
||||
},
|
||||
},
|
||||
"./general/Clan.ts": {
|
||||
ClanBadgeKind: {
|
||||
type: "enum",
|
||||
},
|
||||
ClanBannerKind: {
|
||||
type: "enum",
|
||||
},
|
||||
ClanPlaystyle: {
|
||||
type: "enum",
|
||||
},
|
||||
},
|
||||
"./general/CompanyRecord.ts": {
|
||||
CompanyRecord: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./general/DisplayProfile.ts": {
|
||||
DisplayProfile: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./general/Draft.ts": {
|
||||
DraftType: {
|
||||
type: "enum",
|
||||
// Screaming snake case to pascal case
|
||||
keyMapper: key => key.replaceAll(
|
||||
/(?:^|_)(.)([^_]*)/g,
|
||||
(_, first: string, rest: string) => first.toUpperCase() + rest.toLowerCase()
|
||||
),
|
||||
},
|
||||
},
|
||||
"./general/Frecency.ts": {
|
||||
Frecency: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./general/GuildMember.ts": {
|
||||
GuildMemberFlags: {
|
||||
type: "enum",
|
||||
},
|
||||
},
|
||||
"./general/GuildRecord.ts": {
|
||||
GuildRecord: {
|
||||
type: "class",
|
||||
ignoredAdditions: {
|
||||
// Overrides
|
||||
methods: ["merge", "toString"],
|
||||
},
|
||||
},
|
||||
UserNotificationSetting: {
|
||||
type: "enum",
|
||||
},
|
||||
GuildExplicitContentFilterType: {
|
||||
type: "enum",
|
||||
},
|
||||
GuildFeature: {
|
||||
type: "enum",
|
||||
},
|
||||
/*
|
||||
// Not exported; cannot be found
|
||||
GuildHubType: {
|
||||
type: "enum",
|
||||
},
|
||||
*/
|
||||
MFALevel: {
|
||||
type: "enum",
|
||||
},
|
||||
GuildNSFWContentLevel: {
|
||||
type: "enum",
|
||||
},
|
||||
BoostedGuildTier: {
|
||||
type: "enum",
|
||||
},
|
||||
SystemChannelFlags: {
|
||||
type: "enum",
|
||||
},
|
||||
VerificationLevel: {
|
||||
type: "enum",
|
||||
},
|
||||
},
|
||||
"./general/Permissions.ts": {
|
||||
/*
|
||||
// bigint enums are not yet possible: https://github.com/microsoft/TypeScript/issues/37783
|
||||
Permissions: {
|
||||
type: "enum",
|
||||
},
|
||||
*/
|
||||
PermissionOverwriteType: {
|
||||
type: "enum",
|
||||
},
|
||||
},
|
||||
"./general/ReadState.ts": {
|
||||
ReadState: {
|
||||
type: "class",
|
||||
async find() {
|
||||
const { Common } = this.Webpack;
|
||||
let me = Common.UserStore.getCurrentUser();
|
||||
if (!me)
|
||||
await new Promise<void>(res => {
|
||||
Common.UserStore.addConditionalChangeListener(() => {
|
||||
me = Common.UserStore.getCurrentUser();
|
||||
if (me) {
|
||||
res();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
return Common.ReadStateStore.getNotifCenterReadState(me!.id)?.constructor;
|
||||
},
|
||||
},
|
||||
ChannelNotificationSettingsFlags: {
|
||||
type: "enum",
|
||||
},
|
||||
/*
|
||||
// Not exported; cannot be found
|
||||
ReadStateFlags: {
|
||||
type: "enum",
|
||||
},
|
||||
*/
|
||||
ReadStateType: {
|
||||
type: "enum",
|
||||
},
|
||||
},
|
||||
"./general/Record.ts": {
|
||||
RecordBase: {
|
||||
type: "class",
|
||||
ignoredRemovals: {
|
||||
// Exists on type to enforce that subclasses have a valid constructor
|
||||
constructorDefinition: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
"./general/Role.ts": {
|
||||
RoleFlags: {
|
||||
type: "enum",
|
||||
},
|
||||
},
|
||||
"./general/UserProfile.ts": {
|
||||
PlatformType: {
|
||||
type: "enum",
|
||||
},
|
||||
},
|
||||
"./general/UserRecord.ts": {
|
||||
UserRecord: {
|
||||
type: "class",
|
||||
ignoredAdditions: {
|
||||
// Overrides
|
||||
methods: ["toString"],
|
||||
},
|
||||
},
|
||||
UserFlags: {
|
||||
type: "enum",
|
||||
// From the API documentation
|
||||
ignoredRemovals: [["TEAM_PSEUDO_USER"]],
|
||||
},
|
||||
PremiumType: {
|
||||
type: "enum",
|
||||
},
|
||||
},
|
||||
"./i18n/FormattedMessage.ts": {
|
||||
FormattedMessage: {
|
||||
type: "class",
|
||||
},
|
||||
ASTNodeType: {
|
||||
type: "enum",
|
||||
// Undocumented
|
||||
ignoredRemovals: [["HOOK"]],
|
||||
},
|
||||
},
|
||||
"./i18n/I18N.ts": {
|
||||
I18N: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./i18n/Provider.ts": {
|
||||
Provider: {
|
||||
type: "class",
|
||||
find() {
|
||||
const { constructor } = this.Webpack.Common.i18n._provider;
|
||||
return [Object.getPrototypeOf(constructor), constructor];
|
||||
},
|
||||
},
|
||||
},
|
||||
"./stores/ApplicationStore.ts": {
|
||||
ApplicationStore: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./stores/ChannelStore.ts": {
|
||||
ChannelStore: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./stores/DraftStore.ts": {
|
||||
DraftStore: {
|
||||
type: "class",
|
||||
ignoredAdditions: {
|
||||
// Overrides
|
||||
staticMethodsAndFields: ["migrations"],
|
||||
},
|
||||
},
|
||||
},
|
||||
"./stores/EmojiStore.ts": {
|
||||
EmojiStore: {
|
||||
type: "class",
|
||||
ignoredAdditions: {
|
||||
// Overrides
|
||||
staticMethodsAndFields: ["migrations"],
|
||||
},
|
||||
},
|
||||
EmojiIntention: {
|
||||
type: "enum",
|
||||
},
|
||||
},
|
||||
"./stores/GuildChannelStore.ts": {
|
||||
GuildChannelStore: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./stores/GuildMemberStore.ts": {
|
||||
GuildMemberStore: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./stores/GuildStore.ts": {
|
||||
GuildStore: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./stores/MessageStore.ts": {
|
||||
MessageStore: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./stores/PermissionStore.ts": {
|
||||
PermissionStore: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./stores/PresenceStore.ts": {
|
||||
PresenceStore: {
|
||||
type: "class",
|
||||
},
|
||||
ClientType: {
|
||||
type: "enum",
|
||||
// Undocumented
|
||||
ignoredRemovals: [["EMBEDDED"]],
|
||||
},
|
||||
StatusType: {
|
||||
type: "enum",
|
||||
},
|
||||
},
|
||||
"./stores/ReadStateStore.ts": {
|
||||
ReadStateStore: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./stores/RelationshipStore.ts": {
|
||||
RelationshipStore: {
|
||||
type: "class",
|
||||
},
|
||||
RelationshipType: {
|
||||
type: "enum",
|
||||
},
|
||||
},
|
||||
"./stores/SelectedChannelStore.ts": {
|
||||
SelectedChannelStore: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./stores/SelectedGuildStore.ts": {
|
||||
SelectedGuildStore: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./stores/ThemeStore.ts": {
|
||||
ThemeStore: {
|
||||
type: "class",
|
||||
ignoredAdditions: {
|
||||
// Overrides
|
||||
staticMethodsAndFields: ["migrations"],
|
||||
},
|
||||
},
|
||||
Theme: {
|
||||
type: "enum",
|
||||
},
|
||||
},
|
||||
"./stores/UserProfileStore.ts": {
|
||||
UserProfileStore: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./stores/UserStore.ts": {
|
||||
UserStore: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
"./stores/WindowStore.ts": {
|
||||
WindowStore: {
|
||||
type: "class",
|
||||
},
|
||||
},
|
||||
},
|
||||
} satisfies CR.ReporterConfig;
|
279
packages/discord-types/scripts/changeReporter/finds/classes.mts
Normal file
279
packages/discord-types/scripts/changeReporter/finds/classes.mts
Normal file
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import type * as Vencord from "../../../../../src/Vencord.ts";
|
||||
import type { CR } from "../types.mts";
|
||||
|
||||
export function autoFindStore(this: typeof Vencord, source: CR.ClassMembers, name: string) {
|
||||
const persistKeyRE = new RegExp(`^${name}(?:V\\d+)?$`);
|
||||
|
||||
const store: { constructor: CR.Class; } | undefined = this.Webpack.find(exp => {
|
||||
// Find stores from exported instances
|
||||
const { constructor } = exp;
|
||||
return typeof constructor === "function" && (
|
||||
constructor.displayName === name
|
||||
|| persistKeyRE.test(constructor.persistKey)
|
||||
);
|
||||
});
|
||||
|
||||
if (store)
|
||||
return getClassChanges(source, [store.constructor]);
|
||||
}
|
||||
|
||||
export function autoFindClass(this: typeof Vencord, source: CR.ClassMembers) {
|
||||
let bestMatch: CR.ClassChanges | undefined;
|
||||
let lowestChangedCount = Infinity;
|
||||
|
||||
const checked = new WeakSet<CR.Class>();
|
||||
this.Webpack.find(exps => {
|
||||
for (const name in exps) {
|
||||
let constructor: CR.Class;
|
||||
// Some getters throw errors
|
||||
try {
|
||||
// Find classes from exported constructors
|
||||
if (isValidClass(exps[name]))
|
||||
constructor = exps[name];
|
||||
// Find classes from exported instances
|
||||
else if (isValidClass(exps[name]?.constructor))
|
||||
({ constructor } = exps[name]);
|
||||
else
|
||||
continue;
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!checked.has(constructor)) {
|
||||
checked.add(constructor);
|
||||
|
||||
const changes = getClassChanges(source, [constructor]);
|
||||
const { changedCount } = changes;
|
||||
if (changedCount < lowestChangedCount) {
|
||||
lowestChangedCount = changedCount;
|
||||
bestMatch = changes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}, { isIndirect: true });
|
||||
|
||||
return bestMatch;
|
||||
}
|
||||
|
||||
export function isValidClass(value: unknown): value is CR.Class {
|
||||
if (typeof value !== "function")
|
||||
return false;
|
||||
const { prototype } = value;
|
||||
return typeof prototype === "object" && prototype !== null;
|
||||
}
|
||||
|
||||
export function getClassChanges(
|
||||
source: CR.ClassMembers,
|
||||
constructors: readonly [CR.Class, ...CR.Class[]] | readonly [...CR.Class[], CR.Class]
|
||||
): CR.ClassChanges {
|
||||
let hasConstructorDefinition = false;
|
||||
const constructorDescriptors = new Map<PropertyKey, PropertyDescriptor>();
|
||||
const prototypeDescriptors = new Map<PropertyKey, PropertyDescriptor>();
|
||||
const matchedFields = new Set<string>();
|
||||
|
||||
// Ignore constructor definitions without parameters
|
||||
const constructorRE = /[{}]constructor\([^)]/;
|
||||
const fieldRE = /(?<=[{}]constructor\(.+?{.+\(this,")[^"]+(?=",)/g;
|
||||
for (const constructor of constructors) {
|
||||
const constructorString = constructor.toString();
|
||||
|
||||
if (constructorRE.test(constructorString))
|
||||
hasConstructorDefinition = true;
|
||||
|
||||
const constDescriptors = Object.getOwnPropertyDescriptors(constructor);
|
||||
for (const key of Object.getOwnPropertyNames(constructor))
|
||||
constructorDescriptors.set(key, constDescriptors[key]!);
|
||||
for (const key of Object.getOwnPropertySymbols(constructor))
|
||||
constructorDescriptors.set(key, constDescriptors[key]!);
|
||||
|
||||
const { prototype } = constructor;
|
||||
const protoDescriptors = Object.getOwnPropertyDescriptors(prototype);
|
||||
for (const key of Object.getOwnPropertyNames(prototype))
|
||||
prototypeDescriptors.set(key, protoDescriptors[key]!);
|
||||
for (const key of Object.getOwnPropertySymbols(prototype))
|
||||
prototypeDescriptors.set(key, protoDescriptors[key]!);
|
||||
|
||||
for (const [field] of constructorString.matchAll(fieldRE))
|
||||
matchedFields.add(field);
|
||||
}
|
||||
|
||||
const additions: CR.ClassMembers = {
|
||||
constructorDefinition: false,
|
||||
staticMethodsAndFields: [],
|
||||
staticGetters: [],
|
||||
staticSetters: [],
|
||||
methods: [],
|
||||
getters: [],
|
||||
setters: [],
|
||||
fields: []
|
||||
};
|
||||
let unchangedCount = 0;
|
||||
let changedCount = 0;
|
||||
|
||||
// Constructor definition with parameters removal
|
||||
let constructorDefinition = false;
|
||||
|
||||
if (hasConstructorDefinition) {
|
||||
if (source.constructorDefinition) {
|
||||
unchangedCount++;
|
||||
} else {
|
||||
additions.constructorDefinition = true;
|
||||
changedCount++;
|
||||
}
|
||||
} else if (source.constructorDefinition) {
|
||||
constructorDefinition = true;
|
||||
changedCount++;
|
||||
} else {
|
||||
unchangedCount++;
|
||||
}
|
||||
|
||||
// Static member removals
|
||||
const staticMethodsAndFields = new Set(source.staticMethodsAndFields);
|
||||
const staticGetters = new Set(source.staticGetters);
|
||||
const staticSetters = new Set(source.staticSetters);
|
||||
|
||||
const ignoredConstructorKeys = new Set<PropertyKey>(["length", "name", "prototype"]);
|
||||
for (const [rawKey, descriptor] of constructorDescriptors) {
|
||||
if (ignoredConstructorKeys.has(rawKey)) continue;
|
||||
|
||||
const key = rawKey.toString();
|
||||
|
||||
if (descriptor.get) {
|
||||
if (staticGetters.has(key)) {
|
||||
staticGetters.delete(key);
|
||||
unchangedCount++;
|
||||
} else {
|
||||
additions.staticGetters.push(key);
|
||||
changedCount++;
|
||||
}
|
||||
|
||||
if (descriptor.set) {
|
||||
if (staticSetters.has(key)) {
|
||||
staticSetters.delete(key);
|
||||
unchangedCount++;
|
||||
} else {
|
||||
additions.staticSetters.push(key);
|
||||
changedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (descriptor.set) {
|
||||
if (staticSetters.has(key)) {
|
||||
staticSetters.delete(key);
|
||||
unchangedCount++;
|
||||
} else {
|
||||
additions.staticSetters.push(key);
|
||||
changedCount++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (staticMethodsAndFields.has(key)) {
|
||||
staticMethodsAndFields.delete(key);
|
||||
unchangedCount++;
|
||||
} else {
|
||||
additions.staticMethodsAndFields.push(key);
|
||||
changedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
changedCount += staticMethodsAndFields.size + staticGetters.size + staticSetters.size;
|
||||
|
||||
// Instance method and getter/setter removals
|
||||
const methods = new Set(source.methods);
|
||||
const getters = new Set(source.getters);
|
||||
const setters = new Set(source.setters);
|
||||
|
||||
const ignoredPrototypeKeys = new Set<PropertyKey>(["constructor"]);
|
||||
for (const [rawKey, descriptor] of prototypeDescriptors) {
|
||||
if (ignoredPrototypeKeys.has(rawKey)) continue;
|
||||
|
||||
const key = rawKey.toString();
|
||||
|
||||
if (descriptor.get) {
|
||||
if (getters.has(key)) {
|
||||
getters.delete(key);
|
||||
unchangedCount++;
|
||||
} else {
|
||||
additions.getters.push(key);
|
||||
changedCount++;
|
||||
}
|
||||
|
||||
if (descriptor.set) {
|
||||
if (setters.has(key)) {
|
||||
setters.delete(key);
|
||||
unchangedCount++;
|
||||
} else {
|
||||
additions.setters.push(key);
|
||||
changedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (descriptor.set) {
|
||||
if (setters.has(key)) {
|
||||
setters.delete(key);
|
||||
unchangedCount++;
|
||||
} else {
|
||||
additions.setters.push(key);
|
||||
changedCount++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (methods.has(key)) {
|
||||
methods.delete(key);
|
||||
unchangedCount++;
|
||||
} else {
|
||||
additions.methods.push(key);
|
||||
changedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
changedCount += methods.size + getters.size + setters.size;
|
||||
|
||||
// Field removals
|
||||
const fields = new Set(source.fields);
|
||||
|
||||
for (const field of matchedFields) {
|
||||
if (fields.has(field)) {
|
||||
fields.delete(field);
|
||||
unchangedCount++;
|
||||
} else {
|
||||
additions.fields.push(field);
|
||||
changedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
changedCount += fields.size;
|
||||
|
||||
return {
|
||||
additions,
|
||||
removals: {
|
||||
constructorDefinition,
|
||||
staticMethodsAndFields: [...staticMethodsAndFields],
|
||||
staticGetters: [...staticGetters],
|
||||
staticSetters: [...staticSetters],
|
||||
methods: [...methods],
|
||||
getters: [...getters],
|
||||
setters: [...setters],
|
||||
fields: [...fields]
|
||||
},
|
||||
unchangedCount,
|
||||
changedCount
|
||||
};
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import type * as Vencord from "../../../../../src/Vencord.ts";
|
||||
import type { CR } from "../types.mts";
|
||||
|
||||
export function autoFindEnum(this: typeof Vencord, source: CR.EnumSource) {
|
||||
let bestMatch: CR.EnumChanges | undefined;
|
||||
let lowestChangedCount = Infinity;
|
||||
|
||||
const checked = new WeakSet();
|
||||
this.Webpack.find(exps => {
|
||||
for (const name in exps) {
|
||||
let exp: unknown;
|
||||
// Some getters throw errors
|
||||
try {
|
||||
exp = exps[name];
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isValidEnum(exp) && !checked.has(exp)) {
|
||||
checked.add(exp);
|
||||
|
||||
const changes = getEnumChanges(source, exp);
|
||||
const { changedCount } = changes;
|
||||
if (
|
||||
changedCount < lowestChangedCount
|
||||
// If changedCount is the same as lowestChangedCount, keep the match with the least removals.
|
||||
|| changedCount === lowestChangedCount
|
||||
&& bestMatch
|
||||
&& Object.keys(changes.removals).length < Object.keys(bestMatch.removals).length
|
||||
) {
|
||||
lowestChangedCount = changedCount;
|
||||
bestMatch = changes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}, { isIndirect: true });
|
||||
|
||||
return bestMatch;
|
||||
}
|
||||
|
||||
export function isValidEnum(value: unknown): value is CR.EnumMembers {
|
||||
return typeof value === "object"
|
||||
&& value !== null
|
||||
&& !Array.isArray(value);
|
||||
}
|
||||
|
||||
export function getEnumChanges(source: CR.EnumSource, obj: CR.EnumMembers): CR.EnumChanges {
|
||||
const additions: CR.EnumMembers = {};
|
||||
const removals: CR.EnumMembers = { ...source };
|
||||
let unchangedCount = 0;
|
||||
let changedCount = 0;
|
||||
|
||||
for (const key in obj) {
|
||||
// Ignore numeric enum reverse mapping
|
||||
if (parseFloat(key) === Number(key)) continue;
|
||||
|
||||
// Some getters throw errors
|
||||
try {
|
||||
const value = obj[key]!;
|
||||
if (key in source && value === source[key]) {
|
||||
delete removals[key];
|
||||
unchangedCount++;
|
||||
} else {
|
||||
additions[key] = value;
|
||||
changedCount++;
|
||||
}
|
||||
} catch {
|
||||
changedCount = Infinity;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
changedCount += Object.keys(removals).length;
|
||||
|
||||
return {
|
||||
additions,
|
||||
removals,
|
||||
unchangedCount,
|
||||
changedCount
|
||||
};
|
||||
}
|
83
packages/discord-types/scripts/changeReporter/index.mts
Normal file
83
packages/discord-types/scripts/changeReporter/index.mts
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import process from "node:process";
|
||||
|
||||
import puppeteer from "puppeteer-core";
|
||||
|
||||
import { assertEnvValidity } from "../utils.mjs";
|
||||
import config from "./config.mjs";
|
||||
import { autoFindClass, autoFindStore, getClassChanges, isValidClass } from "./finds/classes.mjs";
|
||||
import { autoFindEnum, getEnumChanges, isValidEnum } from "./finds/enums.mjs";
|
||||
import { logSummary } from "./logging/summaries.mjs";
|
||||
import { postError, postReport } from "./logging/webhooks.mjs";
|
||||
import { getChangeReport } from "./reports/getChangeReport.mjs";
|
||||
|
||||
process.on("uncaughtExceptionMonitor", error => {
|
||||
const { DISCORD_WEBHOOK, CHANNEL } = process.env;
|
||||
postError(error, DISCORD_WEBHOOK, CHANNEL);
|
||||
});
|
||||
|
||||
assertEnvValidity(process.env, {
|
||||
CHANNEL: ["stable", "ptb", "canary"],
|
||||
CHROMIUM_BIN: true,
|
||||
CHROMIUM_VERSION: /^\d+(?:\.|$)/,
|
||||
DISCORD_TOKEN: true,
|
||||
DISCORD_WEBHOOK: false,
|
||||
VENCORD_DIST: true,
|
||||
});
|
||||
|
||||
const { CHANNEL, CHROMIUM_BIN, CHROMIUM_VERSION, DISCORD_TOKEN, DISCORD_WEBHOOK, VENCORD_DIST } = process.env;
|
||||
const CWD = process.cwd();
|
||||
|
||||
const browser = await puppeteer.launch({
|
||||
executablePath: CHROMIUM_BIN,
|
||||
headless: true,
|
||||
args: ["--no-sandbox"]
|
||||
});
|
||||
|
||||
const page = await browser.newPage();
|
||||
await page.setUserAgent(`Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${CHROMIUM_VERSION.split(".", 1)[0]}.0.0.0 Safari/537.36`);
|
||||
await page.setBypassCSP(true);
|
||||
|
||||
await page.evaluateOnNewDocument(`(() => {
|
||||
"use strict";
|
||||
if (/(?:^|\\.)discord\\.com$/.test(location.hostname)) {
|
||||
${readFileSync(join(CWD, VENCORD_DIST), "utf-8")};
|
||||
window.Vencord = Vencord;
|
||||
window.CHANGE_REPORTER_LOGGED_IN = new Promise(res => {
|
||||
Vencord.Webpack.waitFor("loginToken", async exps => {
|
||||
await exps.loginToken(${JSON.stringify(DISCORD_TOKEN)});
|
||||
res();
|
||||
});
|
||||
});
|
||||
}
|
||||
})();
|
||||
`);
|
||||
|
||||
await page.goto(`https://${CHANNEL === "stable" ? "" : CHANNEL + "."}discord.com/login`);
|
||||
await page.evaluate(`(async () => {
|
||||
"use strict";
|
||||
await CHANGE_REPORTER_LOGGED_IN;
|
||||
window.autoFindStore = (${autoFindStore}).bind(Vencord);
|
||||
window.autoFindClass = (${autoFindClass}).bind(Vencord);
|
||||
window.isValidClass = ${isValidClass};
|
||||
window.getClassChanges = ${getClassChanges};
|
||||
window.autoFindEnum = (${autoFindEnum}).bind(Vencord);
|
||||
window.isValidEnum = ${isValidEnum};
|
||||
window.getEnumChanges = ${getEnumChanges};
|
||||
})();
|
||||
`);
|
||||
|
||||
const report = await getChangeReport(page, config);
|
||||
browser.close();
|
||||
|
||||
logSummary(report, CHANNEL);
|
||||
|
||||
if (DISCORD_WEBHOOK)
|
||||
postReport(report, DISCORD_WEBHOOK, CHANNEL);
|
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import console from "node:console";
|
||||
import { writeFile } from "node:fs/promises";
|
||||
import process from "node:process";
|
||||
|
||||
import type { CR } from "../types.mts";
|
||||
import { capitalize, codeBlock, formatChannel, formatEnumEntryList, formatKeyList, formatWarnList } from "./utils.mjs";
|
||||
|
||||
export function logSummary(report: CR.ChangeReport, channel?: string) {
|
||||
const { deps, src } = report;
|
||||
|
||||
let summary = `# Change Report (${formatChannel(channel)})\n`;
|
||||
|
||||
let sections = "";
|
||||
|
||||
if (deps.length > 0) {
|
||||
sections += `## ${deps.length} file${deps.length === 1 ? "" : "s"} with watched dependencies:\n`;
|
||||
|
||||
let fileToLogCount = 0;
|
||||
let section = "";
|
||||
|
||||
for (const report of deps) {
|
||||
const { fileName, fileError, fileWarns, passed, warned, failed, errored } = report;
|
||||
|
||||
const toLogCount = warned.length + failed.length + errored.length;
|
||||
if (
|
||||
toLogCount <= 0
|
||||
&& fileError === undefined
|
||||
&& fileWarns.length <= 0
|
||||
) continue;
|
||||
fileToLogCount++;
|
||||
|
||||
const count = passed.length + toLogCount;
|
||||
section += `### \`${fileName}\`:\n`
|
||||
+ `${fileWarns.length} file-level warning${fileWarns.length === 1 ? "" : "s"}`
|
||||
+ (fileWarns.length > 0 ? ": \n" + formatWarnList(fileWarns) : ". \n")
|
||||
+ `${count} watched dependenc${count === 1 ? "y" : "ies"}: \n`;
|
||||
|
||||
if (fileError === undefined) {
|
||||
section += `* ${passed.length} passed without warnings.\n`;
|
||||
|
||||
section += `* ${warned.length} passed with warnings`;
|
||||
if (warned.length > 0) {
|
||||
section += ":\n";
|
||||
for (const { name, warns } of warned)
|
||||
section += ` * The report for \`${name}\` has ${warns.length} warning${warns.length === 1 ? "" : "s"}:\n`
|
||||
+ formatWarnList(warns, 1);
|
||||
} else
|
||||
section += ".\n";
|
||||
|
||||
section += `* ${failed.length} failed`;
|
||||
if (failed.length > 0) {
|
||||
section += ":\n";
|
||||
for (const { name, packageVersionRange, discordVersion, expectedVersionRange, warns } of failed)
|
||||
section += ` * \`${name}\`: Expected range \`${expectedVersionRange}\` given range \`${discordVersion}\``
|
||||
+ `, but got range \`${packageVersionRange}\`.\n`
|
||||
+ (warns.length > 0
|
||||
? ` * The report for \`${name}\` has ${warns.length} warning${warns.length === 1 ? "" : "s"}:\n`
|
||||
+ formatWarnList(warns, 1)
|
||||
: "");
|
||||
} else
|
||||
section += ".\n";
|
||||
|
||||
section += `* ${errored.length} errored`;
|
||||
if (errored.length > 0) {
|
||||
section += ":\n";
|
||||
for (const { name, packageVersionRange, discordVersion, expectedVersionRange, error, warns } of errored)
|
||||
section += ` * \`${name}\`: \`${fileName}\` version range: \`${packageVersionRange}\``
|
||||
+ `, Found version: \`${discordVersion}\``
|
||||
+ `, Expected version range: \`${expectedVersionRange}\`\n`
|
||||
+ (warns.length > 0
|
||||
? ` * The report for \`${name}\` has ${warns.length} warning${warns.length === 1 ? "" : "s"}:\n`
|
||||
+ formatWarnList(warns, 1)
|
||||
: "")
|
||||
+ ` * The report for \`${name}\` has an error:\n` + codeBlock(error, 1);
|
||||
} else
|
||||
section += ".\n\n";
|
||||
} else
|
||||
section += "File-level error: \n" + codeBlock(fileError);
|
||||
}
|
||||
|
||||
if (fileToLogCount > 0) {
|
||||
const fileToNotLogCount = deps.length - fileToLogCount;
|
||||
sections += `### ${fileToNotLogCount} file${fileToNotLogCount === 1 ? " has" : "s have"}`
|
||||
+ " no file-level errors, file-level warnings, or watched dependencies that failed or have warnings.\n" + section;
|
||||
} else
|
||||
sections += "### No file-level errors or warnings.\n"
|
||||
+ "### All watched dependencies passed without warnings.\n";
|
||||
}
|
||||
|
||||
if (src.length > 0) {
|
||||
sections += `## ${src.length} file${src.length === 1 ? "" : "s"} with watched declarations:\n`;
|
||||
|
||||
let fileToLogCount = 0;
|
||||
let section = "";
|
||||
|
||||
for (const report of src) {
|
||||
const { fileName, fileError, fileWarns, unchanged, warned, changed, errored } = report;
|
||||
|
||||
const toLogCount = warned.length + changed.length + errored.length;
|
||||
if (
|
||||
toLogCount <= 0
|
||||
&& fileError === undefined
|
||||
&& fileWarns.length <= 0
|
||||
) continue;
|
||||
fileToLogCount++;
|
||||
|
||||
const count = unchanged.length + toLogCount;
|
||||
section += `### \`${fileName}\`:\n`
|
||||
+ `${fileWarns.length} file-level warning${fileWarns.length === 1 ? "" : "s"}`
|
||||
+ (fileWarns.length > 0 ? ": \n" + formatWarnList(fileWarns) : ". \n")
|
||||
+ `${count} watched declaration${count === 1 ? "" : "s"}: \n`;
|
||||
|
||||
if (fileError === undefined) {
|
||||
section += `* ${unchanged.length} ${unchanged.length === 1 ? "is" : "are"} unchanged without warnings.\n`;
|
||||
|
||||
section += `* ${warned.length} ${warned.length === 1 ? "is" : "are"} unchanged with warnings`;
|
||||
if (warned.length > 0) {
|
||||
section += ":\n";
|
||||
for (const { type, identifier, warns } of warned)
|
||||
section += ` * The report for ${type} \`${identifier}\` has ${warns.length} warning${warns.length === 1 ? "" : "s"}:\n`
|
||||
+ formatWarnList(warns, 1);
|
||||
} else
|
||||
section += ".\n";
|
||||
|
||||
section += `* ${changed.length} ha${changed.length === 1 ? "s" : "ve"} changes`;
|
||||
if (changed.length > 0) {
|
||||
section += ":\n";
|
||||
for (const { type, identifier, changes, warns } of changed) {
|
||||
let additionCount = 0;
|
||||
let added = "";
|
||||
|
||||
let removalCount = 0;
|
||||
let removed = "";
|
||||
|
||||
switch (type) {
|
||||
case "class": {
|
||||
const { additions, removals } = changes;
|
||||
|
||||
if (additions.constructorDefinition) {
|
||||
additionCount++;
|
||||
added += " * Constructor definition with parameters\n";
|
||||
}
|
||||
if (additions.staticMethodsAndFields.length > 0) {
|
||||
additionCount += additions.staticMethodsAndFields.length;
|
||||
added += " * Static methods and fields:\n" + formatKeyList(additions.staticMethodsAndFields, 4);
|
||||
}
|
||||
if (additions.staticGetters.length > 0) {
|
||||
additionCount += additions.staticGetters.length;
|
||||
added += " * Static getters:\n" + formatKeyList(additions.staticGetters, 4);
|
||||
}
|
||||
if (additions.staticSetters.length > 0) {
|
||||
additionCount += additions.staticSetters.length;
|
||||
added += " * Static setters:\n" + formatKeyList(additions.staticSetters, 4);
|
||||
}
|
||||
if (additions.methods.length > 0) {
|
||||
additionCount += additions.methods.length;
|
||||
added += " * Instance methods:\n" + formatKeyList(additions.methods, 4);
|
||||
}
|
||||
if (additions.getters.length > 0) {
|
||||
additionCount += additions.getters.length;
|
||||
added += " * Getters:\n" + formatKeyList(additions.getters, 4);
|
||||
}
|
||||
if (additions.setters.length > 0) {
|
||||
additionCount += additions.setters.length;
|
||||
added += " * Setters:\n" + formatKeyList(additions.setters, 4);
|
||||
}
|
||||
if (additions.fields.length > 0) {
|
||||
additionCount += additions.fields.length;
|
||||
added += " * Fields:\n" + formatKeyList(additions.fields, 4);
|
||||
}
|
||||
|
||||
if (removals.constructorDefinition) {
|
||||
removalCount++;
|
||||
removed += " * Constructor definition with parameters\n";
|
||||
}
|
||||
if (removals.staticMethodsAndFields.length > 0) {
|
||||
removalCount += removals.staticMethodsAndFields.length;
|
||||
removed += " * Static methods and fields:\n" + formatKeyList(removals.staticMethodsAndFields, 4);
|
||||
}
|
||||
if (removals.staticGetters.length > 0) {
|
||||
removalCount += removals.staticGetters.length;
|
||||
removed += " * Static getters:\n" + formatKeyList(removals.staticGetters, 4);
|
||||
}
|
||||
if (removals.staticSetters.length > 0) {
|
||||
removalCount += removals.staticSetters.length;
|
||||
removed += " * Static setters:\n" + formatKeyList(removals.staticSetters, 4);
|
||||
}
|
||||
if (removals.methods.length > 0) {
|
||||
removalCount += removals.methods.length;
|
||||
removed += " * Instance methods:\n" + formatKeyList(removals.methods, 4);
|
||||
}
|
||||
if (removals.getters.length > 0) {
|
||||
removalCount += removals.getters.length;
|
||||
removed += " * Getters:\n" + formatKeyList(removals.getters, 4);
|
||||
}
|
||||
if (removals.setters.length > 0) {
|
||||
removalCount += removals.setters.length;
|
||||
removed += " * Setters:\n" + formatKeyList(removals.setters, 4);
|
||||
}
|
||||
if (removals.fields.length > 0) {
|
||||
removalCount += removals.fields.length;
|
||||
removed += " * Fields:\n" + formatKeyList(removals.fields, 4);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case "enum": {
|
||||
const { additions, removals } = changes;
|
||||
|
||||
const addedEntries = Object.entries(additions);
|
||||
if (addedEntries.length > 0) {
|
||||
additionCount = addedEntries.length;
|
||||
added += formatEnumEntryList(addedEntries, 3);
|
||||
}
|
||||
|
||||
const removedEntries = Object.entries(removals);
|
||||
if (removedEntries.length > 0) {
|
||||
removalCount = removedEntries.length;
|
||||
removed += formatEnumEntryList(removedEntries, 3);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const changeCount = additionCount + removalCount;
|
||||
section += ` * ${capitalize(type)} \`${identifier}\` has ${changeCount} change${changeCount === 1 ? "" : "s"}:\n`
|
||||
+ ` * ${additionCount} addition${additionCount === 1 ? "" : "s"}`
|
||||
+ (additionCount > 0 ? ":\n" + added : ".\n")
|
||||
+ ` * ${removalCount} removal${removalCount === 1 ? "" : "s"}`
|
||||
+ (removalCount > 0 ? ":\n" + removed : ".\n")
|
||||
+ (warns.length > 0
|
||||
? ` * The report for ${type} \`${identifier}\` has ${warns.length} warning${warns.length === 1 ? "" : "s"}:\n`
|
||||
+ formatWarnList(warns, 1)
|
||||
: "");
|
||||
}
|
||||
} else
|
||||
section += ".\n";
|
||||
|
||||
section += `* ${errored.length} errored`;
|
||||
if (errored.length > 0) {
|
||||
section += ":\n";
|
||||
for (const { type, identifier, warns, error } of errored)
|
||||
section += (warns.length > 0
|
||||
? ` * The report for ${type} \`${identifier}\` has ${warns.length} warning${warns.length === 1 ? "" : "s"}:\n`
|
||||
+ formatWarnList(warns, 1)
|
||||
: "")
|
||||
+ ` * The report for ${type} \`${identifier}\` has an error:\n` + codeBlock(error, 1);
|
||||
} else
|
||||
section += ".\n\n";
|
||||
} else
|
||||
section += "File-level error: \n" + codeBlock(fileError);
|
||||
}
|
||||
|
||||
if (fileToLogCount > 0) {
|
||||
const fileToNotLogCount = src.length - fileToLogCount;
|
||||
sections += `### ${fileToNotLogCount} file${fileToNotLogCount === 1 ? " has" : "s have"}`
|
||||
+ " no file-level errors, file-level warnings, or watched declarations with changes or warnings.\n" + section;
|
||||
} else
|
||||
sections += "### No file-level errors or warnings.\n"
|
||||
+ "### All watched declarations are unchanged without warnings.\n";
|
||||
}
|
||||
|
||||
summary += sections || "## There are 0 watched dependencies and declarations.\n";
|
||||
|
||||
const { GITHUB_STEP_SUMMARY } = process.env;
|
||||
if (GITHUB_STEP_SUMMARY)
|
||||
writeFile(GITHUB_STEP_SUMMARY, summary, "utf-8");
|
||||
else
|
||||
console.log(summary);
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import process from "node:process";
|
||||
|
||||
export function capitalize(string: string) {
|
||||
return string.replace(/^./, c => c.toUpperCase());
|
||||
}
|
||||
|
||||
export function codeBlock(content?: unknown, indentLevel = 0) {
|
||||
const indent = " ".repeat(indentLevel);
|
||||
return `\`\`\`\n${content}\n\`\`\``.replaceAll(/^/gm, indent) + "\n";
|
||||
}
|
||||
|
||||
export function formatWarnList(warns: readonly string[], indentLevel = 0) {
|
||||
return warns.reduce((list, warn) => list + codeBlock(warn, indentLevel), "");
|
||||
}
|
||||
|
||||
export function formatKeyList(keys: readonly string[], indentLevel = 0) {
|
||||
const indent = " ".repeat(indentLevel);
|
||||
return keys.reduce((list, key) => list + indent + `* \`${key}\`\n`, "");
|
||||
}
|
||||
|
||||
export function formatValue(value?: unknown) {
|
||||
switch (typeof value) {
|
||||
case "string":
|
||||
return JSON.stringify(value);
|
||||
case "bigint":
|
||||
return value + "n";
|
||||
default:
|
||||
return String(value);
|
||||
}
|
||||
}
|
||||
|
||||
export function formatEnumEntryList(entries: readonly (readonly [key: string, value: unknown])[], indentLevel = 0) {
|
||||
const indent = " ".repeat(indentLevel);
|
||||
return entries.reduce((list, [key, value]) => list + indent + `* \`${key} = ${formatValue(value)}\`\n`, "");
|
||||
}
|
||||
|
||||
export function formatChannel(channel?: string) {
|
||||
switch (channel) {
|
||||
case "stable":
|
||||
case "canary":
|
||||
return capitalize(channel);
|
||||
case "ptb":
|
||||
return channel.toUpperCase();
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
export function getSummaryURL(channel?: string) {
|
||||
const { GITHUB_SERVER_URL, GITHUB_REPOSITORY, GITHUB_RUN_ID, GITHUB_RUN_ATTEMPT } = process.env;
|
||||
if (GITHUB_SERVER_URL && GITHUB_REPOSITORY && GITHUB_RUN_ID && GITHUB_RUN_ATTEMPT)
|
||||
return encodeURI(
|
||||
`${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/attempts/${GITHUB_RUN_ATTEMPT}`
|
||||
+ `#:~:text=Change Report (${formatChannel(channel)})`
|
||||
);
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import console from "node:console";
|
||||
|
||||
import type { CR } from "../types.mts";
|
||||
import { codeBlock, formatChannel, getSummaryURL } from "./utils.mjs";
|
||||
|
||||
export async function postError(error: Error, webhookURL?: string, channel?: string) {
|
||||
if (!webhookURL) return;
|
||||
|
||||
const res = await fetch(webhookURL, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
username: "Change Reporter",
|
||||
embeds: [{
|
||||
title: `Change Report (${formatChannel(channel)})`,
|
||||
description: "### Fatal error:\n" + codeBlock(error.stack),
|
||||
url: getSummaryURL(channel),
|
||||
color: 0xF23F42
|
||||
}]
|
||||
})
|
||||
});
|
||||
|
||||
if (!res.ok)
|
||||
console.error(`Failed to exectute webhook (status '${res.status} ${res.statusText}').`);
|
||||
}
|
||||
|
||||
export async function postReport(report: CR.ChangeReport, webhookURL: string, channel?: string) {
|
||||
const { deps, src } = report;
|
||||
|
||||
let areChanges = false;
|
||||
let description = "";
|
||||
|
||||
if (deps.length > 0) {
|
||||
let warnedFileCount = 0;
|
||||
let erroredFileCount = 0;
|
||||
let passedCount = 0;
|
||||
let warnedCount = 0;
|
||||
let failedCount = 0;
|
||||
let erroredCount = 0;
|
||||
for (const report of deps) {
|
||||
if (report.fileWarns.length > 0)
|
||||
warnedFileCount++;
|
||||
if (report.fileError !== undefined)
|
||||
erroredFileCount++;
|
||||
passedCount += report.passed.length;
|
||||
warnedCount += report.warned.length;
|
||||
failedCount += report.failed.length;
|
||||
erroredCount += report.errored.length;
|
||||
}
|
||||
|
||||
const fileToLogCount = warnedFileCount + erroredFileCount;
|
||||
const toLogCount = warnedCount + failedCount + erroredCount;
|
||||
const count = passedCount + toLogCount;
|
||||
if (fileToLogCount + count > 0) {
|
||||
description += "### Dependencies:\n";
|
||||
|
||||
if (fileToLogCount > 0) {
|
||||
areChanges = true;
|
||||
description += `${deps.length} file${deps.length === 1 ? "" : "s"}:\n`
|
||||
+ `* ${warnedFileCount} file${warnedFileCount === 1 ? " has" : "s have"} file-level warnings.\n`
|
||||
+ `* ${erroredFileCount} file${erroredFileCount === 1 ? " has" : "s have"} a file-level error.\n`;
|
||||
} else
|
||||
description += "No file-level errors or warnings.\n";
|
||||
|
||||
if (toLogCount > 0) {
|
||||
areChanges = true;
|
||||
description += `${count} watched dependenc${count === 1 ? "y" : "ies"}:\n`
|
||||
+ `* ${passedCount} passed without warnings.\n`
|
||||
+ `* ${warnedCount} passed with warnings.\n`
|
||||
+ `* ${failedCount} failed.\n`
|
||||
+ `* ${erroredCount} errored.\n`;
|
||||
} else
|
||||
description += "All watched dependencies passed without warnings.\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (src.length > 0) {
|
||||
let warnedFileCount = 0;
|
||||
let erroredFileCount = 0;
|
||||
let unchangedCount = 0;
|
||||
let warnedCount = 0;
|
||||
let changedCount = 0;
|
||||
let erroredCount = 0;
|
||||
for (const report of src) {
|
||||
if (report.fileWarns.length > 0)
|
||||
warnedFileCount++;
|
||||
if (report.fileError !== undefined)
|
||||
erroredFileCount++;
|
||||
unchangedCount += report.unchanged.length;
|
||||
warnedCount += report.warned.length;
|
||||
changedCount += report.changed.length;
|
||||
erroredCount += report.errored.length;
|
||||
}
|
||||
|
||||
const fileToLogCount = warnedFileCount + erroredFileCount;
|
||||
const toLogCount = warnedCount + changedCount + erroredCount;
|
||||
const count = unchangedCount + toLogCount;
|
||||
if (fileToLogCount + count > 0) {
|
||||
description += "### Declarations:\n";
|
||||
|
||||
if (fileToLogCount > 0) {
|
||||
areChanges = true;
|
||||
description += `${src.length} file${src.length === 1 ? "" : "s"}:\n`
|
||||
+ `* ${warnedFileCount} file${warnedFileCount === 1 ? " has" : "s have"} file-level warnings.\n`
|
||||
+ `* ${erroredFileCount} file${erroredFileCount === 1 ? " has" : "s have"} a file-level error.\n`;
|
||||
} else
|
||||
description += "No file-level errors or warnings.\n";
|
||||
|
||||
if (toLogCount > 0) {
|
||||
areChanges = true;
|
||||
description += `${count} watched declaration${count === 1 ? "" : "s"}:\n`
|
||||
+ `* ${unchangedCount} ${unchangedCount === 1 ? "is" : "are"} unchanged without warnings.\n`
|
||||
+ `* ${warnedCount} ${warnedCount === 1 ? "is" : "are"} unchanged with warnings.\n`
|
||||
+ `* ${changedCount} ha${changedCount === 1 ? "s" : "ve"} changes.\n`
|
||||
+ `* ${erroredCount} errored.\n`;
|
||||
} else
|
||||
description += "All watched declarations are unchanged without warnings.\n";
|
||||
}
|
||||
}
|
||||
|
||||
description ||= "### There are 0 watched dependencies and declarations.\n";
|
||||
|
||||
const res = await fetch(webhookURL, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
username: "Change Reporter",
|
||||
embeds: [{
|
||||
title: `Change Report (${formatChannel(channel)})`,
|
||||
description,
|
||||
url: getSummaryURL(channel),
|
||||
color: areChanges ? 0xF0B132 : 0x23A559
|
||||
}]
|
||||
})
|
||||
});
|
||||
|
||||
if (!res.ok)
|
||||
console.error(`Failed to exectute webhook (status '${res.status} ${res.statusText}').`);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { join } from "node:path";
|
||||
|
||||
import type { Page } from "puppeteer-core";
|
||||
|
||||
import type { CR } from "../types.mts";
|
||||
import { getDependenciesReport } from "./getDependenciesReport.mjs";
|
||||
import { getSrcFileReport } from "./getSrcFileReport.mjs";
|
||||
|
||||
export async function getChangeReport(page: Page, config: CR.ReporterConfig): Promise<CR.ChangeReport> {
|
||||
const { rootDir, deps, src } = config;
|
||||
|
||||
const depsReports: Promise<CR.DependenciesReport>[] = [];
|
||||
if (deps)
|
||||
for (const filePath in deps)
|
||||
depsReports.push(getDependenciesReport(page, join(rootDir, filePath), deps[filePath]!));
|
||||
|
||||
const srcReports: Promise<CR.SrcFileReport>[] = [];
|
||||
if (src)
|
||||
for (const filePath in src)
|
||||
srcReports.push(getSrcFileReport(page, join(rootDir, filePath), src[filePath]!));
|
||||
|
||||
return {
|
||||
deps: await Promise.all(depsReports),
|
||||
src: await Promise.all(srcReports)
|
||||
};
|
||||
}
|
|
@ -0,0 +1,289 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { AST_NODE_TYPES, type TSESTree } from "@typescript-eslint/typescript-estree";
|
||||
import type { Page } from "puppeteer-core";
|
||||
|
||||
import type { autoFindClass, autoFindStore } from "../finds/classes.mts";
|
||||
import type { CR } from "../types.mts";
|
||||
import { funcToString, getErrorStack, getSanitizedConfig, pageAsyncFunction, pageFunction } from "./utils.mjs";
|
||||
|
||||
export async function getClassReport(
|
||||
page: Page,
|
||||
declaration: TSESTree.ClassDeclarationWithName,
|
||||
rawConfig: CR.DeclarationConfig
|
||||
) {
|
||||
const { name } = declaration.id;
|
||||
const report: CR.ClassReport = {
|
||||
type: "class",
|
||||
identifier: name,
|
||||
changes: undefined,
|
||||
error: undefined,
|
||||
warns: []
|
||||
};
|
||||
|
||||
const config = getSanitizedConfig(rawConfig, report);
|
||||
const source = getClassMembers(declaration.body.body, config, report);
|
||||
|
||||
const { find } = config;
|
||||
if (find) {
|
||||
try {
|
||||
const changes = await page.evaluate<[CR.ClassMembers], CR.FindFunction<[CR.ClassMembers], CR.ClassChanges>>(
|
||||
pageAsyncFunction("s", `const c = await ${funcToString(find)}.call(Vencord, s);`
|
||||
+ "if (Array.isArray(c)) { if (c.length > 0 && c.every(isValidClass)) return getClassChanges(s, c); }"
|
||||
+ "else if (isValidClass(c)) return getClassChanges(s, [c]);"),
|
||||
source
|
||||
);
|
||||
if (changes) {
|
||||
checkClassIgnores(changes, config, report);
|
||||
report.changes = changes;
|
||||
return report;
|
||||
}
|
||||
report.warns.push(`Find for class '${name}' failed; attempting automatic class find.`);
|
||||
} catch (error) {
|
||||
report.warns.push(`Find for class '${name}' errored; attempting automatic class find:\n` + getErrorStack(error));
|
||||
}
|
||||
}
|
||||
|
||||
// Fast path for stores
|
||||
if (/Store$/.test(name) && !declaration.abstract) {
|
||||
try {
|
||||
const changes = await page.evaluate<Parameters<typeof autoFindStore>, typeof autoFindStore>(
|
||||
pageFunction("s", "n", "return autoFindStore(s, n);"),
|
||||
source,
|
||||
name
|
||||
);
|
||||
if (changes) {
|
||||
checkClassIgnores(changes, config, report);
|
||||
report.changes = changes;
|
||||
return report;
|
||||
}
|
||||
report.warns.push(`Automatic store find for store '${name}' failed; attempting automatic class find.`);
|
||||
} catch (error) {
|
||||
report.warns.push(`Automatic store find for store '${name}' errored; attempting automatic class find:\n` + getErrorStack(error));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const changes = await page.evaluate<Parameters<typeof autoFindClass>, typeof autoFindClass>(
|
||||
pageFunction("s", "return autoFindClass(s);"),
|
||||
source
|
||||
);
|
||||
if (changes) {
|
||||
if (
|
||||
// Ignore classes that do not have any members in common
|
||||
// or classes that only have a constructor in common
|
||||
changes.unchangedCount > 1
|
||||
|| changes.unchangedCount > 0
|
||||
&& (changes.additions.constructorDefinition
|
||||
|| changes.removals.constructorDefinition)
|
||||
) {
|
||||
checkClassIgnores(changes, config, report);
|
||||
report.changes = changes;
|
||||
} else
|
||||
report.error = `Automatic class find for class '${name}' failed. The target class may have too many changes.`;
|
||||
} else
|
||||
report.error = `Automatic class find for class '${name}' failed.`;
|
||||
} catch (error) {
|
||||
report.error = `Automatic class find for class '${name}' errored:\n` + getErrorStack(error);
|
||||
}
|
||||
return report;
|
||||
}
|
||||
|
||||
function getClassMembers(
|
||||
members: readonly TSESTree.ClassElement[],
|
||||
config: CR.ClassConfig,
|
||||
report: CR.ClassReport
|
||||
): CR.ClassMembers {
|
||||
let constructorDefinition = false;
|
||||
// Ignore duplicate members from overload signatures and config ignores
|
||||
const staticMethodsAndFields = new Set<string>();
|
||||
const staticGetters = new Set<string>();
|
||||
const staticSetters = new Set<string>();
|
||||
const methods = new Set<string>();
|
||||
const getters = new Set<string>();
|
||||
const setters = new Set<string>();
|
||||
const fields = new Set<string>();
|
||||
|
||||
const { includeOptional } = config;
|
||||
for (const [index, member] of members.entries()) {
|
||||
switch (member.type) {
|
||||
// Exclude abstract methods
|
||||
case AST_NODE_TYPES.MethodDefinition: {
|
||||
if (member.optional && !includeOptional) continue;
|
||||
|
||||
const name = getClassMemberName(member, index, report);
|
||||
if (name === undefined) continue;
|
||||
|
||||
switch (member.kind) {
|
||||
case "constructor":
|
||||
// Ignore constructor definitions without parameters
|
||||
if (member.value.params.length > 0)
|
||||
constructorDefinition = true;
|
||||
break;
|
||||
case "method":
|
||||
if (member.static)
|
||||
staticMethodsAndFields.add(name);
|
||||
else
|
||||
methods.add(name);
|
||||
break;
|
||||
case "get":
|
||||
if (member.static)
|
||||
staticGetters.add(name);
|
||||
else
|
||||
getters.add(name);
|
||||
break;
|
||||
case "set":
|
||||
if (member.static)
|
||||
staticSetters.add(name);
|
||||
else
|
||||
setters.add(name);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
// Exclude abstract properties
|
||||
case AST_NODE_TYPES.PropertyDefinition: {
|
||||
if (member.optional && !includeOptional) continue;
|
||||
|
||||
const name = getClassMemberName(member, index, report);
|
||||
if (name === undefined) continue;
|
||||
|
||||
if (member.static)
|
||||
staticMethodsAndFields.add(name);
|
||||
else
|
||||
fields.add(name);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const { ignoredAdditions, ignoredRemovals } = config;
|
||||
|
||||
if (ignoredAdditions) {
|
||||
if (ignoredAdditions.constructorDefinition)
|
||||
constructorDefinition = true;
|
||||
applyClassIgnoredAdditions(staticMethodsAndFields, ignoredAdditions.staticMethodsAndFields);
|
||||
applyClassIgnoredAdditions(staticGetters, ignoredAdditions.staticGetters);
|
||||
applyClassIgnoredAdditions(staticSetters, ignoredAdditions.staticSetters);
|
||||
applyClassIgnoredAdditions(methods, ignoredAdditions.methods);
|
||||
applyClassIgnoredAdditions(getters, ignoredAdditions.getters);
|
||||
applyClassIgnoredAdditions(setters, ignoredAdditions.setters);
|
||||
applyClassIgnoredAdditions(fields, ignoredAdditions.fields);
|
||||
}
|
||||
|
||||
if (ignoredRemovals) {
|
||||
if (ignoredRemovals.constructorDefinition)
|
||||
constructorDefinition = false;
|
||||
applyClassIgnoredRemovals(staticMethodsAndFields, ignoredRemovals.staticMethodsAndFields);
|
||||
applyClassIgnoredRemovals(staticGetters, ignoredRemovals.staticGetters);
|
||||
applyClassIgnoredRemovals(staticSetters, ignoredRemovals.staticSetters);
|
||||
applyClassIgnoredRemovals(methods, ignoredRemovals.methods);
|
||||
applyClassIgnoredRemovals(getters, ignoredRemovals.getters);
|
||||
applyClassIgnoredRemovals(setters, ignoredRemovals.setters);
|
||||
applyClassIgnoredRemovals(fields, ignoredRemovals.fields);
|
||||
}
|
||||
|
||||
return {
|
||||
constructorDefinition: constructorDefinition,
|
||||
staticMethodsAndFields: [...staticMethodsAndFields],
|
||||
staticGetters: [...staticGetters],
|
||||
staticSetters: [...staticSetters],
|
||||
methods: [...methods],
|
||||
getters: [...getters],
|
||||
setters: [...setters],
|
||||
fields: [...fields]
|
||||
};
|
||||
}
|
||||
|
||||
function getClassMemberName(
|
||||
member: TSESTree.MethodDefinition | TSESTree.PropertyDefinition,
|
||||
index: number,
|
||||
report: CR.ClassReport
|
||||
) {
|
||||
const { key } = member;
|
||||
switch (key.type) {
|
||||
case AST_NODE_TYPES.Identifier: {
|
||||
const { name } = key;
|
||||
if (!member.computed)
|
||||
return name;
|
||||
report.warns.push(`Computed key '[${name}]' of member at index '${index}' of class '${report.identifier}' is unsupported; ignoring member.`);
|
||||
return;
|
||||
}
|
||||
case AST_NODE_TYPES.Literal:
|
||||
return String(key.value);
|
||||
case AST_NODE_TYPES.MemberExpression: {
|
||||
const { object, property } = key;
|
||||
if (
|
||||
object.type === AST_NODE_TYPES.Identifier
|
||||
&& property.type === AST_NODE_TYPES.Identifier
|
||||
) return `Symbol(${object.name}.${property.name})`;
|
||||
break;
|
||||
}
|
||||
}
|
||||
report.warns.push(`Computed key of member at index '${index}' of class '${report.identifier}' is unsupported; ignoring member.`);
|
||||
}
|
||||
|
||||
/** Adds ignored additions so as to not affect `changedCount`. */
|
||||
function applyClassIgnoredAdditions(members: Set<string>, ignored?: readonly string[]) {
|
||||
if (ignored)
|
||||
for (const key of ignored)
|
||||
members.add(key);
|
||||
}
|
||||
|
||||
/** Removes ignored removals so as to not affect `changedCount`. */
|
||||
function applyClassIgnoredRemovals(members: Set<string>, ignored?: readonly string[] | boolean) {
|
||||
if (Array.isArray(ignored)) {
|
||||
for (const key of ignored)
|
||||
members.delete(key);
|
||||
} else if (ignored)
|
||||
members.clear();
|
||||
}
|
||||
|
||||
function checkClassIgnores(
|
||||
changes: CR.ClassChanges,
|
||||
config: CR.ClassConfig,
|
||||
report: CR.ClassReport
|
||||
) {
|
||||
const { additions, removals } = changes;
|
||||
const { ignoredAdditions, ignoredRemovals } = config;
|
||||
|
||||
if (ignoredAdditions) {
|
||||
const { constructorDefinition, ...rest } = ignoredAdditions;
|
||||
|
||||
if (constructorDefinition && removals.constructorDefinition)
|
||||
report.warns.push(`Ignored addition 'constructorDefinition' in config for class '${report.identifier}' had no effect.`);
|
||||
|
||||
for (const key in rest) {
|
||||
const memberCategory = key as keyof typeof rest;
|
||||
const removedKeys = new Set(removals[memberCategory]);
|
||||
for (const ignoredKey in rest[memberCategory])
|
||||
if (removedKeys.has(ignoredKey))
|
||||
report.warns.push(`Ignored addition '${ignoredKey}' of '${memberCategory}' in config for class '${report.identifier}' had no effect.`);
|
||||
}
|
||||
}
|
||||
|
||||
if (ignoredRemovals) {
|
||||
const { constructorDefinition, ...rest } = ignoredRemovals;
|
||||
|
||||
if (constructorDefinition && additions.constructorDefinition)
|
||||
report.warns.push(`Ignored removal 'constructorDefinition' in config for class '${report.identifier}' had no effect.`);
|
||||
|
||||
for (const key in rest) {
|
||||
const memberCategory = key as keyof typeof rest;
|
||||
const ignoredKeys = rest[memberCategory];
|
||||
if (Array.isArray(ignoredKeys)) {
|
||||
const addedKeys = new Set(additions[memberCategory]);
|
||||
for (const ignoredKey in ignoredKeys)
|
||||
if (addedKeys.has(ignoredKey))
|
||||
report.warns.push(`Ignored removal '${ignoredKey}' of '${memberCategory}' in config for class '${report.identifier}' had no effect.`);
|
||||
} else if (ignoredKeys && additions[memberCategory].length > 0)
|
||||
report.warns.push(`Ignored removal for members of category '${memberCategory}' in config for class '${report.identifier}' had no effect.`);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { basename } from "node:path";
|
||||
|
||||
import type { Page } from "puppeteer-core";
|
||||
import { satisfies, subset, valid, validRange } from "semver";
|
||||
import type { JsonObject, JsonValue } from "type-fest";
|
||||
|
||||
import type { CR } from "../types.mts";
|
||||
import { funcToString, getErrorStack, pageFunction } from "./utils.mjs";
|
||||
|
||||
export async function getDependenciesReport(page: Page, filePath: string, config: CR.DependenciesConfig) {
|
||||
const fileName = basename(filePath);
|
||||
const fileReport: CR.DependenciesReport = {
|
||||
filePath,
|
||||
fileName,
|
||||
fileWarns: [],
|
||||
passed: [],
|
||||
warned: [],
|
||||
failed: [],
|
||||
errored: []
|
||||
};
|
||||
|
||||
let dependencies: JsonValue | undefined;
|
||||
try {
|
||||
dependencies = JSON.parse(await readFile(filePath, "utf-8"))?.dependencies;
|
||||
} catch (error) {
|
||||
fileReport.fileError = `Failed to read and parse file '${fileName}':\n` + error;
|
||||
return fileReport;
|
||||
}
|
||||
|
||||
if (
|
||||
typeof dependencies !== "object"
|
||||
|| dependencies === null
|
||||
|| Array.isArray(dependencies)
|
||||
) {
|
||||
fileReport.fileError = `File '${fileName}' does not have a valid dependencies object.`;
|
||||
return fileReport;
|
||||
}
|
||||
|
||||
for (const key in config) {
|
||||
const dependencyConfig = config[key]!;
|
||||
|
||||
const report: CR.DependencyReport = {
|
||||
name: key,
|
||||
packageVersionRange: undefined,
|
||||
discordVersion: undefined,
|
||||
expectedVersionRange: undefined,
|
||||
error: undefined,
|
||||
warns: []
|
||||
};
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/53395
|
||||
const packageVersionRange = (dependencies as JsonObject)[key];
|
||||
if (typeof packageVersionRange !== "string") {
|
||||
report.error = `File '${fileName}' does not have a dependency with name '${key}'.`;
|
||||
fileReport.errored.push(report);
|
||||
continue;
|
||||
}
|
||||
report.packageVersionRange = packageVersionRange;
|
||||
|
||||
if (!validRange(packageVersionRange)) {
|
||||
report.error = `Version range '${packageVersionRange}' for dependency '${key}' in file '${fileName}' is invalid.`;
|
||||
fileReport.errored.push(report);
|
||||
continue;
|
||||
}
|
||||
|
||||
let discordVersion: unknown;
|
||||
try {
|
||||
discordVersion = await page.evaluate<[], CR.FindFunction<[]>>(
|
||||
pageFunction(`return ${funcToString(dependencyConfig.find)}.call(Vencord);`)
|
||||
);
|
||||
} catch (error) {
|
||||
report.error = `Find for version of dependency '${key}' errored:\n` + getErrorStack(error);
|
||||
fileReport.errored.push(report);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (typeof discordVersion !== "string") {
|
||||
report.error = `Find for version of dependency '${key}' failed.`;
|
||||
fileReport.errored.push(report);
|
||||
continue;
|
||||
}
|
||||
report.discordVersion = discordVersion;
|
||||
|
||||
if (!valid(discordVersion)) {
|
||||
report.error = `Find for version of dependency '${key}' returned an invalid SemVer version ('${discordVersion}').`;
|
||||
fileReport.errored.push(report);
|
||||
continue;
|
||||
}
|
||||
|
||||
const { overrides } = dependencyConfig;
|
||||
const expectedVersionRange = overrides?.find(([range]) => satisfies(discordVersion, range))?.[1]
|
||||
?? discordVersion;
|
||||
report.expectedVersionRange = expectedVersionRange;
|
||||
|
||||
if (subset(packageVersionRange, expectedVersionRange)) {
|
||||
if (report.warns.length > 0)
|
||||
fileReport.warned.push(report);
|
||||
else
|
||||
fileReport.passed.push(report);
|
||||
} else
|
||||
fileReport.failed.push(report);
|
||||
}
|
||||
|
||||
return fileReport;
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { AST_NODE_TYPES, type TSESTree } from "@typescript-eslint/typescript-estree";
|
||||
import type { Page } from "puppeteer-core";
|
||||
|
||||
import type { autoFindEnum } from "../finds/enums.mts";
|
||||
import { formatValue } from "../logging/utils.mjs";
|
||||
import type { CR } from "../types.mts";
|
||||
import { funcToString, getErrorStack, getSanitizedConfig, pageAsyncFunction, pageFunction } from "./utils.mjs";
|
||||
|
||||
export async function getEnumReport(
|
||||
page: Page,
|
||||
declaration: TSESTree.TSEnumDeclaration,
|
||||
rawConfig: CR.DeclarationConfig
|
||||
) {
|
||||
const { name } = declaration.id;
|
||||
const report: CR.EnumReport = {
|
||||
type: "enum",
|
||||
identifier: name,
|
||||
changes: undefined,
|
||||
error: undefined,
|
||||
warns: []
|
||||
};
|
||||
|
||||
const config = getSanitizedConfig(rawConfig, report);
|
||||
const source = getEnumMembers(declaration.body.members, config, report);
|
||||
|
||||
const { find } = config;
|
||||
if (find) {
|
||||
try {
|
||||
const changes = await page.evaluate<[CR.EnumSource], CR.FindFunction<[CR.EnumSource], CR.EnumChanges>>(
|
||||
pageAsyncFunction("s", `const o = await ${funcToString(find)}.call(Vencord, s);`
|
||||
+ "if (isValidEnum(o)) return getEnumChanges(s, o);"),
|
||||
source
|
||||
);
|
||||
if (changes) {
|
||||
checkEnumIgnores(changes, config, report);
|
||||
report.changes = changes;
|
||||
return report;
|
||||
}
|
||||
report.warns.push(`Find for enum '${name}' failed; attempting automatic enum find.`);
|
||||
} catch (error) {
|
||||
report.warns.push(`Find for enum '${name}' errored; attempting automatic enum find:\n` + getErrorStack(error));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const changes = await page.evaluate<Parameters<typeof autoFindEnum>, typeof autoFindEnum>(
|
||||
pageFunction("s", "return autoFindEnum(s);"),
|
||||
source
|
||||
);
|
||||
if (changes) {
|
||||
// Ignore enums that do not have any members in common
|
||||
if (changes.unchangedCount > 0) {
|
||||
checkEnumIgnores(changes, config, report);
|
||||
report.changes = changes;
|
||||
} else
|
||||
report.error = `Automatic enum find for enum '${name}' failed. The target enum may have too many changes.`;
|
||||
} else
|
||||
report.error = `Automatic enum find for enum '${name}' failed.`;
|
||||
} catch (error) {
|
||||
report.error = `Automatic enum find for enum '${name}' errored:\n` + getErrorStack(error);
|
||||
}
|
||||
return report;
|
||||
}
|
||||
|
||||
function getEnumMembers(
|
||||
members: readonly TSESTree.TSEnumMember[],
|
||||
config: CR.EnumConfig,
|
||||
report: CR.EnumReport
|
||||
) {
|
||||
const source: CR.EnumSource = {};
|
||||
|
||||
for (const [index, member] of members.entries()) {
|
||||
if (member.computed) {
|
||||
report.warns.push(`Key of member at index '${index}' of enum '${report.identifier}' is computed. Computed enum member keys are unsupported; ignoring member.`);
|
||||
continue;
|
||||
}
|
||||
const { id } = member;
|
||||
const key = id.type === AST_NODE_TYPES.Literal ? id.value : id.name;
|
||||
|
||||
const { initializer } = member;
|
||||
if (!initializer) {
|
||||
report.warns.push(`Member '${key}' of enum '${report.identifier}' has no initializer. Enum members without initializers are unsupported; ignoring member.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const { type } = initializer;
|
||||
switch (type) {
|
||||
case AST_NODE_TYPES.Literal: {
|
||||
const { value } = initializer;
|
||||
if (typeof value === "string" || typeof value === "number")
|
||||
source[key] = value;
|
||||
else
|
||||
report.warns.push(`Literal initializer type '${typeof value}' of member '${key}' of enum '${report.identifier}' is unsupported; ignoring member.`);
|
||||
break;
|
||||
}
|
||||
case AST_NODE_TYPES.BinaryExpression: {
|
||||
const { operator } = initializer;
|
||||
if (operator !== "<<") {
|
||||
report.warns.push(`BinaryExpression initializer operator '${operator}' of member '${key}' of enum '${report.identifier}' is unsupported; ignoring member.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const { left, right } = initializer;
|
||||
if (
|
||||
left.type !== AST_NODE_TYPES.Literal
|
||||
|| typeof left.value !== "number"
|
||||
|| right.type !== AST_NODE_TYPES.Literal
|
||||
|| typeof right.value !== "number"
|
||||
) {
|
||||
report.warns.push(`BinaryExpression initializer of member '${key}' of enum '${report.identifier}' is unsupported; ignoring member.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
source[key] = left.value << right.value;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
report.warns.push(`Initializer type '${type}' of member '${key}' of enum '${report.identifier}' is unsupported; ignoring member.`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const { keyMapper } = config;
|
||||
if (keyMapper)
|
||||
for (const key in source) {
|
||||
const value = source[key]!;
|
||||
delete source[key];
|
||||
source[keyMapper(key)] = value;
|
||||
}
|
||||
|
||||
const { ignoredAdditions, ignoredRemovals } = config;
|
||||
|
||||
// Add ignored additions so as to not affect similarity score
|
||||
if (ignoredAdditions)
|
||||
for (const [key, value] of ignoredAdditions)
|
||||
source[key] = value;
|
||||
|
||||
// Remove ignored removals so as to not affect similarity score
|
||||
if (ignoredRemovals)
|
||||
for (const [key, value] of ignoredRemovals)
|
||||
if (value === undefined || source[key] === value)
|
||||
delete source[key];
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
function checkEnumIgnores(
|
||||
changes: CR.EnumChanges,
|
||||
config: CR.EnumConfig,
|
||||
report: CR.EnumReport
|
||||
) {
|
||||
const { additions, removals } = changes;
|
||||
const { ignoredAdditions, ignoredRemovals } = config;
|
||||
|
||||
if (ignoredAdditions)
|
||||
for (const [key, value] of ignoredAdditions)
|
||||
if (removals[key] === value)
|
||||
report.warns.push(`Ignored addition '${key} = ${formatValue(value)}' in config for enum '${report.identifier}' had no effect.`);
|
||||
|
||||
if (ignoredRemovals)
|
||||
for (const [key, value] of ignoredRemovals)
|
||||
if (value === undefined ? key in additions : additions[key] === value)
|
||||
report.warns.push(`Ignored removal '${key}${value === undefined ? "" : " = " + formatValue(value)}' in config for enum '${report.identifier}' had no effect.`);
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { basename } from "node:path";
|
||||
|
||||
import { AST_NODE_TYPES, parse, type TSESTree } from "@typescript-eslint/typescript-estree";
|
||||
import type { Page } from "puppeteer-core";
|
||||
|
||||
import type { CR } from "../types.mts";
|
||||
import { getClassReport } from "./getClassReport.mjs";
|
||||
import { getEnumReport } from "./getEnumReport.mjs";
|
||||
|
||||
export async function getSrcFileReport(page: Page, filePath: string, config: CR.SrcFileConfig) {
|
||||
const fileName = basename(filePath);
|
||||
const fileReport: CR.SrcFileReport = {
|
||||
filePath,
|
||||
fileName,
|
||||
fileWarns: [],
|
||||
unchanged: [],
|
||||
warned: [],
|
||||
changed: [],
|
||||
errored: []
|
||||
};
|
||||
|
||||
let ast: TSESTree.Program;
|
||||
try {
|
||||
ast = parse(await readFile(filePath, "utf-8"));
|
||||
} catch (error) {
|
||||
fileReport.fileError = `Failed to read and parse '${fileName}':\n` + error;
|
||||
return fileReport;
|
||||
}
|
||||
|
||||
const unfoundDeclarations = new Set(Object.keys(config));
|
||||
const reports: Promise<CR.DeclarationReport>[] = [];
|
||||
for (const node of ast.body) {
|
||||
if (unfoundDeclarations.size <= 0) break;
|
||||
|
||||
const declaration = node.type === AST_NODE_TYPES.ExportNamedDeclaration
|
||||
? node.declaration
|
||||
: node;
|
||||
if (!declaration) continue;
|
||||
|
||||
switch (declaration.type) {
|
||||
case AST_NODE_TYPES.ClassDeclaration: {
|
||||
const { id } = declaration;
|
||||
if (!id) continue;
|
||||
|
||||
const { name } = id;
|
||||
const declarationConfig = config[name];
|
||||
if (!declarationConfig) continue;
|
||||
|
||||
unfoundDeclarations.delete(name);
|
||||
reports.push(getClassReport(
|
||||
page,
|
||||
// @ts-expect-error: Control flow narrowing bug
|
||||
declaration,
|
||||
declarationConfig
|
||||
));
|
||||
break;
|
||||
}
|
||||
case AST_NODE_TYPES.TSEnumDeclaration: {
|
||||
const { name } = declaration.id;
|
||||
const declarationConfig = config[name];
|
||||
if (!declarationConfig) continue;
|
||||
|
||||
unfoundDeclarations.delete(name);
|
||||
reports.push(getEnumReport(
|
||||
page,
|
||||
declaration,
|
||||
declarationConfig
|
||||
));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const report of await Promise.all(reports)) {
|
||||
if (report.error !== undefined) {
|
||||
fileReport.errored.push(report);
|
||||
} else {
|
||||
const { changes } = report;
|
||||
if (changes!.changedCount > 0)
|
||||
fileReport.changed.push(report);
|
||||
else if (report.warns.length > 0)
|
||||
fileReport.warned.push(report);
|
||||
else
|
||||
fileReport.unchanged.push(report);
|
||||
}
|
||||
}
|
||||
|
||||
for (const identifier of unfoundDeclarations)
|
||||
fileReport.errored.push({
|
||||
type: config[identifier]!.type,
|
||||
identifier,
|
||||
changes: undefined,
|
||||
error: `File '${fileName}' does not have a declaration with identifier '${identifier}'.`,
|
||||
warns: []
|
||||
});
|
||||
|
||||
return fileReport;
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { CR } from "../types.mts";
|
||||
|
||||
/** Ensures config's type matches the type of the declaration found by the parser. */
|
||||
export function getSanitizedConfig(config: CR.DeclarationConfig, report: CR.ClassReport): CR.ClassConfig;
|
||||
export function getSanitizedConfig(config: CR.DeclarationConfig, report: CR.EnumReport): CR.EnumConfig;
|
||||
export function getSanitizedConfig(config: CR.DeclarationConfig, report: CR.DeclarationReport) {
|
||||
const { type } = config;
|
||||
const expectedType = report.type;
|
||||
if (type === expectedType)
|
||||
return config;
|
||||
report.warns.push(`Expected config type for '${report.identifier}' to be '${expectedType}', but got '${type}'; config values will be ignored.`);
|
||||
return { type: expectedType };
|
||||
}
|
||||
|
||||
export function pageFunction(...args: [string, ...string[]]): any {
|
||||
const body = args.pop()!;
|
||||
return new Function(...args, `"use strict";${body}`);
|
||||
}
|
||||
|
||||
// https://github.com/microsoft/TypeScript/issues/36177
|
||||
const AsyncFunction: any = async function () {}.constructor;
|
||||
|
||||
export function pageAsyncFunction(...args: [string, ...string[]]): any {
|
||||
const body = args.pop()!;
|
||||
return new AsyncFunction(...args, `"use strict";${body}`);
|
||||
}
|
||||
|
||||
// Based on ECMA-262
|
||||
const functionDeclarationOrArrowFunctionDefinitionRE = /^(?:async(?:[\t\v\f\uFEFF\p{Zs}]|\/\*.*\*\/)+)?(?:function[(*/\t\n\v\f\r\uFEFF\p{Zs}]|(?:\(|(?:[\p{IDS}$_]|\\u(?:[0-9A-Fa-f]{4}|\{[0-9A-Fa-f]{5}\}))(?:[\p{IDC}$]|\\u(?:[0-9A-Fa-f]{4}|\{[0-9A-Fa-f]{5}\}))+(?:[\t\n\v\f\r\uFEFF\p{Zs}]|\/\*.*\*\/)*=))/u;
|
||||
|
||||
/**
|
||||
* Makes the result of `func.toString()` a callable expression when evaled.
|
||||
* Does not support getters, setters, static methods, private methods/getters/setters,
|
||||
* or method definitions with symbol keys.
|
||||
*/
|
||||
export function funcToString(func: (...args: never) => unknown) {
|
||||
const funcString = func.toString();
|
||||
if (functionDeclarationOrArrowFunctionDefinitionRE.test(funcString))
|
||||
return `(${funcString})`;
|
||||
return `({${funcString}})[${JSON.stringify(func.name)}]`;
|
||||
}
|
||||
|
||||
export function getErrorStack(error: unknown) {
|
||||
return typeof error === "object" && error !== null && "stack" in error
|
||||
? error.stack
|
||||
: error;
|
||||
}
|
227
packages/discord-types/scripts/changeReporter/types.mts
Normal file
227
packages/discord-types/scripts/changeReporter/types.mts
Normal file
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import type * as Vencord from "../../../../src/Vencord.ts";
|
||||
|
||||
export namespace CR {
|
||||
export interface ChangeReport {
|
||||
deps: DependenciesReport[];
|
||||
src: SrcFileReport[];
|
||||
}
|
||||
|
||||
export type FileReport = DependenciesReport | SrcFileReport;
|
||||
|
||||
interface FileReportBase {
|
||||
filePath: string;
|
||||
fileName: string;
|
||||
/** Error that caused the report to be returned early. */
|
||||
fileError?: string | undefined;
|
||||
/** Contains warnings not specific to any dependency or declaration. */
|
||||
fileWarns: string[];
|
||||
}
|
||||
|
||||
export interface DependenciesReport extends FileReportBase {
|
||||
/** Contains reports that passed with no warns and no error. */
|
||||
passed: DependencyReport<false>[];
|
||||
/** Contains reports that passed with warns and no error. */
|
||||
warned: DependencyReport<false>[];
|
||||
/** Contains reports that failed with no error and maybe warns. */
|
||||
failed: DependencyReport<false>[];
|
||||
/** Contains reports that have an error. */
|
||||
errored: DependencyReport<true>[];
|
||||
}
|
||||
|
||||
export interface DependencyReport<Errored extends boolean = boolean> {
|
||||
/** The name of the dependency. */
|
||||
name: string;
|
||||
/** The version of the dependency in `package.json`. */
|
||||
packageVersionRange: Errored extends true ? string | undefined : string;
|
||||
/** The version of the dependency bundled with Discord. */
|
||||
discordVersion: Errored extends true ? string | undefined : string;
|
||||
/**
|
||||
* The matched version range from the `overrides` property of {@link DependencyConfig}
|
||||
* or, if none matched, the version of the dependency bundled with Discord.
|
||||
*/
|
||||
expectedVersionRange: Errored extends true ? string | undefined : string;
|
||||
/** Error that caused the report to return early. */
|
||||
error: Errored extends true ? string : undefined;
|
||||
warns: string[];
|
||||
}
|
||||
|
||||
export interface SrcFileReport extends FileReportBase {
|
||||
/** Contains reports that have no changes, no warns, and no error. */
|
||||
unchanged: DeclarationReport<false>[];
|
||||
/** Contains reports that have warns, no changes, and no error. */
|
||||
warned: DeclarationReport<false>[];
|
||||
/** Contains reports that have changes, maybe warns, and no error. */
|
||||
changed: DeclarationReport<false>[];
|
||||
/** Contains reports that have an error. */
|
||||
errored: DeclarationReport<true>[];
|
||||
}
|
||||
|
||||
export type DeclarationReport<Errored extends boolean = boolean>
|
||||
= ClassReport<Errored> | EnumReport<Errored>;
|
||||
|
||||
interface DeclarationReportBase<Errored extends boolean = boolean> {
|
||||
type: string;
|
||||
/** The declaration's identifier. */
|
||||
identifier: string;
|
||||
changes: Errored extends true ? undefined : object;
|
||||
/** Error that caused the report to return early. */
|
||||
error: Errored extends true ? string : undefined;
|
||||
warns: string[];
|
||||
}
|
||||
|
||||
export interface ClassReport<Errored extends boolean = boolean> extends DeclarationReportBase<Errored> {
|
||||
type: "class";
|
||||
identifier: string;
|
||||
changes: Errored extends true ? undefined : ClassChanges;
|
||||
}
|
||||
|
||||
export interface EnumReport<Errored extends boolean = boolean> extends DeclarationReportBase<Errored> {
|
||||
type: "enum";
|
||||
identifier: string;
|
||||
changes: Errored extends true ? undefined : EnumChanges;
|
||||
}
|
||||
|
||||
export interface ReporterConfig {
|
||||
/** The directory file paths are relative to. */
|
||||
rootDir: string;
|
||||
deps?: { [filePath: string]: DependenciesConfig; } | undefined;
|
||||
src?: { [filePath: string]: SrcFileConfig; } | undefined;
|
||||
}
|
||||
|
||||
export interface DependenciesConfig {
|
||||
[dependencyName: string]: DependencyConfig;
|
||||
}
|
||||
|
||||
export interface DependencyConfig {
|
||||
/**
|
||||
* @returns The version of the dependency bundled with Discord or undefined if the version could not be found.
|
||||
*/
|
||||
find: FindFunction<[], string>;
|
||||
/**
|
||||
* Specifies the version range to expect in `package.json` given the version bundled with Discord.
|
||||
*/
|
||||
overrides?: [discordVersionRange: string, packageVersionRange: string][] | undefined;
|
||||
}
|
||||
|
||||
export interface SrcFileConfig {
|
||||
[identifier: string]: DeclarationConfig;
|
||||
}
|
||||
|
||||
export type DeclarationConfig = ClassConfig | EnumConfig;
|
||||
|
||||
interface DeclarationConfigBase {
|
||||
type: string;
|
||||
find?: FindFunction | undefined;
|
||||
}
|
||||
|
||||
export interface ClassConfig extends DeclarationConfigBase {
|
||||
type: "class";
|
||||
/**
|
||||
* An automatic find will be performed if omitted.
|
||||
* If multiple classes are returned, their members will be merged.
|
||||
* @param source The source class.
|
||||
* @returns The class or undefined if it could not be found.
|
||||
*/
|
||||
// https://github.com/microsoft/TypeScript/issues/20007
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
find?: FindFunction<[source: ClassMembers], Function[] | Function> | undefined;
|
||||
/** Whether to include optional class members. */
|
||||
includeOptional?: boolean | undefined;
|
||||
/** Members expected to be added. */
|
||||
ignoredAdditions?: { [Key in keyof ClassMembers]?: ClassMembers[Key] | undefined; } | undefined;
|
||||
/**
|
||||
* Members expected to be removed.
|
||||
* If a category is `true`, all members in that category will be expected to be removed.
|
||||
*/
|
||||
ignoredRemovals?: { [Key in keyof ClassMembers]?: ClassMembers[Key] | boolean | undefined; } | undefined;
|
||||
}
|
||||
|
||||
export interface EnumConfig extends DeclarationConfigBase {
|
||||
type: "enum";
|
||||
/**
|
||||
* An automatic find will be performed if omitted.
|
||||
* @param source The source enum.
|
||||
* @returns The enum or undefined if it could not be found.
|
||||
*/
|
||||
find?: FindFunction<[source: EnumSource], EnumMembers> | undefined;
|
||||
/**
|
||||
* Mapper function to modifiy the source enum's keys.
|
||||
* Ignored additions and removals will not be modified by this function.
|
||||
*/
|
||||
keyMapper?: ((key: string) => string) | undefined;
|
||||
/** Members expected to be added. */
|
||||
ignoredAdditions?: [key: string, value: string | number][] | undefined;
|
||||
/** Members expected to be removed. */
|
||||
ignoredRemovals?: [key: string, value?: string | number | undefined][] | undefined;
|
||||
}
|
||||
|
||||
export type FindFunction<Args extends unknown[] = any[], Return = unknown>
|
||||
= (this: typeof Vencord, ...args: Args) =>
|
||||
Promise<Return | undefined> | Return | undefined;
|
||||
|
||||
export type DeclarationChanges = ClassChanges | EnumChanges;
|
||||
|
||||
interface DeclarationChangesBase {
|
||||
additions: object;
|
||||
removals: object;
|
||||
/** The number of added/removed members. */
|
||||
unchangedCount: number;
|
||||
/** The number of added/removed members. */
|
||||
changedCount: number;
|
||||
}
|
||||
|
||||
export interface ClassChanges extends DeclarationChangesBase {
|
||||
additions: ClassMembers;
|
||||
removals: ClassMembers;
|
||||
}
|
||||
|
||||
export interface ClassMembers {
|
||||
/** Whether the class has a constructor definition with parameters. */
|
||||
constructorDefinition: boolean;
|
||||
staticMethodsAndFields: string[];
|
||||
staticGetters: string[];
|
||||
staticSetters: string[];
|
||||
methods: string[];
|
||||
getters: string[];
|
||||
setters: string[];
|
||||
fields: string[];
|
||||
}
|
||||
|
||||
export interface Class {
|
||||
/** Constructor function */
|
||||
new (...args: never): unknown;
|
||||
/** Static members */
|
||||
[key: PropertyKey]: unknown;
|
||||
/** Instance methods and accessors */
|
||||
readonly prototype: Record<PropertyKey, unknown>;
|
||||
}
|
||||
|
||||
export interface EnumChanges extends DeclarationChangesBase {
|
||||
additions: EnumMembers;
|
||||
removals: EnumMembers;
|
||||
}
|
||||
|
||||
export type EnumMembers = Record<string, unknown>;
|
||||
|
||||
export type EnumSource = Record<string, number> | Record<string, string>;
|
||||
|
||||
/** Excludes heterogeneous enums. */
|
||||
export type Enum = NumericEnum | StringEnum;
|
||||
|
||||
/** Numeric enums have reverse mapping. */
|
||||
export type NumericEnum
|
||||
= { readonly [key: string]: number; }
|
||||
& { readonly [value: number]: string; };
|
||||
|
||||
/** String enums do not have reverse mapping. */
|
||||
export interface StringEnum {
|
||||
readonly [key: string]: string;
|
||||
}
|
||||
}
|
51
packages/discord-types/scripts/utils.mts
Normal file
51
packages/discord-types/scripts/utils.mts
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
type EnvConfig = Record<string, RegExp | [string, ...string[]] | [...string[], string] | boolean>;
|
||||
|
||||
type ValidEnv<Config extends EnvConfig> = NodeJS.ProcessEnv & {
|
||||
[Key in keyof Config as false extends Config[Key]
|
||||
? never
|
||||
: Key
|
||||
]: Config[Key] extends string[]
|
||||
? Config[Key][number]
|
||||
: string;
|
||||
} & Partial<Record<keyof Config, string>>;
|
||||
|
||||
export function assertEnvValidity<const Config extends EnvConfig>(
|
||||
env: NodeJS.ProcessEnv,
|
||||
config: Config
|
||||
): asserts env is ValidEnv<Config> {
|
||||
const errors: string[] = [];
|
||||
|
||||
for (const key in config) {
|
||||
const varValue = env[key];
|
||||
const varConfig = config[key]!;
|
||||
|
||||
if (varValue === undefined) {
|
||||
if (varConfig)
|
||||
errors.push(`TypeError: A value must be provided for required environment variable '${key}'.`);
|
||||
} else if (Array.isArray(varConfig)) {
|
||||
if (!varConfig.includes(varValue))
|
||||
errors.push(`RangeError: The value provided for environment variable '${key}' must be one of ${formatChoices(varConfig)}.`);
|
||||
} else if (typeof varConfig === "object" && !varConfig.test(varValue))
|
||||
errors.push(`RangeError: The value provided for environment variable '${key}' must match ${varConfig}.`);
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
for (const error of errors)
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function formatChoices(choices: string[]) {
|
||||
const quotedChoices = choices.map(c => `'${c}'`);
|
||||
if (choices.length < 3)
|
||||
return quotedChoices.join(" or ");
|
||||
const lastChoice = quotedChoices.pop()!;
|
||||
return quotedChoices.join(", ") + ", or " + lastChoice;
|
||||
}
|
70
packages/discord-types/src/flux/ActionHandlersGraph.ts
Normal file
70
packages/discord-types/src/flux/ActionHandlersGraph.ts
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { DepGraph } from "dependency-graph";
|
||||
|
||||
import type { IsAny, Nullish, UnionToIntersection } from "../internal";
|
||||
import type { Action, ActionHandler, ActionType, ExtractAction } from "./actions";
|
||||
import type { DispatchBand } from "./Dispatcher";
|
||||
|
||||
export declare class ActionHandlersGraph {
|
||||
_addToBand(dispatchToken: string, dispatchBand: DispatchBand): void;
|
||||
_bandToken(dispatchBand: DispatchBand): string;
|
||||
_computeOrderedActionHandlers<T extends ActionType>(
|
||||
actionType: T
|
||||
): OrderedActionHandlers<ExtractAction<Action, T>>[];
|
||||
_computeOrderedCallbackTokens(): string[];
|
||||
_invalidateCaches(): void;
|
||||
_validateDependencies(fromDispatchToken: string, toDispatchToken: string): void;
|
||||
addDependencies(fromDispatchToken: string, toDispatchTokens: readonly string[]): void;
|
||||
createToken(): string;
|
||||
getOrderedActionHandlers<T extends ActionType>(partialAction: {
|
||||
type: T;
|
||||
}): OrderedActionHandlers<ExtractAction<Action, T>>;
|
||||
register<A extends Action>(
|
||||
storeName: string,
|
||||
actionHandlers: ActionHandlerMap<A>,
|
||||
storeDidChange: ActionHandler<A>,
|
||||
dispatchBand: DispatchBand,
|
||||
dispatchToken?: string /* = this.createToken() */
|
||||
): string;
|
||||
|
||||
_dependencyGraph: DepGraph<ActionHandlersGraphNode>;
|
||||
_lastID: number;
|
||||
_orderedActionHandlers: {
|
||||
[T in ActionType]?: OrderedActionHandlers<ExtractAction<Action, T>> | Nullish;
|
||||
};
|
||||
_orderedCallbackTokens: string[] | Nullish;
|
||||
}
|
||||
|
||||
export interface ActionHandlersGraphNode {
|
||||
actionHandler: Partial<ActionHandlerMap>;
|
||||
band: DispatchBand;
|
||||
/** Store name */
|
||||
name: string;
|
||||
storeDidChange: ActionHandler;
|
||||
}
|
||||
|
||||
export type ActionHandlerMap<A extends Action = Action>
|
||||
// Workaround to avoid ts(2589)
|
||||
= UnionToIntersection<
|
||||
A extends unknown
|
||||
? unknown extends (
|
||||
IsAny<A[Extract<string, keyof A>]>
|
||||
& IsAny<A[Extract<number, keyof A>]>
|
||||
& IsAny<A[Extract<symbol, keyof A>]>
|
||||
)
|
||||
? Record<A["type"], (action: any) => void>
|
||||
: { [T in A["type"]]: (action: A & { type: T; }) => void; }
|
||||
: never
|
||||
>;
|
||||
|
||||
export type OrderedActionHandlers<A extends Action = Action> = {
|
||||
actionHandler: ActionHandler<A>;
|
||||
/** Store name */
|
||||
name: string;
|
||||
storeDidChange: ActionHandler<A>;
|
||||
}[];
|
30
packages/discord-types/src/flux/ActionLog.ts
Normal file
30
packages/discord-types/src/flux/ActionLog.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Action } from "./actions";
|
||||
|
||||
export declare class ActionLog<A extends Action = Action> {
|
||||
constructor(actionType: A["type"]);
|
||||
|
||||
get name(): A["type"];
|
||||
toJSON(): Pick<ActionLog<A>, "action" | "createdAt" | "traces"> & {
|
||||
created_at: ActionLog["createdAt"];
|
||||
};
|
||||
|
||||
action: A;
|
||||
createdAt: Date;
|
||||
error: Error | undefined;
|
||||
id: number;
|
||||
startTime: number;
|
||||
totalTime: number;
|
||||
traces: ActionLogTrace[];
|
||||
}
|
||||
|
||||
export interface ActionLogTrace {
|
||||
/** Store name */
|
||||
name: string;
|
||||
time: number;
|
||||
}
|
30
packages/discord-types/src/flux/ActionLogger.ts
Normal file
30
packages/discord-types/src/flux/ActionLogger.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { EventEmitter } from "events";
|
||||
|
||||
import type { ActionLog } from "./ActionLog";
|
||||
import type { Action, ActionType } from "./actions";
|
||||
|
||||
export declare class ActionLogger extends EventEmitter {
|
||||
constructor(options?: { persist?: boolean | undefined; });
|
||||
|
||||
getLastActionMetrics(title: string, limit?: number /* = 20 */): ActionMetric[];
|
||||
getSlowestActions<T extends ActionType = ActionType>(
|
||||
actionType?: T | null,
|
||||
limit?: number /* = 20 */
|
||||
): ActionMetric<T>[];
|
||||
log<A extends Action>(
|
||||
action: A,
|
||||
callback: (func: <T>(storeName: string, func: () => T) => T) => void
|
||||
): ActionLog<A>;
|
||||
|
||||
logs: ActionLog[];
|
||||
persist: boolean;
|
||||
}
|
||||
|
||||
export type ActionMetric<T extends ActionType = ActionType>
|
||||
= [storeName: string, actionType: T, totalTime: number];
|
20
packages/discord-types/src/flux/BatchedStoreListener.ts
Normal file
20
packages/discord-types/src/flux/BatchedStoreListener.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Stringable } from "../internal";
|
||||
import type { Store } from "./Store";
|
||||
|
||||
export declare class BatchedStoreListener {
|
||||
constructor(stores: Store[], changeCallback: () => void);
|
||||
|
||||
attach(debugName?: Stringable): void;
|
||||
detach(): void;
|
||||
|
||||
changeCallback: () => void;
|
||||
handleStoreChange: () => void;
|
||||
stores: Store[];
|
||||
storeVersionHandled: number | undefined;
|
||||
}
|
27
packages/discord-types/src/flux/ChangeListeners.ts
Normal file
27
packages/discord-types/src/flux/ChangeListeners.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export declare class ChangeListeners {
|
||||
has(listener: ChangeListener): boolean;
|
||||
hasAny(): boolean;
|
||||
invokeAll(): void;
|
||||
|
||||
add: (listener: ChangeListener<false>) => void;
|
||||
/**
|
||||
* @param listener The change listener to add. It will be removed when it returns false.
|
||||
*/
|
||||
addConditional: (
|
||||
listener: ChangeListener<true>,
|
||||
immediatelyCall?: boolean /* = true */
|
||||
) => void;
|
||||
listeners: Set<ChangeListener>;
|
||||
remove: (listener: ChangeListener) => void;
|
||||
}
|
||||
|
||||
export type ChangeListener<Conditional extends boolean = boolean>
|
||||
= true extends Conditional
|
||||
? () => unknown
|
||||
: () => void;
|
87
packages/discord-types/src/flux/Dispatcher.ts
Normal file
87
packages/discord-types/src/flux/Dispatcher.ts
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Nullish } from "../internal";
|
||||
import type { ActionHandlerMap, ActionHandlersGraph } from "./ActionHandlersGraph";
|
||||
import type { ActionLogger } from "./ActionLogger";
|
||||
import type { Action, ActionHandler, ActionType, ExtractAction } from "./actions";
|
||||
|
||||
export declare class Dispatcher {
|
||||
constructor(
|
||||
defaultBand?: DispatchBand /* = DispatchBand.EARLY */,
|
||||
actionLogger?: ActionLogger | null,
|
||||
sentryUtils?: SentryUtils | null
|
||||
);
|
||||
|
||||
_dispatch(
|
||||
action: Action,
|
||||
func: <T>(storeName: string, func: () => T) => T
|
||||
): boolean | undefined;
|
||||
_dispatchWithDevtools(action: Action): void;
|
||||
_dispatchWithLogging(action: Action): void;
|
||||
addDependencies(fromDispatchToken: string, toDispatchTokens: readonly string[]): void;
|
||||
addInterceptor(interceptor: ActionHandler): void;
|
||||
createToken(): string;
|
||||
dispatch(action: Action): Promise<void>;
|
||||
flushWaitQueue(): void;
|
||||
isDispatching(): boolean;
|
||||
register<A extends Action>(
|
||||
storeName: string,
|
||||
actionHandlers: ActionHandlerMap<A>,
|
||||
storeDidChange: ActionHandler<A>,
|
||||
dispatchBand?: DispatchBand | null, /* = this._defaultBand */
|
||||
dispatchToken?: string /* = this._actionHandlers.createToken() */
|
||||
): string;
|
||||
subscribe<T extends ActionType>(
|
||||
actionType: T,
|
||||
listener: ActionHandler<ExtractAction<Action, T>>): void;
|
||||
unsubscribe<T extends ActionType>(
|
||||
actionType: T,
|
||||
listener: ActionHandler<ExtractAction<Action, T>>
|
||||
): void;
|
||||
wait(callback: () => void): void;
|
||||
|
||||
_actionHandlers: ActionHandlersGraph;
|
||||
_currentDispatchActionType: ActionType | Nullish;
|
||||
_defaultBand: DispatchBand;
|
||||
_interceptors: ((action: Action) => boolean)[];
|
||||
_processingWaitQueue: boolean;
|
||||
_sentryUtils: SentryUtils | Nullish;
|
||||
_subscriptions: {
|
||||
[T in ActionType]?: Set<ActionHandler<ExtractAction<Action, T>>> | Nullish;
|
||||
};
|
||||
_waitQueue: (() => void)[];
|
||||
actionLogger: ActionLogger;
|
||||
functionCache: Partial<ActionHandlerMap>;
|
||||
}
|
||||
|
||||
// Enum keys made screaming snake case for consistency.
|
||||
export enum DispatchBand {
|
||||
EARLY = 0,
|
||||
DATABASE = 1,
|
||||
DEFAULT = 2,
|
||||
}
|
||||
|
||||
export interface SentryUtils {
|
||||
addBreadcrumb: (breadcrumb: {
|
||||
category?: string | undefined;
|
||||
data?: Record<string, unknown> | undefined;
|
||||
event_id?: string | undefined;
|
||||
level?: SeverityLevel | undefined;
|
||||
message?: string | undefined;
|
||||
timestamp?: number | undefined;
|
||||
type?: string | undefined;
|
||||
}) => void;
|
||||
}
|
||||
|
||||
export enum SeverityLevel {
|
||||
DEBUG = "debug",
|
||||
ERROR = "error",
|
||||
FATAL = "fatal",
|
||||
INFO = "info",
|
||||
LOG = "log",
|
||||
WARNING = "warning",
|
||||
}
|
30
packages/discord-types/src/flux/Emitter.ts
Normal file
30
packages/discord-types/src/flux/Emitter.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Store } from "./Store";
|
||||
|
||||
export declare class Emitter {
|
||||
batched<T>(callback: () => T): T;
|
||||
destroy(): void;
|
||||
emit(): void;
|
||||
emitNonReactOnce(syncWiths: Set<() => unknown>, changedStores: Set<Store>): void;
|
||||
emitReactOnce(): void;
|
||||
getChangeSentinel(): number;
|
||||
getIsPaused(): boolean;
|
||||
injectBatchEmitChanges(batchEmitChanges: () => unknown): void;
|
||||
markChanged(store: Store): void;
|
||||
/** If timeout is omitted, Emitter will pause until resume is called. */
|
||||
pause(timeout?: number): void;
|
||||
resume(shouldEmit?: boolean /* = true */): void;
|
||||
|
||||
changedStores: Set<Store>;
|
||||
changeSentinel: number;
|
||||
isBatchEmitting: boolean;
|
||||
isDispatching: boolean;
|
||||
isPaused: boolean;
|
||||
pauseTimer: number | null;
|
||||
reactChangedStores: Set<Store>;
|
||||
}
|
108
packages/discord-types/src/flux/PersistedStore.ts
Normal file
108
packages/discord-types/src/flux/PersistedStore.ts
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { GenericConstructor, Nullish } from "../internal";
|
||||
import type { ActionHandlerMap } from "./ActionHandlersGraph";
|
||||
import type { Dispatcher } from "./Dispatcher";
|
||||
import type { Store } from "./Store";
|
||||
|
||||
export declare abstract class PersistedStore<
|
||||
Constructor extends GenericConstructor = GenericConstructor,
|
||||
State = unknown
|
||||
> extends Store {
|
||||
constructor(dispatcher: Dispatcher, actionHandlers: Partial<ActionHandlerMap>);
|
||||
|
||||
static _clearAllPromise: Promise<void> | Nullish;
|
||||
static _writePromises: Map</* persistKey: */string, Promise<void>>;
|
||||
static _writeResolvers: Map</* persistKey: */string, [resolver: () => void, callbackId: number]>;
|
||||
static allPersistKeys: Set<string>;
|
||||
static clearAll(options: PersistedStoreClearOptions): Promise<void>;
|
||||
static clearPersistQueue(options: PersistedStoreClearOptions): void;
|
||||
static disableWrite: boolean;
|
||||
static disableWrites: boolean;
|
||||
static getAllStates(): Promise<{ [persistKey: string]: unknown; }>;
|
||||
static initializeAll(stateMap: { [persistKey: string]: unknown; } & Pick<Object, "hasOwnProperty">): void;
|
||||
/**
|
||||
* If {@link clearAll} has been called for the specified persist key, state in the returned object will be undefined.
|
||||
*/
|
||||
static migrateAndReadStoreState<
|
||||
States extends readonly [unknown, ...unknown[]] | readonly [...unknown[], unknown] = [unknown]
|
||||
>(
|
||||
persistKey: string,
|
||||
...migrations: [] extends PersistedStoreMigrations<States>
|
||||
? [migrations?: PersistedStoreMigrations<States> | null]
|
||||
: [migrations: PersistedStoreMigrations<States>]
|
||||
): { requiresPersist: true; state: Tail<States>; } | { requiresPersist: false; state: undefined; };
|
||||
static migrations: ((oldState: never) => unknown)[] | undefined;
|
||||
/**
|
||||
* Not present on {@link PersistedStore}'s constructor.
|
||||
* All subclasses are required to define their own.
|
||||
*/
|
||||
static persistKey: string;
|
||||
static shouldClear(options: PersistedStoreClearOptions, persistKey: string): boolean;
|
||||
static throttleDelay: number;
|
||||
static userAgnosticPersistKeys: Set<string>;
|
||||
|
||||
asyncPersist(): Promise<boolean | undefined>;
|
||||
clear(): void;
|
||||
getClass(): Constructor;
|
||||
abstract getState(): State;
|
||||
abstract initialize(state: State): void;
|
||||
initializeFromState(state: State): void;
|
||||
persist(): void;
|
||||
|
||||
_version: number;
|
||||
callback: (callback: () => void) => void;
|
||||
throttledCallback: {
|
||||
(callback: () => void): () => void;
|
||||
cancel: () => void;
|
||||
flush: () => () => void;
|
||||
};
|
||||
}
|
||||
|
||||
export interface PersistedStoreClearOptions {
|
||||
/** Array of persist keys */
|
||||
omit?: readonly string[] | Nullish;
|
||||
type: "all" | "user-data-only";
|
||||
}
|
||||
|
||||
export type PersistedStoreMigrations<
|
||||
States extends readonly [unknown, ...unknown[]] | readonly [...unknown[], unknown]
|
||||
>
|
||||
= States extends readonly [...infer OldStates, infer NewState]
|
||||
? OldStates extends [...infer OlderStates, infer OldState]
|
||||
? [...PersistedStoreMigrations<[...OlderStates, OldState]>, (oldState: OldState) => NewState]
|
||||
: OldStates extends []
|
||||
? []
|
||||
: OldStates extends (infer T)[]
|
||||
? [] | [...((oldState: T) => T)[], (oldState: T) => NewState]
|
||||
: never
|
||||
: PersistedStoreMigrationsTrailingRest<States>;
|
||||
|
||||
type PersistedStoreMigrationsTrailingRest<States extends readonly unknown[]>
|
||||
= States extends readonly [infer OldState, ...infer NewStates]
|
||||
? NewStates extends [infer NewState, ...infer NewerStates]
|
||||
? [(oldState: OldState) => NewState, ...PersistedStoreMigrationsTrailingRest<[NewState, ...NewerStates]>]
|
||||
: NewStates extends []
|
||||
? []
|
||||
: NewStates extends (infer T)[]
|
||||
? [] | [(oldState: OldState) => T, ...((oldState: T) => T)[]]
|
||||
: never
|
||||
: never;
|
||||
|
||||
type Tail<T extends readonly [unknown, ...unknown[]] | readonly [...unknown[], unknown]>
|
||||
= T extends readonly [...unknown[], infer U]
|
||||
? U
|
||||
: TailTrailingRest<T>;
|
||||
|
||||
type TailTrailingRest<T extends readonly unknown[]>
|
||||
= T extends readonly [infer U, ...infer V]
|
||||
? V extends [unknown, ...unknown[]]
|
||||
? TailTrailingRest<V>
|
||||
: V extends (infer W)[]
|
||||
? U | W
|
||||
: never
|
||||
: never;
|
39
packages/discord-types/src/flux/SnapshotStore.ts
Normal file
39
packages/discord-types/src/flux/SnapshotStore.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { GenericConstructor } from "../internal";
|
||||
import type { ActionHandlerMap } from "./ActionHandlersGraph";
|
||||
import type { Store } from "./Store";
|
||||
|
||||
export interface SnapshotStoreSnapshot<SnapshotData = unknown> {
|
||||
data: SnapshotData;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export declare abstract class SnapshotStore<
|
||||
Constructor extends GenericConstructor = GenericConstructor,
|
||||
SnapshotData = unknown
|
||||
> extends Store {
|
||||
constructor(
|
||||
actionHandlers: Partial<ActionHandlerMap>
|
||||
& Partial<Record<"CLEAR_CACHES" | "WRITE_CACHES", never>>
|
||||
);
|
||||
|
||||
static allStores: SnapshotStore[];
|
||||
static clearAll(): void;
|
||||
/**
|
||||
* Not present on {@link SnapshotStore}'s constructor.
|
||||
* All subclasses are required to define their own.
|
||||
*/
|
||||
static displayName: string;
|
||||
|
||||
clear(): void;
|
||||
getClass(): Constructor;
|
||||
get persistKey(): string;
|
||||
readSnapshot(version: number): SnapshotData | null;
|
||||
save(): void;
|
||||
abstract takeSnapshot(): SnapshotStoreSnapshot<SnapshotData>;
|
||||
}
|
65
packages/discord-types/src/flux/Store.ts
Normal file
65
packages/discord-types/src/flux/Store.ts
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Nullish } from "../internal";
|
||||
import type { ActionHandlerMap } from "./ActionHandlersGraph";
|
||||
import type { Action } from "./actions";
|
||||
import type { ChangeListeners } from "./ChangeListeners";
|
||||
import type { DispatchBand, Dispatcher } from "./Dispatcher";
|
||||
|
||||
export declare abstract class Store {
|
||||
constructor(
|
||||
dispatcher: Dispatcher,
|
||||
actionHandlers?: Partial<ActionHandlerMap> | null,
|
||||
dispatchBand?: DispatchBand | null /* = dispatcher._defaultBand */
|
||||
);
|
||||
|
||||
static destroy(): void;
|
||||
/** Undefined on {@link Store}'s constructor. */
|
||||
static displayName: string | undefined;
|
||||
static getAll(): Store[];
|
||||
static initialize(): void;
|
||||
static initialized: Promise<void>;
|
||||
|
||||
emitChange(): void;
|
||||
getDispatchToken(): string;
|
||||
getName(): string;
|
||||
initialize(...args: never[]): void;
|
||||
initializeIfNeeded(): void;
|
||||
mustEmitChanges(
|
||||
mustEmitChanges?: ((action: Action) => boolean) | null /* = () => true */
|
||||
): void;
|
||||
registerActionHandlers(
|
||||
actionHandlers: Partial<ActionHandlerMap>,
|
||||
dispatchBand?: DispatchBand | null /* = this._dispatcher._defaultBand */
|
||||
): void;
|
||||
syncWith(
|
||||
stores: readonly Store[],
|
||||
func: () => unknown,
|
||||
timeout?: number | null
|
||||
): void;
|
||||
waitFor(...stores: Store[]): void;
|
||||
|
||||
__getLocalVars: undefined;
|
||||
_changeCallbacks: ChangeListeners;
|
||||
_dispatcher: Dispatcher;
|
||||
_dispatchToken: string;
|
||||
_isInitialized: boolean;
|
||||
_mustEmitChanges: ((action: Action) => boolean) | Nullish;
|
||||
_reactChangeCallbacks: ChangeListeners;
|
||||
_syncWiths: {
|
||||
func: () => unknown;
|
||||
store: Store;
|
||||
}[];
|
||||
addChangeListener: ChangeListeners["add"];
|
||||
/**
|
||||
* @param listener The change listener to add. It will be removed when it returns false.
|
||||
*/
|
||||
addConditionalChangeListener: ChangeListeners["addConditional"];
|
||||
addReactChangeListener: ChangeListeners["add"];
|
||||
removeChangeListener: ChangeListeners["remove"];
|
||||
removeReactChangeListener: ChangeListeners["remove"];
|
||||
}
|
15
packages/discord-types/src/flux/UserAgnosticStore.ts
Normal file
15
packages/discord-types/src/flux/UserAgnosticStore.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { GenericConstructor } from "../internal";
|
||||
import type { PersistedStore } from "./PersistedStore";
|
||||
|
||||
export declare abstract class UserAgnosticStore<
|
||||
Constructor extends GenericConstructor = GenericConstructor,
|
||||
State = unknown
|
||||
> extends PersistedStore<Constructor, State> {
|
||||
abstract getUserAgnosticState(): State;
|
||||
}
|
145
packages/discord-types/src/flux/actions.ts
Normal file
145
packages/discord-types/src/flux/actions.ts
Normal file
File diff suppressed because one or more lines are too long
51
packages/discord-types/src/flux/index.ts
Normal file
51
packages/discord-types/src/flux/index.ts
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { ComponentClass, ElementType, ForwardRefExoticComponent } from "react";
|
||||
|
||||
import type { Subtract } from "../internal";
|
||||
import type { Emitter } from "./Emitter";
|
||||
import type { PersistedStore } from "./PersistedStore";
|
||||
import type { Store } from "./Store";
|
||||
import type { UserAgnosticStore } from "./UserAgnosticStore";
|
||||
|
||||
export * from "./ActionHandlersGraph";
|
||||
export * from "./ActionLog";
|
||||
export * from "./ActionLogger";
|
||||
export * from "./actions";
|
||||
export * from "./BatchedStoreListener";
|
||||
export * from "./ChangeListeners";
|
||||
export * from "./Dispatcher";
|
||||
export * from "./Emitter";
|
||||
export * from "./PersistedStore";
|
||||
export * from "./SnapshotStore";
|
||||
export * from "./Store";
|
||||
export * from "./UserAgnosticStore";
|
||||
export * from "./utils";
|
||||
|
||||
export interface Flux {
|
||||
get initialized(): typeof Store["initialized"];
|
||||
|
||||
connectStores: <
|
||||
Props extends {},
|
||||
State extends {},
|
||||
ForwardRef extends boolean | undefined = undefined
|
||||
>(
|
||||
stores: Store[],
|
||||
getStateFromStores: (props: Props) => State,
|
||||
options?: {
|
||||
forwardRef?: ForwardRef /* = false */;
|
||||
} | null
|
||||
) => <P extends Props & State>(type: ElementType<P>) => ForwardRef extends true
|
||||
? ForwardRefExoticComponent<Subtract<P, State> & Props>
|
||||
: ComponentClass<Subtract<P, State> & Props>;
|
||||
DeviceSettingsStore: typeof UserAgnosticStore;
|
||||
Emitter: Emitter;
|
||||
initialize: typeof Store["initialize"];
|
||||
OfflineCacheStore: typeof UserAgnosticStore;
|
||||
PersistedStore: typeof PersistedStore;
|
||||
Store: typeof Store;
|
||||
}
|
79
packages/discord-types/src/flux/utils.ts
Normal file
79
packages/discord-types/src/flux/utils.ts
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Nullish } from "../internal";
|
||||
import type { Store } from "./Store";
|
||||
|
||||
// For createFetchStore
|
||||
export type FetchStoreFactory<
|
||||
StoreConstraint extends Store = Store,
|
||||
StateConstraint = unknown,
|
||||
DependenciesConstraint extends readonly unknown[] = readonly unknown[],
|
||||
IsLoadingConstraint extends boolean = boolean
|
||||
> = <
|
||||
S extends StoreConstraint,
|
||||
State extends StateConstraint,
|
||||
Dependencies extends DependenciesConstraint,
|
||||
IsLoading extends IsLoadingConstraint
|
||||
>(
|
||||
store: S,
|
||||
options: {
|
||||
dangerousAbortOnCleanup?: boolean | undefined /* = false */;
|
||||
get: (...dependencies: Dependencies) => State;
|
||||
getIsLoading: (...dependencies: Dependencies) => IsLoading;
|
||||
load: (signal: AbortSignal, ...dependencies: Dependencies) => Promise<void>;
|
||||
useStateHook: StoreStateHook<[S], State, Dependencies>;
|
||||
}
|
||||
) => (...dependencies: Dependencies) => {
|
||||
data: State;
|
||||
error: unknown;
|
||||
isLoading: IsLoading;
|
||||
};
|
||||
|
||||
// For useStateFromStores
|
||||
export type StoreStateHook<
|
||||
Stores extends readonly Store[] = readonly Store[],
|
||||
StateConstraint = unknown,
|
||||
Dependencies extends readonly unknown[] | Nullish = readonly unknown[] | Nullish
|
||||
> = <State extends StateConstraint>(
|
||||
stores: Stores,
|
||||
getStateFromStores: () => State,
|
||||
...args: [
|
||||
...undefined extends Dependencies
|
||||
? [dependencies?: Dependencies]
|
||||
: [dependencies: Dependencies],
|
||||
areStatesEqual?: ((prevState: State, nextState: State) => boolean) | undefined
|
||||
]
|
||||
) => State;
|
||||
|
||||
// For useStateFromStoresObject
|
||||
export type StoreObjectStateHook<
|
||||
Stores extends readonly Store[] = readonly Store[],
|
||||
StateConstraint extends {} = {},
|
||||
Dependencies extends readonly unknown[] | Nullish = readonly unknown[] | Nullish
|
||||
> = <State extends StateConstraint>(
|
||||
stores: Stores,
|
||||
getStateFromStores: () => State,
|
||||
...dependencies: undefined extends Dependencies
|
||||
? [dependencies?: Dependencies]
|
||||
: [dependencies: Dependencies]
|
||||
) => State;
|
||||
|
||||
// For useStateFromStoresArray
|
||||
export type StoreArrayStateHook<
|
||||
Stores extends readonly Store[] = readonly Store[],
|
||||
StateConstraint extends readonly unknown[] = readonly unknown[],
|
||||
Dependencies extends readonly unknown[] | Nullish = readonly unknown[] | Nullish
|
||||
> = <State extends StateConstraint>(
|
||||
stores: Stores,
|
||||
getStateFromStores: () => State,
|
||||
...dependencies: undefined extends Dependencies
|
||||
? [dependencies?: Dependencies]
|
||||
: [dependencies: Dependencies]
|
||||
) => State;
|
||||
|
||||
// For statesWillNeverBeEqual
|
||||
export type UnequatableStateComparator = () => false;
|
95
packages/discord-types/src/general/Activity.ts
Normal file
95
packages/discord-types/src/general/Activity.ts
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
/** @todo May have more properties. */
|
||||
export interface Activity {
|
||||
application_id?: string | number;
|
||||
assets?: ActivityAssets;
|
||||
buttons?: string[];
|
||||
created_at: number;
|
||||
details?: string;
|
||||
emoji?: ActivityEmoji;
|
||||
flags?: ActivityFlags;
|
||||
id: string;
|
||||
metadata?: Record<string, any>;
|
||||
name: string;
|
||||
party?: ActivityParty;
|
||||
platform?: ActivityGamePlatform;
|
||||
session_id?: string;
|
||||
state?: string;
|
||||
supported_platforms?: ActivityPlatform[];
|
||||
sync_id?: string;
|
||||
timestamps?: ActivityTimestamps;
|
||||
type: ActivityType;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
export interface ActivityAssets {
|
||||
large_image?: string;
|
||||
large_text?: string;
|
||||
small_image?: string;
|
||||
small_text?: string;
|
||||
}
|
||||
|
||||
export type ActivityEmoji = ActivityUnicodeEmoji | ActivityGuildEmoji;
|
||||
|
||||
export interface ActivityUnicodeEmoji {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface ActivityGuildEmoji {
|
||||
animated: boolean;
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export enum ActivityFlags {
|
||||
INSTANCE = 1 << 0,
|
||||
JOIN = 1 << 1,
|
||||
SYNC = 1 << 4,
|
||||
PLAY = 1 << 5,
|
||||
PARTY_PRIVACY_FRIENDS = 1 << 6,
|
||||
PARTY_PRIVACY_VOICE_CHANNEL = 1 << 7,
|
||||
EMBEDDED = 1 << 8,
|
||||
}
|
||||
|
||||
export interface ActivityParty {
|
||||
id?: string;
|
||||
size?: [minimumSize: number, maximumSize: number];
|
||||
}
|
||||
|
||||
// Original name: ActivityGamePlatforms
|
||||
export enum ActivityGamePlatform {
|
||||
ANDROID = "android",
|
||||
DESKTOP = "desktop",
|
||||
EMBEDDED = "embedded",
|
||||
IOS = "ios",
|
||||
PS4 = "ps4",
|
||||
PS5 = "ps5",
|
||||
SAMSUNG = "samsung",
|
||||
XBOX = "xbox",
|
||||
}
|
||||
|
||||
export enum ActivityPlatform {
|
||||
DESKTOP = "desktop",
|
||||
MOBILE = "mobile",
|
||||
}
|
||||
|
||||
export interface ActivityTimestamps {
|
||||
end?: number;
|
||||
start?: number;
|
||||
}
|
||||
|
||||
// Original name: ActivityTypes
|
||||
export enum ActivityType {
|
||||
PLAYING = 0,
|
||||
STREAMING = 1,
|
||||
LISTENING = 2,
|
||||
WATCHING = 3,
|
||||
CUSTOM_STATUS = 4,
|
||||
COMPETING = 5,
|
||||
HANG_STATUS = 6,
|
||||
}
|
140
packages/discord-types/src/general/ApplicationCommand.ts
Normal file
140
packages/discord-types/src/general/ApplicationCommand.ts
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { ApplicationIntegrationType } from "./ApplicationRecord";
|
||||
import type { ChannelType } from "./channels/ChannelRecord";
|
||||
|
||||
export type ApplicationCommand<CommandType extends ApplicationCommandType = ApplicationCommandType> = {
|
||||
application_id: string;
|
||||
contexts?: InteractionContextType[] | null;
|
||||
/** Permissions serialized as a string. */
|
||||
default_member_permissions: string | null;
|
||||
default_permission?: boolean | null;
|
||||
description: CommandType extends ApplicationCommandType.CHAT ? string : "";
|
||||
description_localizations?: { [locale: string]: string; } | null;
|
||||
dm_permission?: boolean;
|
||||
guild_id?: string;
|
||||
id: string;
|
||||
integration_types?: ApplicationIntegrationType[];
|
||||
name: string;
|
||||
name_localizations?: { [locale: string]: string; } | null;
|
||||
nsfw?: boolean;
|
||||
type?: ApplicationCommandType;
|
||||
version: string;
|
||||
} & (CommandType extends ApplicationCommandType.CHAT ? { options?: ApplicationCommandOption[]; } : {});
|
||||
|
||||
export enum InteractionContextType {
|
||||
GUILD = 0,
|
||||
BOT_DM = 1,
|
||||
PRIVATE_CHANNEL = 2,
|
||||
}
|
||||
|
||||
export enum ApplicationCommandType {
|
||||
CHAT = 1,
|
||||
USER = 2,
|
||||
MESSAGE = 3,
|
||||
PRIMARY_ENTRY_POINT = 4,
|
||||
}
|
||||
|
||||
export type ApplicationCommandOption = ApplicationCommandSubcommandOption | ApplicationCommandSubcommandGroupOption | ApplicationCommandNonSubOption;
|
||||
|
||||
export interface ApplicationCommandOptionBase extends Pick<ApplicationCommand, "description" | "description_localizations" | "name" | "name_localizations"> {
|
||||
type: ApplicationCommandOptionType;
|
||||
}
|
||||
|
||||
export interface ApplicationCommandSubcommandOption extends ApplicationCommandOptionBase {
|
||||
options?: ApplicationCommandNonSubOption[];
|
||||
type: ApplicationCommandOptionType.SUB_COMMAND;
|
||||
}
|
||||
|
||||
export interface ApplicationCommandSubcommandGroupOption extends ApplicationCommandOptionBase {
|
||||
options?: ApplicationCommandOption[];
|
||||
type: ApplicationCommandOptionType.SUB_COMMAND;
|
||||
}
|
||||
|
||||
export type ApplicationCommandNonSubOption = ApplicationCommandChoicesOption | ApplicationCommandBooleanOption | ApplicationCommandUserOption | ApplicationCommandChannelOption | ApplicationCommandRoleOption | ApplicationCommandMentionableOption | ApplicationCommandAttachmentOption;
|
||||
|
||||
export interface ApplicationCommandNonSubOptionBase extends ApplicationCommandOptionBase {
|
||||
required?: boolean;
|
||||
}
|
||||
|
||||
type ApplicationCommandChoiceOptionType = ApplicationCommandOptionType.STRING | ApplicationCommandOptionType.INTEGER | ApplicationCommandOptionType.NUMBER;
|
||||
|
||||
export type ApplicationCommandChoicesOption = ApplicationCommandStringOption | ApplicationCommandNumericOption;
|
||||
|
||||
export type ApplicationCommandChoicesOptionBase = ApplicationCommandNonSubOptionBase
|
||||
& { type: ApplicationCommandChoiceOptionType; }
|
||||
& ({ autocomplete?: false; choice: ApplicationCommandOptionChoice[]; }
|
||||
| { autocomplete?: boolean; });
|
||||
|
||||
export interface ApplicationCommandOptionChoice<
|
||||
OptionType extends ApplicationCommandChoiceOptionType = ApplicationCommandChoiceOptionType
|
||||
> extends Pick<ApplicationCommand, "name" | "name_localizations"> {
|
||||
value: OptionType extends ApplicationCommandOptionType.STRING ? string
|
||||
: OptionType extends ApplicationCommandOptionType.INTEGER | ApplicationCommandOptionType.NUMBER ? number
|
||||
: never;
|
||||
}
|
||||
|
||||
export type ApplicationCommandStringOption = ApplicationCommandChoicesOptionBase & {
|
||||
max_length?: number;
|
||||
min_length?: number;
|
||||
type: ApplicationCommandOptionType.STRING;
|
||||
};
|
||||
|
||||
export type ApplicationCommandNumericOption = ApplicationCommandIntegerOption | ApplicationCommandNumberOption;
|
||||
|
||||
export type ApplicationCommandNumericOptionBase = ApplicationCommandChoicesOptionBase & {
|
||||
max_value?: number;
|
||||
min_value?: number;
|
||||
type: ApplicationCommandOptionType.INTEGER | ApplicationCommandOptionType.NUMBER;
|
||||
};
|
||||
|
||||
export type ApplicationCommandIntegerOption = ApplicationCommandNumericOptionBase & {
|
||||
type: ApplicationCommandOptionType.INTEGER;
|
||||
};
|
||||
|
||||
export type ApplicationCommandNumberOption = ApplicationCommandNumericOptionBase & {
|
||||
type: ApplicationCommandOptionType.NUMBER;
|
||||
};
|
||||
|
||||
export interface ApplicationCommandBooleanOption extends ApplicationCommandNonSubOptionBase {
|
||||
type: ApplicationCommandOptionType.BOOLEAN;
|
||||
}
|
||||
|
||||
export interface ApplicationCommandUserOption extends ApplicationCommandNonSubOptionBase {
|
||||
type: ApplicationCommandOptionType.USER;
|
||||
}
|
||||
|
||||
export interface ApplicationCommandChannelOption extends ApplicationCommandNonSubOptionBase {
|
||||
channel_types?: ChannelType[];
|
||||
type: ApplicationCommandOptionType.CHANNEL;
|
||||
}
|
||||
|
||||
export interface ApplicationCommandRoleOption extends ApplicationCommandNonSubOptionBase {
|
||||
type: ApplicationCommandOptionType.ROLE;
|
||||
}
|
||||
|
||||
export interface ApplicationCommandMentionableOption extends ApplicationCommandNonSubOptionBase {
|
||||
type: ApplicationCommandOptionType.MENTIONABLE;
|
||||
}
|
||||
|
||||
export interface ApplicationCommandAttachmentOption extends ApplicationCommandNonSubOptionBase {
|
||||
type: ApplicationCommandOptionType.ATTACHMENT;
|
||||
}
|
||||
|
||||
export enum ApplicationCommandOptionType {
|
||||
SUB_COMMAND = 1,
|
||||
SUB_COMMAND_GROUP = 2,
|
||||
STRING = 3,
|
||||
INTEGER = 4,
|
||||
BOOLEAN = 5,
|
||||
USER = 6,
|
||||
CHANNEL = 7,
|
||||
ROLE = 8,
|
||||
MENTIONABLE = 9,
|
||||
NUMBER = 10,
|
||||
ATTACHMENT = 11,
|
||||
}
|
217
packages/discord-types/src/general/ApplicationRecord.ts
Normal file
217
packages/discord-types/src/general/ApplicationRecord.ts
Normal file
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Nullish, Optional, PartialOnUndefined, SnakeCasedProperties } from "../internal";
|
||||
import type { CompanyRecord } from "./CompanyRecord";
|
||||
import type { IconSource } from "./misc";
|
||||
import type { RecordBase } from "./Record";
|
||||
import type { UserRecord } from "./UserRecord";
|
||||
|
||||
export type ApplicationRecordOwnProperties = Pick<ApplicationRecord, "aliases" | "bot" | "coverImage" | "customInstallUrl" | "description" | "developers" | "embeddedActivityConfig" | "eulaId" | "executables" | "flags" | "guild" | "guildId" | "hashes" | "hook" | "icon" | "id" | "installParams" | "integrationTypesConfig" | "isMonetized" | "isVerified" | "maxParticipants" | "name" | "overlay" | "overlayCompatibilityHook" | "overlayMethods" | "overlayWarn" | "primarySkuId" | "privacyPolicyUrl" | "publishers" | "roleConnectionsVerificationUrl" | "slug" | "splash" | "storefront_available" | "storeListingSkuId" | "tags" | "team" | "termsOfServiceUrl" | "thirdPartySkus" | "type">;
|
||||
|
||||
export type ApplicationProperties = Optional<PartialOnUndefined<Omit<ApplicationRecordOwnProperties, "customInstallUrl" | "embeddedActivityConfig" | "executables" | "installParams" | "isMonetized" | "isVerified">>, Nullish, "id" | "integrationTypesConfig" | "maxParticipants" | "name" | "primarySkuId" | "privacyPolicyUrl" | "roleConnectionsVerificationUrl" | "storefront_available" | "storeListingSkuId" | "team" | "termsOfServiceUrl" | "type", true>
|
||||
& SnakeCasedProperties<PartialOnUndefined<Pick<ApplicationRecordOwnProperties, "customInstallUrl" | "embeddedActivityConfig" | "installParams" | "isMonetized" | "isVerified">>>
|
||||
& { executables: Readonly<ApplicationRecord["executables"]>; };
|
||||
|
||||
export declare class ApplicationRecord<
|
||||
OwnProperties extends ApplicationRecordOwnProperties = ApplicationRecordOwnProperties
|
||||
> extends RecordBase<OwnProperties> {
|
||||
constructor(applicationProperties: ApplicationProperties);
|
||||
|
||||
/** @todo */
|
||||
static createFromServer(applicationFromServer: Record<string, any>): ApplicationRecord;
|
||||
static supportsOutOfProcessOverlay(overlayMethods?: ApplicationOverlayMethodFlags | null): boolean;
|
||||
|
||||
get destinationSkuId(): string | undefined;
|
||||
getCoverImageURL(imageSize?: number): string | null;
|
||||
getIconSource(iconSize?: number, iconFormat?: string | null): IconSource | null;
|
||||
getIconURL(iconSize?: number, iconFormat?: string | null): string | null;
|
||||
getMaxParticipants(): number;
|
||||
getSplashURL(splashSize?: number, splashFormat?: string | null): string | null;
|
||||
supportsIntegrationTypes(...integrationTypes: ApplicationIntegrationType[]): boolean;
|
||||
get supportsOutOfProcessOverlay(): boolean;
|
||||
|
||||
aliases: string[];
|
||||
bot: UserRecord | null;
|
||||
coverImage: string | null;
|
||||
customInstallUrl: string | undefined;
|
||||
description: string | null;
|
||||
developers: CompanyRecord[];
|
||||
embeddedActivityConfig: EmbeddedActivityConfig | undefined;
|
||||
eulaId: string | null;
|
||||
executables: ApplicationExecutable[];
|
||||
flags: ApplicationFlags;
|
||||
/** @todo This is not a GuildRecord; it is a guild object from the API. */
|
||||
guild: Record<string, any> | null;
|
||||
guildId: string | null;
|
||||
hashes: string[];
|
||||
hook: boolean;
|
||||
icon: string | null;
|
||||
id: string;
|
||||
installParams: ApplicationInstallParams | undefined;
|
||||
integrationTypesConfig: Partial<Record<ApplicationIntegrationType, ApplicationIntegrationTypeConfig>> | null;
|
||||
isMonetized: boolean;
|
||||
isVerified: boolean;
|
||||
maxParticipants: number | undefined;
|
||||
name: string;
|
||||
overlay: boolean;
|
||||
overlayCompatibilityHook: boolean;
|
||||
overlayMethods: ApplicationOverlayMethodFlags;
|
||||
overlayWarn: boolean;
|
||||
primarySkuId: string | undefined;
|
||||
privacyPolicyUrl: string | undefined;
|
||||
publishers: CompanyRecord[];
|
||||
roleConnectionsVerificationUrl: string | undefined;
|
||||
slug: string | null;
|
||||
splash: string | null;
|
||||
storefront_available: boolean | undefined;
|
||||
storeListingSkuId: string | undefined;
|
||||
tags: string[];
|
||||
/** @todo This is a team object from the API. */
|
||||
team: Record<string, any> | null;
|
||||
termsOfServiceUrl: string | undefined;
|
||||
thirdPartySkus: string[];
|
||||
type: ApplicationType | null;
|
||||
}
|
||||
|
||||
/** @todo Some properties may not actually be optional or unlikely may also be null. */
|
||||
export interface EmbeddedActivityConfig {
|
||||
application_id: string;
|
||||
client_platform_config: Partial<Record<EmbeddedActivitySupportedPlatform, EmbeddedActivityClientPlatformConfig>>;
|
||||
default_orientation_lock_state?: OrientationLockState;
|
||||
displays_advertisements?: boolean;
|
||||
has_csp_exception?: boolean;
|
||||
requires_age_gate?: boolean;
|
||||
shelf_rank?: number;
|
||||
supported_platforms?: EmbeddedActivitySupportedPlatform[];
|
||||
tablet_default_orientation_lock_state?: OrientationLockState;
|
||||
}
|
||||
|
||||
// Original name: EmbeddedActivitySupportedPlatforms
|
||||
export enum EmbeddedActivitySupportedPlatform {
|
||||
ANDROID = "android",
|
||||
IOS = "ios",
|
||||
WEB = "web",
|
||||
}
|
||||
|
||||
/** @todo Some properties may not actually be optional or unlikely may also be null. */
|
||||
export interface EmbeddedActivityClientPlatformConfig {
|
||||
label_type?: EmbeddedActivityLabelType;
|
||||
label_until?: string | null;
|
||||
release_phase: string;
|
||||
}
|
||||
|
||||
// Original name: EmbeddedActivityLabelTypes
|
||||
export enum EmbeddedActivityLabelType {
|
||||
NONE = 0,
|
||||
NEW = 1,
|
||||
UPDATED = 2,
|
||||
}
|
||||
|
||||
export enum OrientationLockState {
|
||||
UNLOCKED = 1,
|
||||
PORTRAIT = 2,
|
||||
LANDSCAPE = 3,
|
||||
}
|
||||
|
||||
export interface ApplicationExecutable {
|
||||
arguments?: string[];
|
||||
isLauncher?: boolean;
|
||||
name: string;
|
||||
os: string;
|
||||
}
|
||||
|
||||
export interface ApplicationInstallParams {
|
||||
/** Permissions serialized as a string. */
|
||||
permissions: string;
|
||||
scopes: OAuth2Scope[];
|
||||
}
|
||||
|
||||
// Original name: OAuth2Scopes
|
||||
export enum OAuth2Scope {
|
||||
ACCOUNT_GLOBAL_NAME_UPDATE = "account.global_name.update",
|
||||
ACTIVITIES_READ = "activities.read",
|
||||
ACTIVITIES_WRITE = "activities.write",
|
||||
APPLICATIONS_BUILDS_READ = "applications.builds.read",
|
||||
APPLICATIONS_BUILDS_UPLOAD = "applications.builds.upload",
|
||||
APPLICATIONS_COMMANDS = "applications.commands",
|
||||
APPLICATIONS_COMMANDS_PERMISSIONS_UPDATE = "applications.commands.permissions.update",
|
||||
APPLICATIONS_COMMANDS_UPDATE = "applications.commands.update",
|
||||
APPLICATIONS_ENTITLEMENTS = "applications.entitlements",
|
||||
APPLICATIONS_STORE_UPDATE = "applications.store.update",
|
||||
BOT = "bot",
|
||||
CONNECTIONS = "connections",
|
||||
DM_CHANNELS_MESSAGES_READ = "dm_channels.messages.read",
|
||||
DM_CHANNELS_MESSAGES_WRITE = "dm_channels.messages.write",
|
||||
DM_CHANNELS_READ = "dm_channels.read",
|
||||
EMAIL = "email",
|
||||
GATEWAY_CONNECT = "gateway.connect",
|
||||
GDM_JOIN = "gdm.join",
|
||||
GUILDS = "guilds",
|
||||
GUILDS_CHANNELS_READ = "guilds.channels.read",
|
||||
GUILDS_JOIN = "guilds.join",
|
||||
GUILDS_MEMBERS_READ = "guilds.members.read",
|
||||
IDENTIFY = "identify",
|
||||
MESSAGES_READ = "messages.read",
|
||||
OPENID = "openid",
|
||||
PAYMENT_SOURCES_COUNTRY_CODE = "payment_sources.country_code",
|
||||
PRESENCES_READ = "presences.read",
|
||||
PRESENCES_WRITE = "presences.write",
|
||||
RELATIONSHIPS_READ = "relationships.read",
|
||||
RELATIONSHIPS_WRITE = "relationships.write",
|
||||
ROLE_CONNECTIONS_WRITE = "role_connections.write",
|
||||
RPC = "rpc",
|
||||
RPC_ACTIVITIES_WRITE = "rpc.activities.write",
|
||||
RPC_NOTIFICATIONS_READ = "rpc.notifications.read",
|
||||
RPC_SCREENSHARE_READ = "rpc.screenshare.read",
|
||||
RPC_SCREENSHARE_WRITE = "rpc.screenshare.write",
|
||||
RPC_VIDEO_READ = "rpc.video.read",
|
||||
RPC_VIDEO_WRITE = "rpc.video.write",
|
||||
RPC_VOICE_READ = "rpc.voice.read",
|
||||
RPC_VOICE_WRITE = "rpc.voice.write",
|
||||
SDK_SOCIAL_LAYER = "sdk.social_layer",
|
||||
VOICE = "voice",
|
||||
WEBHOOK_INCOMING = "webhook.incoming",
|
||||
}
|
||||
|
||||
export enum ApplicationIntegrationType {
|
||||
GUILD_INSTALL = 0,
|
||||
USER_INSTALL = 1,
|
||||
}
|
||||
|
||||
export interface ApplicationIntegrationTypeConfig {
|
||||
oauth2InstallParams: ApplicationInstallParams | undefined;
|
||||
}
|
||||
|
||||
export enum ApplicationFlags {
|
||||
EMBEDDED_RELEASED = 1 << 1,
|
||||
EMBEDDED_IAP = 1 << 3,
|
||||
APPLICATION_AUTO_MODERATION_RULE_CREATE_BADGE = 1 << 6,
|
||||
GATEWAY_PRESENCE = 1 << 12,
|
||||
GATEWAY_PRESENCE_LIMITED = 1 << 13,
|
||||
GATEWAY_GUILD_MEMBERS = 1 << 14,
|
||||
GATEWAY_GUILD_MEMBERS_LIMITED = 1 << 15,
|
||||
EMBEDDED = 1 << 17,
|
||||
GATEWAY_MESSAGE_CONTENT = 1 << 18,
|
||||
GATEWAY_MESSAGE_CONTENT_LIMITED = 1 << 19,
|
||||
EMBEDDED_FIRST_PARTY = 1 << 20,
|
||||
APPLICATION_COMMAND_BADGE = 1 << 23,
|
||||
SOCIAL_LAYER_INTEGRATION = 1 << 27,
|
||||
PROMOTED = 1 << 29,
|
||||
PARTNER = 1 << 30,
|
||||
}
|
||||
|
||||
export enum ApplicationOverlayMethodFlags {
|
||||
DEFAULT = 0,
|
||||
OUT_OF_PROCESS = 1 << 0,
|
||||
}
|
||||
|
||||
// Original name: ApplicationTypes
|
||||
export enum ApplicationType {
|
||||
GAME = 1,
|
||||
TICKETED_EVENTS = 3,
|
||||
GUILD_ROLE_SUBSCRIPTIONS = 4,
|
||||
}
|
75
packages/discord-types/src/general/Clan.ts
Normal file
75
packages/discord-types/src/general/Clan.ts
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export interface Clan {
|
||||
badge: {
|
||||
badgeKind: ClanBadgeKind;
|
||||
primaryColor: string;
|
||||
secondaryColor: string;
|
||||
};
|
||||
banner: ClanBannerKind;
|
||||
bannerHash: string | null;
|
||||
branding: {
|
||||
primaryColor: string;
|
||||
secondaryColor: string;
|
||||
};
|
||||
description: string | null;
|
||||
games: string[];
|
||||
icon: string | null;
|
||||
id: string;
|
||||
memberCount: number;
|
||||
name: string;
|
||||
playstyle: ClanPlaystyle;
|
||||
tag: string;
|
||||
traits: string[];
|
||||
wildcardDescriptors: string[];
|
||||
}
|
||||
|
||||
export enum ClanBadgeKind {
|
||||
SWORD = 0,
|
||||
WATER_DROP = 1,
|
||||
SKULL = 2,
|
||||
TOADSTOOL = 3,
|
||||
MOON = 4,
|
||||
LIGHTNING = 5,
|
||||
LEAF = 6,
|
||||
HEART = 7,
|
||||
FIRE = 8,
|
||||
COMPASS = 9,
|
||||
CROSSHAIRS = 10,
|
||||
FLOWER = 11,
|
||||
FORCE = 12,
|
||||
GEM = 13,
|
||||
LAVA = 14,
|
||||
PSYCHIC = 15,
|
||||
SMOKE = 16,
|
||||
SNOW = 17,
|
||||
SOUND = 18,
|
||||
SUN = 19,
|
||||
WIND = 20,
|
||||
}
|
||||
|
||||
export enum ClanBannerKind {
|
||||
NIGHT_SKY = 0,
|
||||
CASTLE = 1,
|
||||
WORLD_MAP = 2,
|
||||
SEA_FOAM = 3,
|
||||
WARP_TUNNEL = 4,
|
||||
HOUSE = 5,
|
||||
HEIGHTMAP = 6,
|
||||
MESH = 7,
|
||||
SPATTER = 8,
|
||||
}
|
||||
|
||||
// Original name: ClanPlaystyles
|
||||
export enum ClanPlaystyle {
|
||||
NONE = 0,
|
||||
SOCIAL = 1,
|
||||
CASUAL = 2,
|
||||
COMPETITIVE = 3,
|
||||
CREATIVE = 4,
|
||||
VERY_HARDCORE = 5,
|
||||
}
|
20
packages/discord-types/src/general/CompanyRecord.ts
Normal file
20
packages/discord-types/src/general/CompanyRecord.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { RecordBase } from "./Record";
|
||||
|
||||
export type CompanyRecordOwnProperties = Pick<CompanyRecord, "id" | "name">;
|
||||
|
||||
export declare class CompanyRecord<
|
||||
OwnProperties extends CompanyRecordOwnProperties = CompanyRecordOwnProperties
|
||||
> extends RecordBase<OwnProperties> {
|
||||
constructor(companyProperties: CompanyRecordOwnProperties);
|
||||
|
||||
static createFromServer(companyFromServer: CompanyRecordOwnProperties): CompanyRecord;
|
||||
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
68
packages/discord-types/src/general/DisplayProfile.ts
Normal file
68
packages/discord-types/src/general/DisplayProfile.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Nullish, OptionalTuple } from "../internal";
|
||||
import type { GuildMemberProfile } from "./GuildMemberProfile";
|
||||
import type { ProfileBadge, ProfileThemeColors, UserProfile } from "./UserProfile";
|
||||
|
||||
export declare class DisplayProfile<
|
||||
FetchFailed extends boolean = boolean,
|
||||
Guild extends boolean = boolean
|
||||
> {
|
||||
constructor(
|
||||
userProfile: UserProfile<FetchFailed>,
|
||||
...guildMemberProfile: Guild extends true
|
||||
? [guildMemberProfile: GuildMemberProfile]
|
||||
: [guildMemberProfile?: null]
|
||||
);
|
||||
|
||||
get application(): UserProfile["application"];
|
||||
get canEditThemes(): boolean;
|
||||
get canUsePremiumProfileCustomization(): boolean;
|
||||
getBadges(): ProfileBadge[];
|
||||
getBannerURL(options: {
|
||||
canAnimate?: boolean /* = false */;
|
||||
size: number;
|
||||
}): string | undefined;
|
||||
getLegacyUsername(): UserProfile<FetchFailed>["legacyUsername"];
|
||||
getPreviewBanner(
|
||||
pendingBanner?: string | null,
|
||||
canAnimate?: boolean,
|
||||
size?: number /* = 480 */
|
||||
): string | Nullish;
|
||||
getPreviewBio(pendingBio?: string | null): Guild | false extends infer GuildValue
|
||||
? GuildValue extends true
|
||||
? { isUsingGuildValue: true; value: string; }
|
||||
: { isUsingGuildValue: false; value: string | undefined; }
|
||||
: never;
|
||||
getPreviewThemeColors(
|
||||
pendingThemeColors?: OptionalTuple<ProfileThemeColors, Nullish> | null
|
||||
): UserProfile["themeColors"];
|
||||
hasFullProfile(): boolean;
|
||||
hasPremiumCustomization(): boolean;
|
||||
hasThemeColors(): boolean;
|
||||
isUsingGuildMemberBanner(): Guild | false;
|
||||
isUsingGuildMemberBio(): Guild | false;
|
||||
isUsingGuildMemberPronouns(): Guild | false;
|
||||
get premiumGuildSince(): UserProfile<FetchFailed>["premiumGuildSince"];
|
||||
get premiumSince(): UserProfile<FetchFailed>["premiumSince"];
|
||||
get premiumType(): UserProfile<FetchFailed>["premiumType"];
|
||||
get primaryColor(): UserProfile["accentColor"];
|
||||
|
||||
_guildMemberProfile: Guild extends true ? GuildMemberProfile : Nullish;
|
||||
_userProfile: UserProfile<FetchFailed>;
|
||||
accentColor: UserProfile<FetchFailed>["accentColor"];
|
||||
banner: UserProfile["banner"];
|
||||
bio: UserProfile["bio"];
|
||||
guildId: Guild extends true ? string : undefined;
|
||||
/** @todo Does not seem to be implemented. */
|
||||
popoutAnimationParticleType: UserProfile["popoutAnimationParticleType"];
|
||||
profileEffectExpiresAt: UserProfile["profileEffectExpiresAt"];
|
||||
profileEffectId: UserProfile<FetchFailed>["profileEffectId"];
|
||||
pronouns: UserProfile<FetchFailed>["pronouns"];
|
||||
themeColors: UserProfile["themeColors"];
|
||||
userId: UserProfile<FetchFailed>["userId"];
|
||||
}
|
45
packages/discord-types/src/general/Draft.ts
Normal file
45
packages/discord-types/src/general/Draft.ts
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
/** @todo It seems that the other DraftTypes are either not handled by DraftStore or not yet implemented. */
|
||||
export type Draft<Type extends DraftType = DraftType>
|
||||
= Type extends DraftType.CHANNEL_MESSAGE | DraftType.FIRST_THREAD_MESSAGE ? DraftMessage
|
||||
: Type extends DraftType.THREAD_SETTINGS ? DraftThreadSettings
|
||||
: never;
|
||||
|
||||
// Enum keys made screaming snake case for consistency.
|
||||
export enum DraftType {
|
||||
CHANNEL_MESSAGE = 0,
|
||||
THREAD_SETTINGS = 1,
|
||||
FIRST_THREAD_MESSAGE = 2,
|
||||
APPLICATION_LAUNCHER_COMMAND = 3,
|
||||
POLL = 4,
|
||||
SLASH_COMMAND = 5,
|
||||
}
|
||||
|
||||
export interface DraftBase {
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
export interface DraftMessage extends DraftBase {
|
||||
draft: string;
|
||||
}
|
||||
|
||||
export type DraftThreadSettings = DraftForumThreadSettings | DraftNonForumThreadSettings;
|
||||
|
||||
export interface DraftThreadSettingsBase extends DraftBase {
|
||||
name?: string;
|
||||
parentChannelId: string;
|
||||
}
|
||||
|
||||
export interface DraftForumThreadSettings extends DraftThreadSettingsBase {
|
||||
appliedTags?: Set<string>;
|
||||
}
|
||||
|
||||
export interface DraftNonForumThreadSettings extends DraftThreadSettingsBase {
|
||||
isPrivate?: boolean;
|
||||
parentMessageId?: string | undefined;
|
||||
}
|
70
packages/discord-types/src/general/Frecency.ts
Normal file
70
packages/discord-types/src/general/Frecency.ts
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Nullish } from "../internal";
|
||||
|
||||
export declare class Frecency<Key extends PropertyKey = PropertyKey, Value = unknown> {
|
||||
constructor(options: {
|
||||
afterCompute: Frecency<Key, Value>["afterCompute"];
|
||||
computeBonus: Frecency<Key, Value>["computeBonus"];
|
||||
computeFrecency?: Frecency["computeFrecency"] | undefined /* = frecencyAlgorithms.original */;
|
||||
computeWeight: Frecency<Key, Value>["computeWeight"];
|
||||
lookupKey: Frecency<Key, Value>["lookupKey"];
|
||||
maxSamples?: number | undefined /* = 10 */;
|
||||
numFrequentlyItems?: number | undefined /* = 32 */;
|
||||
});
|
||||
|
||||
compute(): void;
|
||||
get frequently(): Value[];
|
||||
set frequently(values: Value[]);
|
||||
getEntry(key?: Key | null): FrecencyUsageHistoryEntry | Nullish;
|
||||
getFrecency(key?: Key | null): number | null;
|
||||
getScore(key?: Key | null): number | null;
|
||||
isDirty(): boolean;
|
||||
markDirty(): void;
|
||||
overwriteHistory(
|
||||
usageHistory?: Omit<FrecencyUsageHistoryEntry, "frecency"> | null,
|
||||
track?: readonly {
|
||||
key?: Key | Nullish;
|
||||
timestamp?: number | Nullish;
|
||||
}[] | null
|
||||
): void;
|
||||
replaceEntryComputeFunctions(
|
||||
computeWeight: Frecency["computeWeight"],
|
||||
computeFrecency: Frecency["computeFrecency"],
|
||||
calculateMaxTotalUse: Frecency["calculateMaxTotalUse"]
|
||||
): void;
|
||||
track(key?: Key | null, timestamp?: number | null): void;
|
||||
|
||||
_frequently: Value[];
|
||||
afterCompute: (
|
||||
usageHistory: Frecency<Key, Value>["usageHistory"],
|
||||
frequently: Frecency<Key, Value>["frequently"]
|
||||
) => void;
|
||||
calculateMaxTotalUse: boolean;
|
||||
computeBonus: (key: Key) => number;
|
||||
computeFrecency: (
|
||||
totalUses: number,
|
||||
score: number,
|
||||
usageStats: {
|
||||
maxTotalUse: number | undefined;
|
||||
numOfRecentUses: number;
|
||||
}
|
||||
) => number;
|
||||
computeWeight: (daysSinceUsage: number) => number;
|
||||
dirty: boolean;
|
||||
lookupKey: (key: Key) => Value;
|
||||
maxSamples: number;
|
||||
numFrequentlyItems: number;
|
||||
usageHistory: Partial<Record<Key, FrecencyUsageHistoryEntry>>;
|
||||
}
|
||||
|
||||
export interface FrecencyUsageHistoryEntry {
|
||||
frecency: number;
|
||||
recentUses: number[];
|
||||
score: number;
|
||||
totalUses: number;
|
||||
}
|
43
packages/discord-types/src/general/GuildMember.ts
Normal file
43
packages/discord-types/src/general/GuildMember.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Nullish } from "../internal";
|
||||
import type { AvatarDecorationData } from "./UserRecord";
|
||||
|
||||
export interface GuildMember {
|
||||
avatar: string | null;
|
||||
avatarDecoration: AvatarDecorationData | undefined;
|
||||
colorRoleId: string | undefined;
|
||||
colorString: string | undefined;
|
||||
communicationDisabledUntil: string | null;
|
||||
flags: GuildMemberFlags;
|
||||
fullProfileLoadedTimestamp: number | undefined;
|
||||
guildId: string;
|
||||
highestRoleId: string | undefined;
|
||||
hoistRoleId: string | undefined;
|
||||
iconRoleId: string | undefined;
|
||||
isPending: boolean;
|
||||
joinedAt: string;
|
||||
nick: string | null;
|
||||
premiumSince: string | null;
|
||||
roles: string[];
|
||||
unusualDMActivityUntil: string | Nullish;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export enum GuildMemberFlags {
|
||||
DID_REJOIN = 1 << 0,
|
||||
COMPLETED_ONBOARDING = 1 << 1,
|
||||
BYPASSES_VERIFICATION = 1 << 2,
|
||||
STARTED_ONBOARDING = 1 << 3,
|
||||
IS_GUEST = 1 << 4,
|
||||
STARTED_HOME_ACTIONS = 1 << 5,
|
||||
COMPLETED_HOME_ACTIONS = 1 << 6,
|
||||
AUTOMOD_QUARANTINED_USERNAME_OR_GUILD_NICKNAME = 1 << 7,
|
||||
AUTOMOD_QUARANTINED_BIO = 1 << 8,
|
||||
DM_SETTINGS_UPSELL_ACKNOWLEDGED = 1 << 9,
|
||||
AUTOMOD_QUARANTINED_CLAN_TAG = 1 << 10,
|
||||
}
|
23
packages/discord-types/src/general/GuildMemberProfile.ts
Normal file
23
packages/discord-types/src/general/GuildMemberProfile.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Nullish } from "../internal";
|
||||
import type { ProfileBadge, ProfileThemeColors } from "./UserProfile";
|
||||
|
||||
export interface GuildMemberProfile {
|
||||
accentColor: number | Nullish;
|
||||
badges: ProfileBadge[];
|
||||
banner: string | Nullish;
|
||||
bio: string | undefined;
|
||||
guildId: string;
|
||||
/** @todo Does not seem to be implemented. */
|
||||
popoutAnimationParticleType: any /* | Nullish */;
|
||||
profileEffectExpiresAt: number | Nullish;
|
||||
profileEffectId: string | undefined;
|
||||
pronouns: string;
|
||||
themeColors: ProfileThemeColors | Nullish;
|
||||
userId: string;
|
||||
}
|
221
packages/discord-types/src/general/GuildRecord.ts
Normal file
221
packages/discord-types/src/general/GuildRecord.ts
Normal file
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Nullish, Optional } from "../internal";
|
||||
import type { Clan } from "./Clan";
|
||||
import type { IconSource } from "./misc";
|
||||
import type { RecordBase } from "./Record";
|
||||
import type { UserRecord } from "./UserRecord";
|
||||
|
||||
export type GuildRecordOwnProperties = Pick<GuildRecord, "afkChannelId" | "afkTimeout" | "application_id" | "banner" | "clan" | "defaultMessageNotifications" | "description" | "discoverySplash" | "explicitContentFilter" | "features" | "homeHeader" | "hubType" | "icon" | "id" | "joinedAt" | "latestOnboardingQuestionId" | "maxMembers" | "maxStageVideoChannelUsers" | "maxVideoChannelUsers" | "mfaLevel" | "name" | "nsfwLevel" | "ownerId" | "preferredLocale" | "premiumProgressBarEnabled" | "premiumSubscriberCount" | "premiumTier" | "publicUpdatesChannelId" | "rulesChannelId" | "safetyAlertsChannelId" | "splash" | "systemChannelFlags" | "systemChannelId" | "vanityURLCode" | "verificationLevel">;
|
||||
|
||||
export type GuildProperties = Optional<Omit<GuildRecordOwnProperties, "features" | "joinedAt">, Nullish, "afkTimeout" | "hubType" | "id" | "systemChannelFlags", true> & {
|
||||
features?: Iterable<GuildFeature> | ArrayLike<GuildFeature> | Nullish;
|
||||
joinedAt: Date | string | number;
|
||||
};
|
||||
|
||||
export declare class GuildRecord<
|
||||
OwnProperties extends GuildRecordOwnProperties = GuildRecordOwnProperties
|
||||
> extends RecordBase<OwnProperties> {
|
||||
constructor(guildProperties: GuildProperties);
|
||||
|
||||
get acronym(): string;
|
||||
canHaveRaidActivityAlerts(): boolean;
|
||||
getApplicationId(): string | null;
|
||||
getEveryoneRoleId(): string;
|
||||
getIconSource(iconSize?: number, canAnimate?: boolean /* = false */): IconSource;
|
||||
getIconURL(iconSize?: number, canAnimate?: boolean /* = false */): string;
|
||||
getMaxEmojiSlots(): number;
|
||||
getMaxRoleSubscriptionEmojiSlots(): number;
|
||||
getMaxSoundboardSlots(): number;
|
||||
getSafetyAlertsChannelId(): string | null;
|
||||
hasCommunityInfoSubheader(): boolean;
|
||||
hasFeature(guildFeature: GuildFeature): boolean;
|
||||
hasVerificationGate(): boolean;
|
||||
isCommunity(): boolean;
|
||||
isLurker(): boolean;
|
||||
isNew(): boolean;
|
||||
isOwner(userOrUserId?: UserRecord | string | null): boolean;
|
||||
isOwnerWithRequiredMfaLevel(userOrUserId?: UserRecord | string | null): boolean;
|
||||
updateJoinedAt(joinedAt: Date | string): this;
|
||||
|
||||
afkChannelId: string | null;
|
||||
afkTimeout: number;
|
||||
application_id: string | null;
|
||||
banner: string | null;
|
||||
clan: Clan | null;
|
||||
defaultMessageNotifications: UserNotificationSetting;
|
||||
description: string | null;
|
||||
discoverySplash: string | null;
|
||||
explicitContentFilter: GuildExplicitContentFilterType;
|
||||
features: Set<GuildFeature>;
|
||||
homeHeader: string | null;
|
||||
hubType: GuildHubType | null;
|
||||
icon: string | null;
|
||||
id: string;
|
||||
joinedAt: Date;
|
||||
latestOnboardingQuestionId: string | null;
|
||||
maxMembers: number;
|
||||
maxStageVideoChannelUsers: number;
|
||||
maxVideoChannelUsers: number;
|
||||
mfaLevel: MFALevel;
|
||||
name: string;
|
||||
nsfwLevel: GuildNSFWContentLevel;
|
||||
ownerId: string | null;
|
||||
preferredLocale: string;
|
||||
premiumProgressBarEnabled: boolean;
|
||||
premiumSubscriberCount: number;
|
||||
premiumTier: BoostedGuildTier;
|
||||
publicUpdatesChannelId: string | null;
|
||||
rulesChannelId: string | null;
|
||||
safetyAlertsChannelId: string | null;
|
||||
splash: string | null;
|
||||
systemChannelFlags: SystemChannelFlags;
|
||||
systemChannelId: string | null;
|
||||
vanityURLCode: string | null;
|
||||
verificationLevel: VerificationLevel;
|
||||
}
|
||||
|
||||
// Original name: UserNotificationSettings
|
||||
export enum UserNotificationSetting {
|
||||
ALL_MESSAGES = 0,
|
||||
ONLY_MENTIONS = 1,
|
||||
NO_MESSAGES = 2,
|
||||
NULL = 3,
|
||||
}
|
||||
|
||||
// Original name: GuildExplicitContentFilterTypes
|
||||
export enum GuildExplicitContentFilterType {
|
||||
DISABLED = 0,
|
||||
MEMBERS_WITHOUT_ROLES = 1,
|
||||
ALL_MEMBERS = 2,
|
||||
}
|
||||
|
||||
// Original name: GuildFeatures
|
||||
export enum GuildFeature {
|
||||
ACTIVITY_FEED_DISABLED_BY_USER = "ACTIVITY_FEED_DISABLED_BY_USER",
|
||||
ACTIVITY_FEED_ENABLED_BY_USER = "ACTIVITY_FEED_ENABLED_BY_USER",
|
||||
ANIMATED_BANNER = "ANIMATED_BANNER",
|
||||
ANIMATED_ICON = "ANIMATED_ICON",
|
||||
AUTO_MODERATION = "AUTO_MODERATION",
|
||||
AUTOMOD_TRIGGER_USER_PROFILE = "AUTOMOD_TRIGGER_USER_PROFILE",
|
||||
BANNER = "BANNER",
|
||||
BURST_REACTIONS = "BURST_REACTIONS",
|
||||
CHANNEL_ICON_EMOJIS_GENERATED = "CHANNEL_ICON_EMOJIS_GENERATED",
|
||||
CLAN = "CLAN",
|
||||
CLAN_DISCOVERY_DISABLED = "CLAN_DISCOVERY_DISABLED",
|
||||
CLAN_PILOT_GENSHIN = "CLAN_PILOT_GENSHIN",
|
||||
CLAN_PILOT_VALORANT = "CLAN_PILOT_VALORANT",
|
||||
CLYDE_DISABLED = "CLYDE_DISABLED",
|
||||
CLYDE_ENABLED = "CLYDE_ENABLED",
|
||||
COMMERCE = "COMMERCE",
|
||||
COMMUNITY = "COMMUNITY",
|
||||
CREATOR_MONETIZABLE = "CREATOR_MONETIZABLE",
|
||||
CREATOR_MONETIZABLE_DISABLED = "CREATOR_MONETIZABLE_DISABLED",
|
||||
CREATOR_MONETIZABLE_PENDING_NEW_OWNER_ONBOARDING = "CREATOR_MONETIZABLE_PENDING_NEW_OWNER_ONBOARDING",
|
||||
CREATOR_MONETIZABLE_PROVISIONAL = "CREATOR_MONETIZABLE_PROVISIONAL",
|
||||
CREATOR_MONETIZABLE_RESTRICTED = "CREATOR_MONETIZABLE_RESTRICTED",
|
||||
CREATOR_MONETIZABLE_WHITEGLOVE = "CREATOR_MONETIZABLE_WHITEGLOVE",
|
||||
CREATOR_STORE_PAGE = "CREATOR_STORE_PAGE",
|
||||
DISCOVERABLE = "DISCOVERABLE",
|
||||
ENABLED_DISCOVERABLE_BEFORE = "ENABLED_DISCOVERABLE_BEFORE",
|
||||
ENABLED_MODERATION_EXPERIENCE_FOR_NON_COMMUNITY = "ENABLED_MODERATION_EXPERIENCE_FOR_NON_COMMUNITY",
|
||||
EXPOSED_TO_ACTIVITIES_WTP_EXPERIMENT = "EXPOSED_TO_ACTIVITIES_WTP_EXPERIMENT",
|
||||
FEATURABLE = "FEATURABLE",
|
||||
GENSHIN_L30 = "GENSHIN_L30",
|
||||
GUILD_HOME_DEPRECATION_OVERRIDE = "GUILD_HOME_DEPRECATION_OVERRIDE",
|
||||
GUILD_HOME_OVERRIDE = "GUILD_HOME_OVERRIDE",
|
||||
GUILD_HOME_TEST = "GUILD_HOME_TEST",
|
||||
GUILD_ONBOARDING = "GUILD_ONBOARDING",
|
||||
GUILD_ONBOARDING_EVER_ENABLED = "GUILD_ONBOARDING_EVER_ENABLED",
|
||||
GUILD_ONBOARDING_HAS_PROMPTS = "GUILD_ONBOARDING_HAS_PROMPTS",
|
||||
GUILD_PRODUCTS_ALLOW_ARCHIVED_FILE = "GUILD_PRODUCTS_ALLOW_ARCHIVED_FILE",
|
||||
GUILD_SERVER_GUIDE = "GUILD_SERVER_GUIDE",
|
||||
GUILD_WEB_PAGE_VANITY_URL = "GUILD_WEB_PAGE_VANITY_URL",
|
||||
HAS_DIRECTORY_ENTRY = "HAS_DIRECTORY_ENTRY",
|
||||
HUB = "HUB",
|
||||
INTERNAL_EMPLOYEE_ONLY = "INTERNAL_EMPLOYEE_ONLY",
|
||||
INVITE_SPLASH = "INVITE_SPLASH",
|
||||
INVITES_DISABLED = "INVITES_DISABLED",
|
||||
LINKED_TO_HUB = "LINKED_TO_HUB",
|
||||
MEMBER_VERIFICATION_GATE_ENABLED = "MEMBER_VERIFICATION_GATE_ENABLED",
|
||||
MEMBER_VERIFICATION_MANUAL_APPROVAL = "MEMBER_VERIFICATION_MANUAL_APPROVAL",
|
||||
MORE_EMOJI = "MORE_EMOJI",
|
||||
MORE_SOUNDBOARD = "MORE_SOUNDBOARD",
|
||||
MORE_STICKERS = "MORE_STICKERS",
|
||||
NEW_THREAD_PERMISSIONS = "NEW_THREAD_PERMISSIONS",
|
||||
NEWS = "NEWS",
|
||||
NON_COMMUNITY_RAID_ALERTS = "NON_COMMUNITY_RAID_ALERTS",
|
||||
PARTNERED = "PARTNERED",
|
||||
PREVIEW_ENABLED = "PREVIEW_ENABLED",
|
||||
PRODUCTS_AVAILABLE_FOR_PURCHASE = "PRODUCTS_AVAILABLE_FOR_PURCHASE",
|
||||
RAID_ALERTS_DISABLED = "RAID_ALERTS_DISABLED",
|
||||
RAPIDASH_TEST = "RAPIDASH_TEST",
|
||||
ROLE_ICONS = "ROLE_ICONS",
|
||||
ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE = "ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE",
|
||||
ROLE_SUBSCRIPTIONS_ENABLED = "ROLE_SUBSCRIPTIONS_ENABLED",
|
||||
SHARD = "SHARD",
|
||||
SOUNDBOARD = "SOUNDBOARD",
|
||||
SUMMARIES_ENABLED_BY_USER = "SUMMARIES_ENABLED_BY_USER",
|
||||
SUMMARIES_ENABLED_GA = "SUMMARIES_ENABLED_GA",
|
||||
SUMMARIES_OPT_OUT_EXPERIENCE = "SUMMARIES_OPT_OUT_EXPERIENCE",
|
||||
TEXT_IN_STAGE_ENABLED = "TEXT_IN_STAGE_ENABLED",
|
||||
TEXT_IN_VOICE_ENABLED = "TEXT_IN_VOICE_ENABLED",
|
||||
THREADS_ENABLED = "THREADS_ENABLED",
|
||||
THREADS_ENABLED_TESTING = "THREADS_ENABLED_TESTING",
|
||||
VALORANT_L30 = "VALORANT_L30",
|
||||
VANITY_URL = "VANITY_URL",
|
||||
VERIFIED = "VERIFIED",
|
||||
VIP_REGIONS = "VIP_REGIONS",
|
||||
WELCOME_SCREEN_ENABLED = "WELCOME_SCREEN_ENABLED",
|
||||
}
|
||||
|
||||
// Original name: GuildHubTypes
|
||||
export enum GuildHubType {
|
||||
DEFAULT = 0,
|
||||
HIGH_SCHOOL = 1,
|
||||
COLLEGE = 2,
|
||||
}
|
||||
|
||||
// Original name: MFALevels
|
||||
export enum MFALevel {
|
||||
NONE = 0,
|
||||
ELEVATED = 1,
|
||||
}
|
||||
|
||||
export enum GuildNSFWContentLevel {
|
||||
DEFAULT = 0,
|
||||
EXPLICIT = 1,
|
||||
SAFE = 2,
|
||||
AGE_RESTRICTED = 3,
|
||||
}
|
||||
|
||||
// Original name: BoostedGuildTiers
|
||||
export enum BoostedGuildTier {
|
||||
NONE = 0,
|
||||
TIER_1 = 1,
|
||||
TIER_2 = 2,
|
||||
TIER_3 = 3,
|
||||
}
|
||||
|
||||
export enum SystemChannelFlags {
|
||||
SUPPRESS_JOIN_NOTIFICATIONS = 1 << 0,
|
||||
SUPPRESS_PREMIUM_SUBSCRIPTIONS = 1 << 1,
|
||||
SUPPRESS_GUILD_REMINDER_NOTIFICATIONS = 1 << 2,
|
||||
SUPPRESS_JOIN_NOTIFICATION_REPLIES = 1 << 3,
|
||||
SUPPRESS_ROLE_SUBSCRIPTION_PURCHASE_NOTIFICATIONS = 1 << 4,
|
||||
SUPPRESS_ROLE_SUBSCRIPTION_PURCHASE_NOTIFICATION_REPLIES = 1 << 5,
|
||||
SUPPRESS_CHANNEL_PROMPT_DEADCHAT = 1 << 7,
|
||||
}
|
||||
|
||||
// Original name: VerificationLevels
|
||||
export enum VerificationLevel {
|
||||
NONE = 0,
|
||||
LOW = 1,
|
||||
MEDIUM = 2,
|
||||
HIGH = 3,
|
||||
VERY_HIGH = 4,
|
||||
}
|
78
packages/discord-types/src/general/Permissions.ts
Normal file
78
packages/discord-types/src/general/Permissions.ts
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
/*
|
||||
// bigint enums are not yet possible: https://github.com/microsoft/TypeScript/issues/37783
|
||||
export enum Permissions {
|
||||
CREATE_INSTANT_INVITE = 1n << 0n,
|
||||
KICK_MEMBERS = 1n << 1n,
|
||||
BAN_MEMBERS = 1n << 2n,
|
||||
ADMINISTRATOR = 1n << 3n,
|
||||
MANAGE_CHANNELS = 1n << 4n,
|
||||
MANAGE_GUILD = 1n << 5n,
|
||||
ADD_REACTIONS = 1n << 6n,
|
||||
VIEW_AUDIT_LOG = 1n << 7n,
|
||||
PRIORITY_SPEAKER = 1n << 8n,
|
||||
STREAM = 1n << 9n,
|
||||
VIEW_CHANNEL = 1n << 10n,
|
||||
SEND_MESSAGES = 1n << 11n,
|
||||
SEND_TTS_MESSAGES = 1n << 12n,
|
||||
MANAGE_MESSAGES = 1n << 13n,
|
||||
EMBED_LINKS = 1n << 14n,
|
||||
ATTACH_FILES = 1n << 15n,
|
||||
READ_MESSAGE_HISTORY = 1n << 16n,
|
||||
MENTION_EVERYONE = 1n << 17n,
|
||||
USE_EXTERNAL_EMOJIS = 1n << 18n,
|
||||
VIEW_GUILD_ANALYTICS = 1n << 19n,
|
||||
CONNECT = 1n << 20n,
|
||||
SPEAK = 1n << 21n,
|
||||
MUTE_MEMBERS = 1n << 22n,
|
||||
DEAFEN_MEMBERS = 1n << 23n,
|
||||
MOVE_MEMBERS = 1n << 24n,
|
||||
USE_VAD = 1n << 25n,
|
||||
CHANGE_NICKNAME = 1n << 26n,
|
||||
MANAGE_NICKNAMES = 1n << 27n,
|
||||
MANAGE_ROLES = 1n << 28n,
|
||||
MANAGE_WEBHOOKS = 1n << 29n,
|
||||
MANAGE_GUILD_EXPRESSIONS = 1n << 30n,
|
||||
USE_APPLICATION_COMMANDS = 1n << 31n,
|
||||
REQUEST_TO_SPEAK = 1n << 32n,
|
||||
MANAGE_EVENTS = 1n << 33n,
|
||||
MANAGE_THREADS = 1n << 34n,
|
||||
CREATE_PUBLIC_THREADS = 1n << 35n,
|
||||
CREATE_PRIVATE_THREADS = 1n << 36n,
|
||||
USE_EXTERNAL_STICKERS = 1n << 37n,
|
||||
SEND_MESSAGES_IN_THREADS = 1n << 38n,
|
||||
USE_EMBEDDED_ACTIVITIES = 1n << 39n,
|
||||
MODERATE_MEMBERS = 1n << 40n,
|
||||
VIEW_CREATOR_MONETIZATION_ANALYTICS = 1n << 41n,
|
||||
USE_SOUNDBOARD = 1n << 42n,
|
||||
CREATE_GUILD_EXPRESSIONS = 1n << 43n,
|
||||
CREATE_EVENTS = 1n << 44n,
|
||||
USE_EXTERNAL_SOUNDS = 1n << 45n,
|
||||
SEND_VOICE_MESSAGES = 1n << 46n,
|
||||
USE_CLYDE_AI = 1n << 47n,
|
||||
SET_VOICE_CHANNEL_STATUS = 1n << 48n,
|
||||
SEND_POLLS = 1n << 49n,
|
||||
USE_EXTERNAL_APPS = 1n << 50n,
|
||||
}
|
||||
*/
|
||||
|
||||
export interface PermissionOverwriteMap {
|
||||
[roleIdOrUserId: string]: PermissionOverwrite;
|
||||
}
|
||||
|
||||
export interface PermissionOverwrite {
|
||||
allow: /* Permissions */ bigint;
|
||||
deny: /* Permissions */ bigint;
|
||||
id: string;
|
||||
type: PermissionOverwriteType;
|
||||
}
|
||||
|
||||
export enum PermissionOverwriteType {
|
||||
ROLE = 0,
|
||||
MEMBER = 1,
|
||||
}
|
224
packages/discord-types/src/general/ReadState.ts
Normal file
224
packages/discord-types/src/general/ReadState.ts
Normal file
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Nullish, Optional } from "../internal";
|
||||
import type { BasicPermissionsObject } from "../stores/PermissionStore";
|
||||
import type { GuildChannelRecord } from "./channels/ChannelRecord";
|
||||
|
||||
export declare class ReadState<Type extends ReadStateType = ReadStateType> {
|
||||
constructor(channelId: string, type?: Type & ChannelIdReadStateType);
|
||||
constructor(userId: string, type: Type & UserIdReadStateType);
|
||||
constructor(guildId: string, type: Type & GuildIdReadStateType);
|
||||
|
||||
static _guildReadStateSentinels: { [guildId: string]: { unreadsSentinel: number; }; };
|
||||
static _mentionChannels: Set<string>;
|
||||
static _readStates: { [T in ChannelIdReadStateType]?: { [channelId: string]: ReadState<T>; }; }
|
||||
& { [T in UserIdReadStateType]?: { [userId: string]: ReadState<T>; }; }
|
||||
& { [T in GuildIdReadStateType]?: { [guildId: string]: ReadState<T>; }; };
|
||||
static clear(channelId: string, type?: ChannelIdReadStateType): boolean;
|
||||
static clear(userId: string, type: UserIdReadStateType): boolean;
|
||||
static clear(guildId: string, type: GuildIdReadStateType): boolean;
|
||||
static clearAll(): void;
|
||||
/**
|
||||
* @param callback The iteratee. Iteration will terminate early if it returns false.
|
||||
*/
|
||||
static forEach(callback: (value: ReadState) => unknown): void;
|
||||
static get(channelId: string, type?: ChannelIdReadStateType): ReadState<ChannelIdReadStateType>;
|
||||
static get<T extends UserIdReadStateType>(userId: string, type: T): ReadState<T>;
|
||||
static get<T extends GuildIdReadStateType>(guildId: string, type: T): ReadState<T>;
|
||||
static getGuildSentinels(guildId: string): typeof ReadState["_guildReadStateSentinels"];
|
||||
static getIfExists(channelId: string, type?: ChannelIdReadStateType): ReadState<ChannelIdReadStateType> | undefined;
|
||||
static getIfExists<T extends UserIdReadStateType>(userId: string, type: T): ReadState<T> | undefined;
|
||||
static getIfExists<T extends GuildIdReadStateType>(guildId: string, type: T): ReadState<T> | undefined;
|
||||
static getMentionChannelIds(): string[];
|
||||
static getValue<GetterReturn, DefaultValue = undefined>(
|
||||
channelId: string,
|
||||
type: ChannelIdReadStateType | undefined,
|
||||
getter: (readState: ReadState<ChannelIdReadStateType> | undefined) => GetterReturn,
|
||||
defaultValue?: DefaultValue
|
||||
): GetterReturn | DefaultValue;
|
||||
static getValue<T extends UserIdReadStateType, GetterReturn, DefaultValue = undefined>(
|
||||
userId: string,
|
||||
type: T,
|
||||
getter: (readState: ReadState<T> | undefined) => GetterReturn,
|
||||
defaultValue?: DefaultValue
|
||||
): GetterReturn | DefaultValue;
|
||||
static getValue<T extends GuildIdReadStateType, GetterReturn, DefaultValue = undefined>(
|
||||
guildId: string,
|
||||
type: T,
|
||||
getter: (readState: ReadState<T> | undefined) => GetterReturn,
|
||||
defaultValue?: DefaultValue
|
||||
): GetterReturn | DefaultValue;
|
||||
static resetGuildSentinels(): void;
|
||||
|
||||
_ack(location: string, trackAnalytics: boolean): void;
|
||||
_nonChannelAck(): void;
|
||||
_shouldAck(
|
||||
force?: boolean,
|
||||
local?: boolean,
|
||||
isExplicitUserAction?: boolean
|
||||
): boolean;
|
||||
ack(options: {
|
||||
force?: boolean | undefined /* = false */;
|
||||
immediate?: boolean | undefined /* = false */;
|
||||
isExplicitUserAction?: boolean | undefined /* = false */;
|
||||
local?: boolean | undefined /* = false */;
|
||||
location?: { section: string; } /* = { section: AnalyticsSections.CHANNEL } */;
|
||||
messageId?: string | Nullish /* = this.lastMessageId */;
|
||||
trackAnalytics?: boolean | undefined /* = true */;
|
||||
}): boolean;
|
||||
get ackMessageId(): ReadState["_ackMessageId"];
|
||||
set ackMessageId(messageId: ReadState["_ackMessageId"]);
|
||||
ackPins(isoTimestamp?: string | null): boolean;
|
||||
canBeUnread(): boolean;
|
||||
canHaveMentions(): boolean;
|
||||
canTrackUnreads(): boolean;
|
||||
clearOutgoingAck(): void;
|
||||
delete(remote?: boolean): void;
|
||||
deserializeForOverlay(serlizedReadState: Optional<SerializedReadState<false, Type>, Nullish, "_isJoinedThread" | "estimated" | "_isActiveThread" | "isManualAck" | "_isThread" | "loadedMessages" | "oldestUnreadMessageIdStale" | "type"> & {
|
||||
_isActiveJoinedThread?: boolean | Nullish;
|
||||
_unreadCount?: number | Nullish;
|
||||
}): void;
|
||||
getAckTimestamp(): number;
|
||||
getGuildChannelUnreadState(
|
||||
guildChannel: BasicPermissionsObject | GuildChannelRecord,
|
||||
isOptInEnabled: boolean,
|
||||
guildChannelOverrides: { [channelId: string]: GuildChannelOverride; },
|
||||
isChannelMuted: boolean,
|
||||
isReadStateTypeUnread?: boolean
|
||||
): {
|
||||
mentionCount: number;
|
||||
unread: boolean;
|
||||
};
|
||||
getMentionCount(): number;
|
||||
guessAckMessageId(): string | null;
|
||||
get guildId(): GuildIdFromReadStateType<Type>;
|
||||
handleGuildEventRemoval(guildId: string, guildEventId: string): void;
|
||||
hasMentions(): boolean;
|
||||
hasRecentlyVisitedAndRead(): boolean;
|
||||
hasUnread(): boolean;
|
||||
hasUnreadOrMentions(): boolean;
|
||||
incrementGuildUnreadsSentinel(): void;
|
||||
isForumPostUnread(): boolean;
|
||||
isPrivate(): boolean;
|
||||
get lastMessageId(): ReadState["_lastMessageId"];
|
||||
set lastMessageId(messageId: ReadState["_lastMessageId"] | Nullish);
|
||||
get lastMessageTimestamp(): ReadState["_lastMessageTimestamp"];
|
||||
get mentionCount(): ReadState["_mentionCount"];
|
||||
set mentionCount(count: ReadState["_mentionCount"]);
|
||||
get oldestUnreadMessageId(): ReadState["_oldestUnreadMessageId"];
|
||||
set oldestUnreadMessageId(messageId: ReadState["_oldestUnreadMessageId"]);
|
||||
get oldestUnreadTimestamp(): number;
|
||||
rebuildChannelState(
|
||||
ackMessageId?: string | null,
|
||||
resetMentionCount?: boolean /* = false */,
|
||||
newMentionCount?: number | null
|
||||
): void;
|
||||
recalculateFlags(): ReadStateFlags | undefined;
|
||||
recordLastViewedTime(): void;
|
||||
serialize<ForCache extends boolean>(forCache: ForCache): SerializedReadState<ForCache, Type>;
|
||||
shouldDeleteReadState(expirationTimestamp: string): boolean;
|
||||
syncThreadSettings(): boolean;
|
||||
takeSnapshot(): ReadStateSnapshot;
|
||||
get unreadCount(): number;
|
||||
set unreadCount(count: number);
|
||||
|
||||
_ackMessageId: string | null;
|
||||
_ackMessageTimestamp: number;
|
||||
_guildId: GuildIdFromReadStateType<Type> | null;
|
||||
_isActiveThread: boolean;
|
||||
_isJoinedThread: boolean;
|
||||
_isResourceChannel: boolean;
|
||||
_isThread: boolean;
|
||||
_lastMessageId: string | null;
|
||||
_lastMessageTimestamp: number;
|
||||
_mentionCount: number;
|
||||
_oldestUnreadMessageId: string | null;
|
||||
_persisted: boolean;
|
||||
_unreadCount: number;
|
||||
ackedWhileCached: undefined;
|
||||
ackMessageIdAtChannelSelect: string | null;
|
||||
ackPinTimestamp: number;
|
||||
/**
|
||||
* Not always a channel ID.
|
||||
* @see {@link ReadState}
|
||||
*/
|
||||
channelId: string;
|
||||
estimated: boolean;
|
||||
flags: ReadStateFlags | undefined;
|
||||
isManualAck: boolean;
|
||||
lastPinTimestamp: number;
|
||||
lastViewed: number | undefined;
|
||||
loadedMessages: boolean;
|
||||
oldestUnreadMessageIdStale: boolean;
|
||||
outgoingAck: string | null;
|
||||
outgoingAckTimer: number | null;
|
||||
snapshot: ReadStateSnapshot | undefined;
|
||||
type: Type;
|
||||
}
|
||||
|
||||
export type SerializedReadState<ForCache extends boolean = boolean, Type extends ReadStateType = ReadStateType>
|
||||
= ForCache extends true
|
||||
? SerializedForCache<Type>
|
||||
: Serialized<Type>;
|
||||
|
||||
type SerializedForCache<Type extends ReadStateType> = Pick<ReadState<Type>, "_ackMessageId" | "_ackMessageTimestamp" | "_guildId" | "_isActiveThread" | "_isJoinedThread" | "_isThread" | "_lastMessageId" | "_lastMessageTimestamp" | "_mentionCount" | "_persisted" | "ackPinTimestamp" | "channelId" | "flags" | "lastPinTimestamp" | "lastViewed" | "type">;
|
||||
|
||||
type Serialized<Type extends ReadStateType> = SerializedForCache<Type> & Pick<ReadState<Type>, "_oldestUnreadMessageId" | "estimated" | "isManualAck" | "loadedMessages" | "oldestUnreadMessageIdStale">;
|
||||
|
||||
export interface GuildChannelOverride {
|
||||
channel_id: string;
|
||||
collapsed: boolean;
|
||||
flags?: ChannelNotificationSettingsFlags;
|
||||
message_notifications: number;
|
||||
mute_config: GuildChannelOverrideMuteConfig | null;
|
||||
muted: boolean;
|
||||
}
|
||||
|
||||
export enum ChannelNotificationSettingsFlags {
|
||||
UNREADS_ONLY_MENTIONS = 1 << 9,
|
||||
UNREADS_ALL_MESSAGES = 1 << 10,
|
||||
FAVORITED = 1 << 11,
|
||||
OPT_IN_ENABLED = 1 << 12,
|
||||
NEW_FORUM_THREADS_OFF = 1 << 13,
|
||||
NEW_FORUM_THREADS_ON = 1 << 14,
|
||||
}
|
||||
|
||||
export interface GuildChannelOverrideMuteConfig {
|
||||
end_time: string | null;
|
||||
selected_time_window: number | null;
|
||||
}
|
||||
|
||||
export interface ReadStateSnapshot {
|
||||
guildMentionCount: number;
|
||||
guildUnread: boolean;
|
||||
mentionCount: number;
|
||||
takenAt: number;
|
||||
unread: boolean;
|
||||
}
|
||||
|
||||
export enum ReadStateFlags {
|
||||
IS_GUILD_CHANNEL = 1 << 0,
|
||||
IS_THREAD = 1 << 1,
|
||||
}
|
||||
|
||||
export type ChannelIdReadStateType = ReadStateType.CHANNEL;
|
||||
|
||||
export type UserIdReadStateType = ReadStateType.NOTIFICATION_CENTER | ReadStateType.MESSAGE_REQUESTS;
|
||||
|
||||
export type GuildIdReadStateType = ReadStateType.GUILD_EVENT | ReadStateType.GUILD_HOME | ReadStateType.GUILD_ONBOARDING_QUESTION;
|
||||
|
||||
// Original name: ReadStateTypes
|
||||
export enum ReadStateType {
|
||||
CHANNEL = 0,
|
||||
GUILD_EVENT = 1,
|
||||
NOTIFICATION_CENTER = 2,
|
||||
GUILD_HOME = 3,
|
||||
GUILD_ONBOARDING_QUESTION = 4,
|
||||
MESSAGE_REQUESTS = 5,
|
||||
}
|
||||
|
||||
type GuildIdFromReadStateType<Type extends ReadStateType> = Type extends UserIdReadStateType ? null : string;
|
28
packages/discord-types/src/general/Record.ts
Normal file
28
packages/discord-types/src/general/Record.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { StringProperties } from "../internal";
|
||||
|
||||
// Original name: Record
|
||||
// Renamed to avoid name conflicts with TypeScripts's Record utility type.
|
||||
export declare abstract class RecordBase<
|
||||
OwnProperties extends Record<PropertyKey, unknown> = Record<PropertyKey, unknown>
|
||||
> {
|
||||
constructor(properties: OwnProperties);
|
||||
|
||||
merge(collection: Partial<StringProperties<OwnProperties>> & Pick<Object, "hasOwnProperty">): this;
|
||||
set<Key extends keyof OwnProperties>(key: Key, value: OwnProperties[Key]): this;
|
||||
toJS(): OwnProperties;
|
||||
update<Key extends keyof OwnProperties>(
|
||||
key: Key,
|
||||
updater: (value: OwnProperties[Key]) => OwnProperties[Key]
|
||||
): this;
|
||||
update<Key extends keyof OwnProperties>(
|
||||
key: Key,
|
||||
notSetValue: OwnProperties[Key],
|
||||
updater: (value: OwnProperties[Key]) => OwnProperties[Key]
|
||||
): this;
|
||||
}
|
35
packages/discord-types/src/general/Role.ts
Normal file
35
packages/discord-types/src/general/Role.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export interface Role {
|
||||
color: number;
|
||||
colorString: string | null;
|
||||
flags: RoleFlags;
|
||||
hoist: boolean;
|
||||
icon: string | null;
|
||||
id: string;
|
||||
managed: boolean;
|
||||
mentionable: boolean;
|
||||
name: string;
|
||||
originalPosition: number;
|
||||
permissions: /* Permissions */ bigint;
|
||||
position: number;
|
||||
tags: RoleTags;
|
||||
unicodeEmoji: string | null;
|
||||
}
|
||||
|
||||
export enum RoleFlags {
|
||||
IN_PROMPT = 1,
|
||||
}
|
||||
|
||||
export interface RoleTags {
|
||||
available_for_purchase?: null;
|
||||
bot_id?: string;
|
||||
guild_connections?: null;
|
||||
integration_id?: string;
|
||||
premium_subscriber?: null;
|
||||
subscription_listing_id?: string;
|
||||
}
|
107
packages/discord-types/src/general/UserProfile.ts
Normal file
107
packages/discord-types/src/general/UserProfile.ts
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Nullish } from "../internal";
|
||||
import type { ApplicationInstallParams, ApplicationIntegrationType, ApplicationRecordOwnProperties } from "./ApplicationRecord";
|
||||
import type { PremiumType } from "./UserRecord";
|
||||
|
||||
export type UserProfile<FetchFailed extends boolean = boolean> = FetchFailed extends true
|
||||
? UserProfileFetchFailed
|
||||
: UserProfileFetchSucceeded;
|
||||
|
||||
export interface UserProfileBase {
|
||||
accentColor: number | Nullish;
|
||||
application: ProfileApplicationData | null;
|
||||
applicationRoleConnections: ProfileApplicationRoleConnectionData[];
|
||||
badges?: ProfileBadge[];
|
||||
banner: string | Nullish;
|
||||
bio: string;
|
||||
connectedAccounts: ProfileConnectedAccountData[];
|
||||
lastFetched: number;
|
||||
legacyUsername: string | Nullish;
|
||||
/** @todo Does not seem to be implemented. */
|
||||
popoutAnimationParticleType?: any /* | Nullish */;
|
||||
premiumGuildSince: Date | null;
|
||||
premiumSince: Date | null;
|
||||
premiumType?: PremiumType | Nullish;
|
||||
profileEffectExpiresAt?: number | Nullish;
|
||||
profileEffectId?: string | undefined;
|
||||
profileFetchFailed: boolean;
|
||||
pronouns: string;
|
||||
themeColors?: ProfileThemeColors | Nullish;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export interface UserProfileFetchSucceeded extends Required<UserProfileBase> {
|
||||
profileFetchFailed: false;
|
||||
}
|
||||
|
||||
export interface UserProfileFetchFailed extends UserProfileBase {
|
||||
profileFetchFailed: true;
|
||||
}
|
||||
|
||||
export interface ProfileApplicationData extends Pick<ApplicationRecordOwnProperties, "customInstallUrl" | "flags" | "id" | "installParams" | "primarySkuId" | "storefront_available"> {
|
||||
integrationTypesConfig: Partial<Record<ApplicationIntegrationType, {
|
||||
oauth2_install_params?: ApplicationInstallParams;
|
||||
} | null>>;
|
||||
popularApplicationCommandIds: string[] | undefined;
|
||||
}
|
||||
|
||||
export interface ProfileApplicationRoleConnectionData {
|
||||
metadata: Record<string, any /* string | number */>;
|
||||
platform_name: string | null;
|
||||
platform_username: string | null;
|
||||
}
|
||||
|
||||
export interface ProfileBadge {
|
||||
description: string;
|
||||
icon: string;
|
||||
id: string;
|
||||
link?: string;
|
||||
}
|
||||
|
||||
export interface ProfileConnectedAccountData {
|
||||
id: string;
|
||||
metadata?: Record<string, any /* string | number | boolean */>;
|
||||
name: string;
|
||||
type: PlatformType;
|
||||
verified: boolean;
|
||||
}
|
||||
|
||||
// Original name: PlatformTypes
|
||||
export enum PlatformType {
|
||||
AMAZON_MUSIC = "amazon-music",
|
||||
BATTLENET = "battlenet",
|
||||
BUNGIE = "bungie",
|
||||
CONTACTS = "contacts",
|
||||
CRUNCHYROLL = "crunchyroll",
|
||||
DOMAIN = "domain",
|
||||
EBAY = "ebay",
|
||||
EPIC_GAMES = "epicgames",
|
||||
FACEBOOK = "facebook",
|
||||
GITHUB = "github",
|
||||
INSTAGRAM = "instagram",
|
||||
LEAGUE_OF_LEGENDS = "leagueoflegends",
|
||||
PAYPAL = "paypal",
|
||||
PLAYSTATION = "playstation",
|
||||
PLAYSTATION_STAGING = "playstation-stg",
|
||||
REDDIT = "reddit",
|
||||
RIOT_GAMES = "riotgames",
|
||||
ROBLOX = "roblox",
|
||||
SAMSUNG = "samsung",
|
||||
SKYPE = "skype",
|
||||
SOUNDCLOUD = "soundcloud",
|
||||
SPOTIFY = "spotify",
|
||||
STEAM = "steam",
|
||||
TIKTOK = "tiktok",
|
||||
TWITCH = "twitch",
|
||||
TWITTER = "twitter",
|
||||
TWITTER_LEGACY = "twitter_legacy",
|
||||
XBOX = "xbox",
|
||||
YOUTUBE = "youtube",
|
||||
}
|
||||
|
||||
export type ProfileThemeColors = [primaryColor: number, accentColor: number];
|
139
packages/discord-types/src/general/UserRecord.ts
Normal file
139
packages/discord-types/src/general/UserRecord.ts
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Nullish, Optional, SnakeCasedProperties } from "../internal";
|
||||
import type { IconSource } from "./misc";
|
||||
import type { RecordBase } from "./Record";
|
||||
|
||||
export type UserRecordOwnProperties = Pick<UserRecord, "avatar" | "avatarDecorationData" | "banner" | "bot" | "clan" | "desktop" | "discriminator" | "email" | "flags" | "globalName" | "guildMemberAvatars" | "hasAnyStaffLevel" | "hasBouncedEmail" | "hasFlag" | "id" | "isStaff" | "isStaffPersonal" | "mfaEnabled" | "mobile" | "nsfwAllowed" | "personalConnectionId" | "phone" | "premiumType" | "premiumUsageFlags" | "publicFlags" | "purchasedFlags" | "system" | "username" | "verified">;
|
||||
|
||||
export type UserProperties = Optional<Omit<UserRecordOwnProperties, "avatarDecorationData" | "clan" | "hasAnyStaffLevel" | "hasFlag" | "isStaff" | "isStaffPersonal" | "nsfwAllowed" | "premiumType" | "primaryGuild">, Nullish, "id", true>
|
||||
& SnakeCasedProperties<Optional<Pick<UserRecordOwnProperties, "globalName" | "hasBouncedEmail" | "mfaEnabled" | "personalConnectionId" | "premiumUsageFlags" | "publicFlags" | "purchasedFlags">, Nullish>>
|
||||
& Partial<Record<"avatar_decoration_data" | "avatarDecorationData", unknown>>
|
||||
& Partial<Record<"premium_type" | "premiumType", UserRecord["premiumType"] | 0>>
|
||||
& { clan?: SnakeCasedProperties<UserClanData> | UserClanData | Nullish; };
|
||||
|
||||
export declare class UserRecord<
|
||||
OwnProperties extends UserRecordOwnProperties = UserRecordOwnProperties
|
||||
> extends RecordBase<OwnProperties> {
|
||||
constructor(userProperties: UserProperties);
|
||||
|
||||
addGuildAvatarHash(guildId: string, avatarHash: string): this;
|
||||
get avatarDecoration(): AvatarDecorationData | null;
|
||||
set avatarDecoration(avatarDecorationData: {
|
||||
asset: string;
|
||||
sku_id?: string;
|
||||
skuId?: string;
|
||||
} | null);
|
||||
get createdAt(): Date;
|
||||
getAvatarSource(
|
||||
guildId?: string | null,
|
||||
canAnimate?: boolean /* = false */,
|
||||
avatarSize?: number /* = 128 */
|
||||
): IconSource;
|
||||
getAvatarURL(
|
||||
guildId?: string | null,
|
||||
avatarSize?: number /* = 128 */,
|
||||
canAnimate?: boolean /* = false */
|
||||
): string;
|
||||
hasAvatarForGuild(guildId?: string | null): boolean;
|
||||
hasFreePremium(): boolean;
|
||||
hasHadPremium(): boolean;
|
||||
hasHadSKU(skuId: string): boolean;
|
||||
hasPremiumUsageFlag(flag: number): boolean;
|
||||
hasPurchasedFlag(flag: number): boolean;
|
||||
hasUrgentMessages(): boolean;
|
||||
hasVerifiedEmailOrPhone(): boolean;
|
||||
isClaimed(): boolean;
|
||||
isClyde(): boolean;
|
||||
isLocalBot(): boolean;
|
||||
isNonUserBot(): boolean;
|
||||
isPhoneVerified(): boolean;
|
||||
isPomelo(): boolean;
|
||||
isSystemUser(): boolean;
|
||||
isVerifiedBot(): boolean;
|
||||
removeGuildAvatarHash(guildId: string): this;
|
||||
get tag(): string;
|
||||
|
||||
avatar: string | null;
|
||||
avatarDecorationData: AvatarDecorationData | null;
|
||||
banner: string | Nullish;
|
||||
bot: boolean;
|
||||
clan: UserClanData | null;
|
||||
desktop: boolean;
|
||||
discriminator: string;
|
||||
email: string | null;
|
||||
flags: UserFlags;
|
||||
globalName: string | Nullish;
|
||||
guildMemberAvatars: { [guildId: string]: string; };
|
||||
hasAnyStaffLevel: () => boolean;
|
||||
hasBouncedEmail: boolean;
|
||||
hasFlag: (flag: number) => boolean;
|
||||
id: string;
|
||||
isStaff: () => boolean;
|
||||
isStaffPersonal: () => boolean;
|
||||
mfaEnabled: boolean;
|
||||
mobile: boolean;
|
||||
nsfwAllowed: boolean;
|
||||
personalConnectionId: string | null;
|
||||
phone: string | null;
|
||||
premiumType: PremiumType | Nullish;
|
||||
premiumUsageFlags: number;
|
||||
publicFlags: UserFlags;
|
||||
purchasedFlags: number;
|
||||
system: boolean;
|
||||
username: string;
|
||||
verified: boolean;
|
||||
}
|
||||
|
||||
export interface AvatarDecorationData {
|
||||
asset: string;
|
||||
skuId: string;
|
||||
}
|
||||
|
||||
// Original name: PremiumTypes
|
||||
export enum PremiumType {
|
||||
/** Nitro Classic */
|
||||
TIER_1 = 1,
|
||||
/** Nitro Standard */
|
||||
TIER_2 = 2,
|
||||
/** Nitro Basic */
|
||||
TIER_0 = 3,
|
||||
}
|
||||
|
||||
export interface UserClanData {
|
||||
badge: string | null;
|
||||
identityEnabled: boolean | null;
|
||||
identityGuildId: string | null;
|
||||
tag: string | null;
|
||||
}
|
||||
|
||||
export enum UserFlags {
|
||||
STAFF = 1 << 0,
|
||||
PARTNER = 1 << 1,
|
||||
HYPESQUAD = 1 << 2,
|
||||
BUG_HUNTER_LEVEL_1 = 1 << 3,
|
||||
MFA_SMS = 1 << 4,
|
||||
PREMIUM_PROMO_DISMISSED = 1 << 5,
|
||||
HYPESQUAD_ONLINE_HOUSE_1 = 1 << 6,
|
||||
HYPESQUAD_ONLINE_HOUSE_2 = 1 << 7,
|
||||
HYPESQUAD_ONLINE_HOUSE_3 = 1 << 8,
|
||||
PREMIUM_EARLY_SUPPORTER = 1 << 9,
|
||||
TEAM_PSEUDO_USER = 1 << 10,
|
||||
HAS_UNREAD_URGENT_MESSAGES = 1 << 13,
|
||||
BUG_HUNTER_LEVEL_2 = 1 << 14,
|
||||
VERIFIED_BOT = 1 << 16,
|
||||
VERIFIED_DEVELOPER = 1 << 17,
|
||||
CERTIFIED_MODERATOR = 1 << 18,
|
||||
BOT_HTTP_INTERACTIONS = 1 << 19,
|
||||
SPAMMER = 1 << 20,
|
||||
DISABLE_PREMIUM = 1 << 21,
|
||||
ACTIVE_DEVELOPER = 1 << 22,
|
||||
PROVISIONAL_ACCOUNT = 1 << 23,
|
||||
QUARANTINED = 0x10_00_00_00_00_00,
|
||||
COLLABORATOR = 0x4_00_00_00_00_00_00,
|
||||
RESTRICTED_COLLABORATOR = 0x8_00_00_00_00_00_00
|
||||
}
|
267
packages/discord-types/src/general/channels/ChannelRecord.ts
Normal file
267
packages/discord-types/src/general/channels/ChannelRecord.ts
Normal file
|
@ -0,0 +1,267 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Nullish, Optional, SnakeCasedProperties } from "../../internal";
|
||||
import type { PermissionOverwriteMap } from "../Permissions";
|
||||
import type { AvatarDecorationData, UserClanData, UserFlags } from "../UserRecord";
|
||||
import type { ForumChannelRecord } from "./ForumChannelRecord";
|
||||
import type { GuildCategoryChannelRecord, GuildDirectoryChannelRecord, GuildTextualChannelRecord } from "./GuildTextualChannelRecord";
|
||||
import type { GuildStageVoiceChannelRecord, GuildVocalChannelRecord, GuildVoiceChannelRecord } from "./GuildVocalChannelRecord";
|
||||
import type { DMChannelRecord, GroupDMChannelRecord, PrivateChannelRecord } from "./PrivateChannelRecord";
|
||||
import type { ThreadChannelRecord } from "./ThreadChannelRecord";
|
||||
|
||||
export type ChannelRecord = GuildChannelRecord | PrivateChannelRecord | ThreadChannelRecord;
|
||||
|
||||
export type GuildChannelRecord = GuildTextualChannelRecord | GuildVocalChannelRecord | ForumChannelRecord;
|
||||
|
||||
export type GuildSelectableChannelRecord = Exclude<GuildChannelRecord, GuildCategoryChannelRecord | GuildVocalChannelRecord>;
|
||||
|
||||
type ChannelRecordOwnPropertyKeys = "application_id" | "appliedTags" | "availableTags" | "bitrate_" | "blockedUserWarningDismissed" | "defaultAutoArchiveDuration" | "defaultForumLayout" | "defaultReactionEmoji" | "defaultSortOrder" | "defaultThreadRateLimitPerUser" | "flags_" | "guild_id" | "icon" | "iconEmoji" | "id" | "isMessageRequest" | "isMessageRequestTimestamp" | "isSpam" | "lastMessageId" | "lastPinTimestamp" | "linkedLobby" | "member" | "memberCount" | "memberIdsPreview" | "memberListId" | "messageCount" | "name" | "nicks" | "nsfw_" | "originChannelId" | "ownerId" | "parentChannelThreadType" | "parent_id" | "permissionOverwrites_" | "position_" | "rateLimitPerUser_" | "rawRecipients" | "recipients" | "rtcRegion" | "safetyWarnings" | "template" | "themeColor" | "threadMetadata" | "topic_" | "totalMessageSent" | "type" | "userLimit_" | "version" | "videoQualityMode";
|
||||
|
||||
export type ChannelRecordOwnProperties<Channel extends ChannelRecordBase> = Pick<Channel, ChannelRecordOwnPropertyKeys>;
|
||||
|
||||
export declare abstract class ChannelRecordBase extends ChannelRecordProperties {
|
||||
get accessPermissions(): /* Permissions */ bigint;
|
||||
get bitrate(): number;
|
||||
computeLurkerPermissionsAllowList(): /* Permissions */ bigint | undefined;
|
||||
get flags(): ChannelFlags;
|
||||
getApplicationId(): this["application_id"];
|
||||
getDefaultLayout(): ForumLayout;
|
||||
getDefaultSortOrder(): ThreadSortOrder;
|
||||
getGuildId(): this["guild_id"];
|
||||
hasFlag(flag: ChannelFlags): boolean;
|
||||
isActiveThread(): boolean;
|
||||
isAnnouncementThread(): this is ThreadChannelRecord<ChannelType.ANNOUNCEMENT_THREAD>;
|
||||
isArchivedLockedThread(): boolean;
|
||||
isArchivedThread(): boolean;
|
||||
isBroadcastChannel(): boolean;
|
||||
isCategory(): this is GuildCategoryChannelRecord;
|
||||
isDirectory(): this is GuildDirectoryChannelRecord;
|
||||
isDM(): this is DMChannelRecord;
|
||||
isForumChannel(): this is ForumChannelRecord<ChannelType.GUILD_FORUM>;
|
||||
isForumLikeChannel(): this is ForumChannelRecord;
|
||||
isForumPost(): boolean;
|
||||
isGroupDM(): this is GroupDMChannelRecord;
|
||||
isGuildStageVoice(): this is GuildStageVoiceChannelRecord;
|
||||
isGuildVocal(): this is GuildVocalChannelRecord;
|
||||
isGuildVocalOrThread(): this is GuildVocalChannelRecord | ThreadChannelRecord<ChannelType.PUBLIC_THREAD | ChannelType.PRIVATE_THREAD>;
|
||||
isGuildVoice(): this is GuildVoiceChannelRecord;
|
||||
isListenModeCapable(): this is GuildStageVoiceChannelRecord;
|
||||
isLockedThread(): boolean;
|
||||
isManaged(): boolean;
|
||||
isMediaChannel(): this is ForumChannelRecord<ChannelType.GUILD_MEDIA>;
|
||||
isMediaPost(): boolean;
|
||||
/** This method is functionally the same as {@link isGroupDM}. */
|
||||
isMultiUserDM(): this is GroupDMChannelRecord;
|
||||
isNSFW(): boolean;
|
||||
isOwner(userId: string): boolean;
|
||||
isPrivate(): this is PrivateChannelRecord;
|
||||
isRoleSubscriptionTemplatePreviewChannel(): boolean;
|
||||
isScheduledForDeletion(): boolean;
|
||||
isSystemDM(): boolean;
|
||||
isThread(): this is ThreadChannelRecord;
|
||||
isVocal(): this is PrivateChannelRecord | GuildVocalChannelRecord | ThreadChannelRecord<ChannelType.PUBLIC_THREAD | ChannelType.PRIVATE_THREAD>;
|
||||
isVocalThread(): this is ThreadChannelRecord<ChannelType.PUBLIC_THREAD | ChannelType.PRIVATE_THREAD>;
|
||||
merge(collection: Partial<ChannelRecordOwnProperties<this>>): this;
|
||||
get nsfw(): boolean;
|
||||
get permissionOverwrites(): PermissionOverwriteMap;
|
||||
get position(): number;
|
||||
get rateLimitPerUser(): number;
|
||||
set<Key extends ChannelRecordOwnPropertyKeys>(key: Key, value: ChannelRecordOwnProperties<this>[Key]): this;
|
||||
toJS(): ChannelRecordOwnProperties<this>;
|
||||
get topic(): string;
|
||||
get userLimit(): number;
|
||||
}
|
||||
|
||||
export type ChannelProperties = Optional<Pick<ChannelRecordOwnProperties<ChannelRecordBase>, "guild_id" | "id" | "name" | "type">, Nullish, "id", true>;
|
||||
|
||||
export declare abstract class ChannelRecordProperties {
|
||||
constructor(channelProperties: ChannelProperties);
|
||||
|
||||
application_id?: string | undefined;
|
||||
appliedTags?: string[] | undefined;
|
||||
availableTags?: ForumTag[] | undefined;
|
||||
bitrate_?: number | undefined;
|
||||
blockedUserWarningDismissed?: boolean | undefined;
|
||||
defaultAutoArchiveDuration?: number | undefined;
|
||||
defaultForumLayout?: ForumLayout | undefined;
|
||||
defaultReactionEmoji?: ForumDefaultReactionEmoji | undefined;
|
||||
defaultSortOrder?: ThreadSortOrder | Nullish;
|
||||
defaultThreadRateLimitPerUser?: number | undefined;
|
||||
flags_: ChannelFlags | undefined;
|
||||
guild_id: string | null;
|
||||
icon?: string | Nullish;
|
||||
iconEmoji?: {
|
||||
id: string | null;
|
||||
name: string;
|
||||
} | undefined;
|
||||
id: string;
|
||||
isMessageRequest?: boolean | undefined;
|
||||
isMessageRequestTimestamp?: string | Nullish;
|
||||
isSpam?: boolean | undefined;
|
||||
lastMessageId: string | Nullish;
|
||||
lastPinTimestamp: string | Nullish;
|
||||
/** @todo May have more properties. */
|
||||
linkedLobby?: { application_id?: string | null; } & Record<string, any> | Nullish;
|
||||
member?: ThreadMember | undefined;
|
||||
memberCount?: number | undefined;
|
||||
memberIdsPreview?: string[] | undefined;
|
||||
memberListId?: string | Nullish;
|
||||
messageCount?: number | undefined;
|
||||
name: string;
|
||||
nicks?: { [userId: string]: string; } | undefined;
|
||||
nsfw_?: boolean | undefined;
|
||||
originChannelId?: string | Nullish;
|
||||
ownerId?: string | undefined;
|
||||
parent_id?: string | Nullish;
|
||||
parentChannelThreadType?: ChannelType.GUILD_TEXT | ChannelType.GUILD_ANNOUNCEMENT | ChannelType.GUILD_FORUM | ChannelType.GUILD_MEDIA | undefined;
|
||||
permissionOverwrites_?: PermissionOverwriteMap | undefined;
|
||||
position_?: number | undefined;
|
||||
rateLimitPerUser_?: number | undefined;
|
||||
rawRecipients?: ChannelRecipient[] | undefined;
|
||||
recipients?: string[] | undefined;
|
||||
rtcRegion?: string | Nullish;
|
||||
safetyWarnings?: SafetyWarning[] | undefined;
|
||||
template?: string | undefined;
|
||||
themeColor?: number | Nullish;
|
||||
threadMetadata?: ThreadMetadata | undefined;
|
||||
topic_?: string | Nullish;
|
||||
totalMessageSent?: number | undefined;
|
||||
type: ChannelType;
|
||||
userLimit_?: number | undefined;
|
||||
version?: number | undefined;
|
||||
videoQualityMode?: VideoQualityMode | undefined;
|
||||
/** @todo This seems to have been removed. */
|
||||
voiceBackgroundDisplay?: { type: VoiceCallBackgroundType.EMPTY; }
|
||||
| { resourceId: string; type: VoiceCallBackgroundType.GRADIENT; }
|
||||
| Nullish;
|
||||
}
|
||||
|
||||
export interface ForumTag {
|
||||
emojiId: string | null;
|
||||
emojiName: string | null;
|
||||
id: string;
|
||||
moderated: boolean;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export enum ForumLayout {
|
||||
DEFAULT = 0,
|
||||
LIST = 1,
|
||||
GRID = 2,
|
||||
}
|
||||
|
||||
export interface ForumDefaultReactionEmoji {
|
||||
emojiId: string | null;
|
||||
emojiName: string | null;
|
||||
}
|
||||
|
||||
export enum ThreadSortOrder {
|
||||
LATEST_ACTIVITY = 0,
|
||||
CREATION_DATE = 1,
|
||||
}
|
||||
|
||||
export enum ChannelFlags {
|
||||
GUILD_FEED_REMOVED = 1 << 0,
|
||||
PINNED = 1 << 1,
|
||||
ACTIVE_CHANNELS_REMOVED = 1 << 2,
|
||||
REQUIRE_TAG = 1 << 4,
|
||||
IS_SPAM = 1 << 5,
|
||||
IS_GUILD_RESOURCE_CHANNEL = 1 << 7,
|
||||
CLYDE_AI = 1 << 8,
|
||||
IS_SCHEDULED_FOR_DELETION = 1 << 9,
|
||||
IS_MEDIA_CHANNEL = 1 << 10,
|
||||
SUMMARIES_DISABLED = 1 << 11,
|
||||
IS_ROLE_SUBSCRIPTION_TEMPLATE_PREVIEW_CHANNEL = 1 << 13,
|
||||
IS_BROADCASTING = 1 << 14,
|
||||
HIDE_MEDIA_DOWNLOAD_OPTIONS = 1 << 15,
|
||||
IS_JOIN_REQUEST_INTERVIEW_CHANNEL = 1 << 16,
|
||||
}
|
||||
|
||||
export interface ThreadMember {
|
||||
flags: ThreadMemberFlags;
|
||||
joinTimestamp: string;
|
||||
muteConfig: {
|
||||
end_time: string | null;
|
||||
selected_time_window: number;
|
||||
} | null;
|
||||
muted: boolean;
|
||||
}
|
||||
|
||||
export enum ThreadMemberFlags {
|
||||
HAS_INTERACTED = 1 << 0,
|
||||
ALL_MESSAGES = 1 << 1,
|
||||
ONLY_MENTIONS = 1 << 2,
|
||||
NO_MESSAGES = 1 << 3,
|
||||
}
|
||||
|
||||
/** @todo This may just be a user object from the API. */
|
||||
export interface ChannelRecipient {
|
||||
avatar: string | null;
|
||||
avatar_decoration_data: SnakeCasedProperties<AvatarDecorationData> | null;
|
||||
bot?: boolean;
|
||||
clan: SnakeCasedProperties<UserClanData> | null;
|
||||
discriminator: string;
|
||||
display_name?: string | null;
|
||||
global_name: string | null;
|
||||
id: string;
|
||||
public_flags: UserFlags;
|
||||
username: string;
|
||||
}
|
||||
|
||||
export interface SafetyWarning {
|
||||
/** @todo May not be null or optional. */
|
||||
dismiss_timestamp?: string | null;
|
||||
type: SafetyWarningType;
|
||||
}
|
||||
|
||||
// Original name: SafetyWarningTypes
|
||||
export enum SafetyWarningType {
|
||||
STRANGER_DANGER = 1,
|
||||
INAPPROPRIATE_CONVERSATION_TIER_1 = 2,
|
||||
INAPPROPRIATE_CONVERSATION_TIER_2 = 3,
|
||||
}
|
||||
|
||||
export interface ThreadMetadata {
|
||||
archived: boolean;
|
||||
archiveTimestamp: string;
|
||||
autoArchiveDuration: number;
|
||||
createTimestamp: string | Nullish;
|
||||
invitable: boolean;
|
||||
locked: boolean;
|
||||
}
|
||||
|
||||
// Original name: ChannelTypes
|
||||
export enum ChannelType {
|
||||
GUILD_TEXT = 0,
|
||||
DM = 1,
|
||||
GUILD_VOICE = 2,
|
||||
GROUP_DM = 3,
|
||||
GUILD_CATEGORY = 4,
|
||||
GUILD_ANNOUNCEMENT = 5,
|
||||
GUILD_STORE = 6,
|
||||
ANNOUNCEMENT_THREAD = 10,
|
||||
PUBLIC_THREAD = 11,
|
||||
PRIVATE_THREAD = 12,
|
||||
GUILD_STAGE_VOICE = 13,
|
||||
GUILD_DIRECTORY = 14,
|
||||
GUILD_FORUM = 15,
|
||||
GUILD_MEDIA = 16,
|
||||
LOBBY = 17,
|
||||
UNKNOWN = 10_000,
|
||||
}
|
||||
|
||||
export enum VideoQualityMode {
|
||||
AUTO = 1,
|
||||
FULL = 2,
|
||||
}
|
||||
|
||||
// Original name: VoiceCallBackgroundTypes
|
||||
/** @todo This seems to have been removed. */
|
||||
export enum VoiceCallBackgroundType {
|
||||
EMPTY = 0,
|
||||
GRADIENT = 1,
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Defined, Nullish, OmitOptional, Optional, PartialOnUndefined } from "../../internal";
|
||||
import type { ChannelRecordBase, ChannelRecordOwnProperties, ChannelType } from "./ChannelRecord";
|
||||
|
||||
export type ForumChannelProperties = Optional<PartialOnUndefined<OmitOptional<ChannelRecordOwnProperties<ForumChannelRecord>>>, Nullish, "availableTags" | "guild_id" | "name" | "permissionOverwrites_">;
|
||||
|
||||
type ForumChannelType = ChannelType.GUILD_FORUM | ChannelType.GUILD_MEDIA;
|
||||
|
||||
export declare class ForumChannelRecord<ChannelType extends ForumChannelType = ForumChannelType> extends ChannelRecordBase {
|
||||
constructor(channelProperties: ForumChannelProperties);
|
||||
|
||||
static fromServer<Type extends ForumChannelType>(
|
||||
/** @todo */
|
||||
channelFromServer: { type: Type; } & Record<string, any>,
|
||||
guildId?: string | null
|
||||
): ForumChannelRecord<Type>;
|
||||
|
||||
application_id?: undefined;
|
||||
appliedTags?: undefined;
|
||||
availableTags: Defined<ChannelRecordBase["availableTags"]>;
|
||||
bitrate_?: undefined;
|
||||
blockedUserWarningDismissed?: undefined;
|
||||
defaultAutoArchiveDuration: ChannelRecordBase["defaultAutoArchiveDuration"];
|
||||
defaultForumLayout: ChannelRecordBase["defaultForumLayout"];
|
||||
defaultReactionEmoji: ChannelRecordBase["defaultReactionEmoji"];
|
||||
defaultSortOrder: ChannelRecordBase["defaultSortOrder"];
|
||||
defaultThreadRateLimitPerUser: ChannelRecordBase["defaultThreadRateLimitPerUser"];
|
||||
flags_: Defined<ChannelRecordBase["flags_"]>;
|
||||
icon?: undefined;
|
||||
iconEmoji: ChannelRecordBase["iconEmoji"];
|
||||
isMessageRequest?: undefined;
|
||||
isMessageRequestTimestamp?: undefined;
|
||||
isSpam?: undefined;
|
||||
lastMessageId: ChannelRecordBase["lastMessageId"];
|
||||
lastPinTimestamp: ChannelRecordBase["lastPinTimestamp"];
|
||||
linkedLobby?: undefined;
|
||||
member?: undefined;
|
||||
memberCount?: undefined;
|
||||
memberIdsPreview?: undefined;
|
||||
/** @todo May only be nullish. */
|
||||
memberListId: ChannelRecordBase["memberListId"];
|
||||
messageCount?: undefined;
|
||||
nicks?: undefined;
|
||||
nsfw_: Defined<ChannelRecordBase["nsfw_"]>;
|
||||
originChannelId?: undefined;
|
||||
ownerId?: undefined;
|
||||
parent_id: NonNullable<ChannelRecordBase["parent_id"]>;
|
||||
parentChannelThreadType?: undefined;
|
||||
permissionOverwrites_: Defined<ChannelRecordBase["permissionOverwrites_"]>;
|
||||
position_: Defined<ChannelRecordBase["position_"]>;
|
||||
rateLimitPerUser_: Defined<ChannelRecordBase["rateLimitPerUser_"]>;
|
||||
rawRecipients?: undefined;
|
||||
recipients?: undefined;
|
||||
rtcRegion?: undefined;
|
||||
safetyWarnings?: undefined;
|
||||
template: Defined<ChannelRecordBase["template"]>;
|
||||
themeColor: ChannelRecordBase["themeColor"];
|
||||
threadMetadata?: undefined;
|
||||
topic_: ChannelRecordBase["topic_"];
|
||||
totalMessageSent?: undefined;
|
||||
type: ChannelType;
|
||||
userLimit_?: undefined;
|
||||
version: ChannelRecordBase["version"];
|
||||
videoQualityMode?: undefined;
|
||||
voiceBackgroundDisplay?: undefined;
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Defined, Nullish, OmitOptional, Optional, PartialOnUndefined } from "../../internal";
|
||||
import type { ChannelRecordBase, ChannelRecordOwnProperties, ChannelType } from "./ChannelRecord";
|
||||
|
||||
export type GuildTextualChannelRecord = GuildTextChannelRecord | GuildCategoryChannelRecord | GuildAnnouncementChannelRecord | GuildStoreChannelRecord | GuildDirectoryChannelRecord;
|
||||
|
||||
export type GuildTextualChannelProperties = Optional<PartialOnUndefined<OmitOptional<ChannelRecordOwnProperties<GuildTextualChannelRecordBase>>>, Nullish, "guild_id" | "name" | "permissionOverwrites_" | "type">;
|
||||
|
||||
type GuildTextualChannelType = ChannelType.GUILD_TEXT | ChannelType.GUILD_CATEGORY | ChannelType.GUILD_ANNOUNCEMENT | ChannelType.GUILD_STORE | ChannelType.GUILD_DIRECTORY;
|
||||
|
||||
export declare abstract class GuildTextualChannelRecordBase extends ChannelRecordBase {
|
||||
constructor(channelProperties: GuildTextualChannelProperties);
|
||||
|
||||
static fromServer<Type extends GuildTextualChannelType | Nullish = undefined>(
|
||||
/** @todo */
|
||||
channelFromServer: { type?: Type; } & Record<string, any>,
|
||||
guildId?: string | null
|
||||
): {
|
||||
[ChannelType.GUILD_ANNOUNCEMENT]: GuildAnnouncementChannelRecord;
|
||||
[ChannelType.GUILD_CATEGORY]: GuildCategoryChannelRecord;
|
||||
[ChannelType.GUILD_DIRECTORY]: GuildDirectoryChannelRecord;
|
||||
[ChannelType.GUILD_STORE]: GuildStoreChannelRecord;
|
||||
[ChannelType.GUILD_TEXT]: GuildTextChannelRecord;
|
||||
}[Type extends GuildTextualChannelType ? Type : ChannelType.GUILD_TEXT];
|
||||
|
||||
application_id: undefined;
|
||||
appliedTags?: undefined;
|
||||
availableTags?: undefined;
|
||||
bitrate_?: undefined;
|
||||
blockedUserWarningDismissed?: undefined;
|
||||
defaultAutoArchiveDuration: ChannelRecordBase["defaultAutoArchiveDuration"];
|
||||
defaultForumLayout?: undefined;
|
||||
defaultReactionEmoji?: undefined;
|
||||
defaultSortOrder?: undefined;
|
||||
defaultThreadRateLimitPerUser: ChannelRecordBase["defaultThreadRateLimitPerUser"];
|
||||
flags_: Defined<ChannelRecordBase["flags_"]>;
|
||||
icon?: undefined;
|
||||
iconEmoji: ChannelRecordBase["iconEmoji"];
|
||||
isMessageRequest?: undefined;
|
||||
isMessageRequestTimestamp?: undefined;
|
||||
isSpam?: undefined;
|
||||
lastMessageId: ChannelRecordBase["lastMessageId"];
|
||||
lastPinTimestamp: ChannelRecordBase["lastPinTimestamp"];
|
||||
/** @todo May only be nullish. */
|
||||
linkedLobby: ChannelRecordBase["linkedLobby"];
|
||||
member?: undefined;
|
||||
memberCount?: undefined;
|
||||
memberIdsPreview?: undefined;
|
||||
/** @todo May only be nullish. */
|
||||
memberListId: ChannelRecordBase["memberListId"];
|
||||
messageCount?: undefined;
|
||||
nicks?: undefined;
|
||||
nsfw_: Defined<ChannelRecordBase["nsfw_"]>;
|
||||
originChannelId?: undefined;
|
||||
ownerId?: undefined;
|
||||
parent_id: ChannelRecordBase["parent_id"];
|
||||
parentChannelThreadType?: undefined;
|
||||
permissionOverwrites_: Defined<ChannelRecordBase["permissionOverwrites_"]>;
|
||||
position_: Defined<ChannelRecordBase["position_"]>;
|
||||
rateLimitPerUser_: Defined<ChannelRecordBase["rateLimitPerUser_"]>;
|
||||
rawRecipients?: undefined;
|
||||
recipients?: undefined;
|
||||
rtcRegion?: undefined;
|
||||
safetyWarnings?: undefined;
|
||||
template?: undefined;
|
||||
themeColor: ChannelRecordBase["themeColor"];
|
||||
threadMetadata?: undefined;
|
||||
topic_: ChannelRecordBase["topic_"];
|
||||
totalMessageSent?: undefined;
|
||||
type: GuildTextualChannelType;
|
||||
userLimit_?: undefined;
|
||||
version: ChannelRecordBase["version"];
|
||||
videoQualityMode?: undefined;
|
||||
voiceBackgroundDisplay?: undefined;
|
||||
}
|
||||
|
||||
export type GuildTextChannelProperties = Optional<PartialOnUndefined<OmitOptional<ChannelRecordOwnProperties<GuildTextChannelRecord>>>, Nullish, "guild_id" | "name" | "permissionOverwrites_" | "type">;
|
||||
|
||||
export declare class GuildTextChannelRecord extends GuildTextualChannelRecordBase {
|
||||
constructor(channelProperties: GuildTextChannelProperties);
|
||||
|
||||
type: ChannelType.GUILD_TEXT;
|
||||
}
|
||||
|
||||
export type GuildCategoryChannelProperties = Optional<PartialOnUndefined<OmitOptional<ChannelRecordOwnProperties<GuildCategoryChannelRecord>>>, Nullish, "guild_id" | "name" | "permissionOverwrites_">;
|
||||
|
||||
export declare class GuildCategoryChannelRecord extends GuildTextualChannelRecordBase {
|
||||
constructor(channelProperties: GuildCategoryChannelProperties);
|
||||
|
||||
defaultAutoArchiveDuration: undefined;
|
||||
defaultThreadRateLimitPerUser: undefined;
|
||||
lastMessageId: undefined;
|
||||
lastPinTimestamp: undefined;
|
||||
memberListId: undefined;
|
||||
parent_id: Nullish;
|
||||
themeColor: undefined;
|
||||
topic_: undefined;
|
||||
type: ChannelType.GUILD_CATEGORY;
|
||||
}
|
||||
|
||||
export type GuildAnnouncementChannelProperties = Optional<PartialOnUndefined<OmitOptional<ChannelRecordOwnProperties<GuildAnnouncementChannelRecord>>>, Nullish, "guild_id" | "name" | "permissionOverwrites_">;
|
||||
|
||||
export declare class GuildAnnouncementChannelRecord extends GuildTextualChannelRecordBase {
|
||||
constructor(channelProperties: GuildAnnouncementChannelProperties);
|
||||
|
||||
type: ChannelType.GUILD_ANNOUNCEMENT;
|
||||
}
|
||||
|
||||
export type GuildStoreChannelProperties = Optional<PartialOnUndefined<OmitOptional<ChannelRecordOwnProperties<GuildStoreChannelRecord>>>, Nullish, "guild_id" | "name" | "permissionOverwrites_">;
|
||||
|
||||
export declare class GuildStoreChannelRecord extends GuildTextualChannelRecordBase {
|
||||
constructor(channelProperties: GuildStoreChannelProperties);
|
||||
|
||||
type: ChannelType.GUILD_STORE;
|
||||
}
|
||||
|
||||
export type GuildDirectoryChannelProperties = Optional<PartialOnUndefined<OmitOptional<ChannelRecordOwnProperties<GuildDirectoryChannelRecord>>>, Nullish, "guild_id" | "name" | "permissionOverwrites_">;
|
||||
|
||||
export declare class GuildDirectoryChannelRecord extends GuildTextualChannelRecordBase {
|
||||
constructor(channelProperties: GuildDirectoryChannelProperties);
|
||||
|
||||
type: ChannelType.GUILD_DIRECTORY;
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Defined, Nullish, OmitOptional, Optional, PartialOnUndefined } from "../../internal";
|
||||
import type { ChannelRecordBase, ChannelRecordOwnProperties, ChannelType } from "./ChannelRecord";
|
||||
|
||||
export type GuildVocalChannelRecord = GuildVoiceChannelRecord | GuildStageVoiceChannelRecord;
|
||||
|
||||
export type GuildVocalChannelProperties = Optional<PartialOnUndefined<OmitOptional<ChannelRecordOwnProperties<GuildVocalChannelRecordBase>>>, Nullish, "guild_id" | "name" | "permissionOverwrites_">;
|
||||
|
||||
type GuildVocalChannelType = ChannelType.GUILD_VOICE | ChannelType.GUILD_STAGE_VOICE;
|
||||
|
||||
export declare abstract class GuildVocalChannelRecordBase extends ChannelRecordBase {
|
||||
constructor(channelProperties: GuildVocalChannelProperties);
|
||||
|
||||
static fromServer<Type extends GuildVocalChannelType | Nullish = undefined>(
|
||||
/** @todo */
|
||||
channelFromServer: { type?: Type; } & Record<string, any>,
|
||||
guildId?: string | null
|
||||
): {
|
||||
[ChannelType.GUILD_STAGE_VOICE]: GuildStageVoiceChannelRecord;
|
||||
[ChannelType.GUILD_VOICE]: GuildVoiceChannelRecord;
|
||||
}[Type extends GuildVocalChannelType ? Type : ChannelType.GUILD_VOICE];
|
||||
|
||||
application_id: undefined;
|
||||
appliedTags?: undefined;
|
||||
availableTags?: undefined;
|
||||
bitrate_: Defined<ChannelRecordBase["bitrate_"]>;
|
||||
blockedUserWarningDismissed?: undefined;
|
||||
defaultAutoArchiveDuration?: undefined;
|
||||
defaultForumLayout?: undefined;
|
||||
defaultReactionEmoji?: undefined;
|
||||
defaultSortOrder?: undefined;
|
||||
defaultThreadRateLimitPerUser?: undefined;
|
||||
flags_: Defined<ChannelRecordBase["flags_"]>;
|
||||
icon?: undefined;
|
||||
iconEmoji: ChannelRecordBase["iconEmoji"];
|
||||
isMessageRequest?: undefined;
|
||||
isMessageRequestTimestamp?: undefined;
|
||||
isSpam?: undefined;
|
||||
lastMessageId: ChannelRecordBase["lastMessageId"];
|
||||
lastPinTimestamp: undefined;
|
||||
linkedLobby?: undefined;
|
||||
member?: undefined;
|
||||
memberCount?: undefined;
|
||||
memberIdsPreview?: undefined;
|
||||
/** @todo May only be nullish. */
|
||||
memberListId: ChannelRecordBase["memberListId"];
|
||||
messageCount?: undefined;
|
||||
nicks?: undefined;
|
||||
nsfw_: Defined<ChannelRecordBase["nsfw_"]>;
|
||||
/** @todo May only be nullish. */
|
||||
originChannelId: ChannelRecordBase["originChannelId"];
|
||||
ownerId?: undefined;
|
||||
parent_id: ChannelRecordBase["parent_id"];
|
||||
parentChannelThreadType?: undefined;
|
||||
permissionOverwrites_: Defined<ChannelRecordBase["permissionOverwrites_"]>;
|
||||
position_: Defined<ChannelRecordBase["position_"]>;
|
||||
rateLimitPerUser_: Defined<ChannelRecordBase["rateLimitPerUser_"]>;
|
||||
rawRecipients?: undefined;
|
||||
recipients?: undefined;
|
||||
rtcRegion: Defined<ChannelRecordBase["rtcRegion"]>;
|
||||
safetyWarnings?: undefined;
|
||||
template?: undefined;
|
||||
themeColor: Nullish;
|
||||
threadMetadata?: undefined;
|
||||
topic_: Nullish;
|
||||
totalMessageSent?: undefined;
|
||||
type: GuildVocalChannelType;
|
||||
userLimit_: Defined<ChannelRecordBase["userLimit_"]>;
|
||||
version: ChannelRecordBase["version"];
|
||||
videoQualityMode: ChannelRecordBase["videoQualityMode"];
|
||||
voiceBackgroundDisplay: Defined<ChannelRecordBase["voiceBackgroundDisplay"]>;
|
||||
}
|
||||
|
||||
export type GuildVoiceChannelProperties = Optional<PartialOnUndefined<OmitOptional<ChannelRecordOwnProperties<GuildVoiceChannelRecord>>>, Nullish, "guild_id" | "name" | "permissionOverwrites_">;
|
||||
|
||||
export declare class GuildVoiceChannelRecord extends GuildVocalChannelRecordBase {
|
||||
constructor(channelProperties: GuildVoiceChannelProperties);
|
||||
|
||||
type: ChannelType.GUILD_VOICE;
|
||||
}
|
||||
|
||||
export type GuildStageVoiceChannelProperties = Optional<PartialOnUndefined<OmitOptional<ChannelRecordOwnProperties<GuildStageVoiceChannelRecord>>>, Nullish, "guild_id" | "name" | "permissionOverwrites_">;
|
||||
|
||||
export declare class GuildStageVoiceChannelRecord extends GuildVocalChannelRecordBase {
|
||||
constructor(channelProperties: GuildStageVoiceChannelProperties);
|
||||
|
||||
type: ChannelType.GUILD_STAGE_VOICE;
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Defined, Nullish, OmitOptional, Optional, PartialOnUndefined } from "../../internal";
|
||||
import type { ChannelRecipient, ChannelRecordBase, ChannelRecordOwnProperties, ChannelType } from "./ChannelRecord";
|
||||
|
||||
export type PrivateChannelRecord = DMChannelRecord | GroupDMChannelRecord;
|
||||
|
||||
export type PrivateChannelProperties = Omit<Optional<PartialOnUndefined<OmitOptional<ChannelRecordOwnProperties<PrivateChannelRecordBase>>>, Nullish, "guild_id" | "name" | "safetyWarnings">, "rawRecipients" | "recipients">
|
||||
& { rawRecipients?: Readonly<PrivateChannelRecordBase["rawRecipients"]> | Nullish; recipients?: Readonly<PrivateChannelRecordBase["recipients"]> | Nullish; };
|
||||
|
||||
type PrivateChannelType = ChannelType.DM | ChannelType.GROUP_DM;
|
||||
|
||||
export declare abstract class PrivateChannelRecordBase extends ChannelRecordBase {
|
||||
constructor(channelProperties: PrivateChannelProperties);
|
||||
|
||||
static fromServer<Type extends PrivateChannelType | Nullish = undefined>(
|
||||
/** @todo */
|
||||
channelFromServer: { type?: Type; } & Record<string, any>
|
||||
): {
|
||||
[ChannelType.DM]: DMChannelRecord;
|
||||
[ChannelType.GROUP_DM]: GroupDMChannelRecord;
|
||||
}[Type extends PrivateChannelType ? Type : ChannelType.DM];
|
||||
static sortRecipients(recipients: ChannelRecipient[] | Nullish, channelId: string): string[];
|
||||
|
||||
addRecipient(recipientUserId: string, nickname: string | undefined, currentUserId: string): this;
|
||||
getRecipientId(): string | undefined;
|
||||
removeRecipient(recipientUserId: string): this;
|
||||
|
||||
application_id: ChannelRecordBase["application_id"];
|
||||
appliedTags?: undefined;
|
||||
availableTags?: undefined;
|
||||
bitrate_?: undefined;
|
||||
blockedUserWarningDismissed: ChannelRecordBase["blockedUserWarningDismissed"];
|
||||
defaultAutoArchiveDuration?: undefined;
|
||||
defaultForumLayout?: undefined;
|
||||
defaultReactionEmoji?: undefined;
|
||||
defaultSortOrder?: undefined;
|
||||
defaultThreadRateLimitPerUser?: undefined;
|
||||
flags_: Defined<ChannelRecordBase["flags_"]>;
|
||||
guild_id: null;
|
||||
icon: ChannelRecordBase["icon"];
|
||||
iconEmoji?: undefined;
|
||||
isMessageRequest: ChannelRecordBase["isMessageRequest"];
|
||||
isMessageRequestTimestamp: ChannelRecordBase["isMessageRequestTimestamp"];
|
||||
isSpam: Defined<ChannelRecordBase["isSpam"]>;
|
||||
lastMessageId: ChannelRecordBase["lastMessageId"];
|
||||
lastPinTimestamp: ChannelRecordBase["lastPinTimestamp"];
|
||||
linkedLobby?: undefined;
|
||||
member?: undefined;
|
||||
memberCount?: undefined;
|
||||
memberIdsPreview?: undefined;
|
||||
memberListId?: undefined;
|
||||
messageCount?: undefined;
|
||||
nicks: Defined<ChannelRecordBase["nicks"]>;
|
||||
nsfw_?: undefined;
|
||||
originChannelId?: undefined;
|
||||
ownerId: ChannelRecordBase["ownerId"];
|
||||
parent_id?: undefined;
|
||||
parentChannelThreadType?: undefined;
|
||||
permissionOverwrites_?: undefined;
|
||||
position_?: undefined;
|
||||
rateLimitPerUser_?: undefined;
|
||||
rawRecipients: Defined<ChannelRecordBase["rawRecipients"]>;
|
||||
recipients: Defined<ChannelRecordBase["recipients"]>;
|
||||
rtcRegion?: undefined;
|
||||
safetyWarnings: ChannelRecordBase["safetyWarnings"];
|
||||
template?: undefined;
|
||||
themeColor?: undefined;
|
||||
threadMetadata?: undefined;
|
||||
topic_?: undefined;
|
||||
totalMessageSent?: undefined;
|
||||
type: PrivateChannelType;
|
||||
userLimit_?: undefined;
|
||||
version?: undefined;
|
||||
videoQualityMode?: undefined;
|
||||
voiceBackgroundDisplay?: undefined;
|
||||
}
|
||||
|
||||
export type DMChannelProperties = Omit<Optional<PartialOnUndefined<OmitOptional<ChannelRecordOwnProperties<DMChannelRecord>>>, Nullish, "guild_id" | "name" | "safetyWarnings">, "rawRecipients" | "recipients">
|
||||
& { rawRecipients?: Readonly<DMChannelRecord["rawRecipients"]> | Nullish; recipients?: Readonly<DMChannelRecord["recipients"]> | Nullish; };
|
||||
|
||||
export declare class DMChannelRecord extends PrivateChannelRecordBase {
|
||||
constructor(channelProperties: DMChannelProperties);
|
||||
|
||||
application_id: undefined;
|
||||
icon: undefined;
|
||||
name: "";
|
||||
ownerId: undefined;
|
||||
type: ChannelType.DM;
|
||||
}
|
||||
|
||||
export type GroupDMChannelProperties = Omit<Optional<PartialOnUndefined<OmitOptional<ChannelRecordOwnProperties<GroupDMChannelRecord>>>, Nullish, "guild_id" | "name" | "safetyWarnings">, "rawRecipients" | "recipients">
|
||||
& { rawRecipients?: Readonly<GroupDMChannelRecord["rawRecipients"]> | Nullish; recipients?: Readonly<GroupDMChannelRecord["recipients"]> | Nullish; };
|
||||
|
||||
export declare class GroupDMChannelRecord extends PrivateChannelRecordBase {
|
||||
constructor(channelProperties: GroupDMChannelProperties);
|
||||
|
||||
isMessageRequest: undefined;
|
||||
isMessageRequestTimestamp: undefined;
|
||||
ownerId: PrivateChannelRecordBase["ownerId"];
|
||||
type: ChannelType.GROUP_DM;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Defined, Nullish, OmitOptional, Optional, PartialOnUndefined } from "../../internal";
|
||||
import type { ChannelRecordBase, ChannelRecordOwnProperties, ChannelType } from "./ChannelRecord";
|
||||
|
||||
export type ThreadChannelProperties = Optional<PartialOnUndefined<OmitOptional<ChannelRecordOwnProperties<ThreadChannelRecord>>>, Nullish, "appliedTags" | "guild_id" | "name">;
|
||||
|
||||
type ThreadChannelType = ChannelType.ANNOUNCEMENT_THREAD | ChannelType.PUBLIC_THREAD | ChannelType.PRIVATE_THREAD;
|
||||
|
||||
export declare class ThreadChannelRecord<ChannelType extends ThreadChannelType = ThreadChannelType> extends ChannelRecordBase {
|
||||
constructor(channelProperties: ThreadChannelProperties);
|
||||
|
||||
static fromServer<Type extends ThreadChannelType | Nullish = undefined>(
|
||||
/** @todo */
|
||||
channelFromServer: { type?: Type; } & Record<string, any>,
|
||||
guildId?: string | null
|
||||
): ThreadChannelRecord<Type extends ThreadChannelType ? Type : ChannelType.PUBLIC_THREAD>;
|
||||
|
||||
application_id?: undefined;
|
||||
appliedTags: Defined<ChannelRecordBase["appliedTags"]>;
|
||||
availableTags?: undefined;
|
||||
bitrate_: undefined;
|
||||
blockedUserWarningDismissed?: undefined;
|
||||
defaultAutoArchiveDuration?: undefined;
|
||||
defaultForumLayout?: undefined;
|
||||
defaultReactionEmoji?: undefined;
|
||||
defaultSortOrder?: undefined;
|
||||
defaultThreadRateLimitPerUser?: undefined;
|
||||
flags_: Defined<ChannelRecordBase["flags_"]>;
|
||||
icon?: undefined;
|
||||
iconEmoji?: undefined;
|
||||
isMessageRequest?: undefined;
|
||||
isMessageRequestTimestamp?: undefined;
|
||||
isSpam?: undefined;
|
||||
lastMessageId: ChannelRecordBase["lastMessageId"];
|
||||
lastPinTimestamp: ChannelRecordBase["lastMessageId"];
|
||||
linkedLobby?: undefined;
|
||||
member: ChannelRecordBase["member"];
|
||||
memberCount: Defined<ChannelRecordBase["memberCount"]>;
|
||||
memberIdsPreview: Defined<ChannelRecordBase["memberIdsPreview"]>;
|
||||
memberListId?: undefined;
|
||||
messageCount: Defined<ChannelRecordBase["messageCount"]>;
|
||||
nicks?: undefined;
|
||||
nsfw_: Defined<ChannelRecordBase["nsfw_"]>;
|
||||
originChannelId?: undefined;
|
||||
ownerId: Defined<ChannelRecordBase["ownerId"]>;
|
||||
parent_id: NonNullable<ChannelRecordBase["parent_id"]>;
|
||||
parentChannelThreadType: Defined<ChannelRecordBase["parentChannelThreadType"]>;
|
||||
permissionOverwrites_?: undefined;
|
||||
position_?: undefined;
|
||||
rateLimitPerUser_: Defined<ChannelRecordBase["rateLimitPerUser_"]>;
|
||||
rawRecipients?: undefined;
|
||||
recipients?: undefined;
|
||||
rtcRegion: undefined;
|
||||
safetyWarnings?: undefined;
|
||||
template?: undefined;
|
||||
themeColor?: undefined;
|
||||
threadMetadata: ChannelRecordBase["threadMetadata"];
|
||||
topic_?: undefined;
|
||||
totalMessageSent: ChannelRecordBase["rateLimitPerUser_"];
|
||||
type: ChannelType;
|
||||
userLimit_: undefined;
|
||||
version?: undefined;
|
||||
videoQualityMode: undefined;
|
||||
voiceBackgroundDisplay?: undefined;
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Defined, Nullish, Optional } from "../../internal";
|
||||
import type { ChannelRecordBase, ChannelRecordOwnProperties, ChannelType } from "./ChannelRecord";
|
||||
|
||||
export type UnknownChannelProperties = Optional<ChannelRecordOwnProperties<UnknownChannelRecord>, Nullish, "guild_id" | "name">;
|
||||
|
||||
export declare class UnknownChannelRecord extends ChannelRecordBase {
|
||||
constructor(channelProperties: UnknownChannelProperties);
|
||||
|
||||
static fromServer(
|
||||
/** @todo */
|
||||
channelFromServer: { type?: ChannelType.UNKNOWN | Nullish; } & Record<string, any>,
|
||||
guildId?: string | null
|
||||
): UnknownChannelRecord;
|
||||
|
||||
application_id: ChannelRecordBase["application_id"];
|
||||
appliedTags: ChannelRecordBase["appliedTags"];
|
||||
availableTags: ChannelRecordBase["availableTags"];
|
||||
bitrate_: ChannelRecordBase["bitrate_"];
|
||||
blockedUserWarningDismissed: ChannelRecordBase["blockedUserWarningDismissed"];
|
||||
defaultAutoArchiveDuration: ChannelRecordBase["defaultAutoArchiveDuration"];
|
||||
defaultForumLayout: ChannelRecordBase["defaultForumLayout"];
|
||||
defaultReactionEmoji: ChannelRecordBase["defaultReactionEmoji"];
|
||||
defaultSortOrder: ChannelRecordBase["defaultSortOrder"];
|
||||
defaultThreadRateLimitPerUser: ChannelRecordBase["defaultThreadRateLimitPerUser"];
|
||||
flags_: Defined<ChannelRecordBase["flags_"]>;
|
||||
icon: ChannelRecordBase["icon"];
|
||||
iconEmoji: ChannelRecordBase["iconEmoji"];
|
||||
isMessageRequest: ChannelRecordBase["isMessageRequest"];
|
||||
isMessageRequestTimestamp: ChannelRecordBase["isMessageRequestTimestamp"];
|
||||
isSpam: ChannelRecordBase["isSpam"];
|
||||
lastMessageId: ChannelRecordBase["lastMessageId"];
|
||||
lastPinTimestamp: ChannelRecordBase["lastPinTimestamp"];
|
||||
linkedLobby: ChannelRecordBase["linkedLobby"];
|
||||
member: ChannelRecordBase["member"];
|
||||
memberCount: ChannelRecordBase["memberCount"];
|
||||
memberIdsPreview: ChannelRecordBase["memberIdsPreview"];
|
||||
memberListId: ChannelRecordBase["memberListId"];
|
||||
messageCount: ChannelRecordBase["messageCount"];
|
||||
nicks: ChannelRecordBase["nicks"];
|
||||
nsfw_: ChannelRecordBase["nsfw_"];
|
||||
originChannelId: ChannelRecordBase["originChannelId"];
|
||||
ownerId: ChannelRecordBase["ownerId"];
|
||||
parent_id: ChannelRecordBase["parent_id"];
|
||||
parentChannelThreadType: undefined;
|
||||
permissionOverwrites_: Defined<ChannelRecordBase["permissionOverwrites_"]>;
|
||||
position_: ChannelRecordBase["position_"];
|
||||
rateLimitPerUser_: ChannelRecordBase["rateLimitPerUser_"];
|
||||
rawRecipients: Defined<ChannelRecordBase["rawRecipients"]>;
|
||||
recipients: Defined<ChannelRecordBase["recipients"]>;
|
||||
rtcRegion: ChannelRecordBase["rtcRegion"];
|
||||
safetyWarnings: ChannelRecordBase["safetyWarnings"];
|
||||
template: ChannelRecordBase["template"];
|
||||
themeColor: ChannelRecordBase["themeColor"];
|
||||
threadMetadata: ChannelRecordBase["threadMetadata"];
|
||||
topic_: ChannelRecordBase["topic_"];
|
||||
totalMessageSent: ChannelRecordBase["totalMessageSent"];
|
||||
type: ChannelType.UNKNOWN;
|
||||
userLimit_: ChannelRecordBase["userLimit_"];
|
||||
version: ChannelRecordBase["version"];
|
||||
videoQualityMode: ChannelRecordBase["videoQualityMode"];
|
||||
}
|
13
packages/discord-types/src/general/channels/index.ts
Normal file
13
packages/discord-types/src/general/channels/index.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export * from "./ChannelRecord";
|
||||
export * from "./ForumChannelRecord";
|
||||
export * from "./GuildTextualChannelRecord";
|
||||
export * from "./GuildVocalChannelRecord";
|
||||
export * from "./PrivateChannelRecord";
|
||||
export * from "./ThreadChannelRecord";
|
||||
export * from "./UnknownChannelRecord";
|
85
packages/discord-types/src/general/emojis/Emoji.ts
Normal file
85
packages/discord-types/src/general/emojis/Emoji.ts
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Nullish } from "../../internal";
|
||||
|
||||
export type Emoji = UnicodeEmoji | GuildEmoji;
|
||||
|
||||
// Original name: Emoji
|
||||
export declare class UnicodeEmoji {
|
||||
constructor(emojiObject: UnicodeEmojiObject | UnicodeEmojiObjectDiversityChild);
|
||||
|
||||
get allNamesString(): string;
|
||||
get animated(): false;
|
||||
get defaultDiversityChild(): UnicodeEmojiObjectDiversityChild | Nullish;
|
||||
/**
|
||||
* @param callback The iteratee. Iteration will terminate early if it returns false.
|
||||
*/
|
||||
forEachDiversity(callback: (value: string, index: number, array: string[]) => unknown): void;
|
||||
/**
|
||||
* @param callback The iteratee. Iteration will terminate early if it returns false.
|
||||
*/
|
||||
forEachName(callback: (value: string, index: number, array: string[]) => unknown): void;
|
||||
get hasDiversity(): UnicodeEmojiObject["hasDiversity"];
|
||||
get hasDiversityParent(): UnicodeEmojiObjectDiversityChild["hasDiversityParent"];
|
||||
get hasMultiDiversity(): UnicodeEmojiObject["hasMultiDiversity"];
|
||||
get hasMultiDiversityParent(): UnicodeEmojiObjectDiversityChild["hasMultiDiversityParent"];
|
||||
get managed(): true;
|
||||
get name(): string;
|
||||
get names(): UnicodeEmojiObject["names"];
|
||||
get optionallyDiverseSequence(): string;
|
||||
setSpriteSheetIndex(index: number): void;
|
||||
get unicodeVersion(): number;
|
||||
get url(): string;
|
||||
|
||||
diversityChildren: { [diversity: string]: UnicodeEmojiObjectDiversityChild; };
|
||||
emojiObject: UnicodeEmojiObject;
|
||||
guildId: undefined;
|
||||
id: undefined;
|
||||
index: number | undefined;
|
||||
originalName: string | undefined;
|
||||
surrogates: string;
|
||||
type: EmojiType.UNICODE;
|
||||
uniqueName: string;
|
||||
useSpriteSheet: boolean | undefined;
|
||||
}
|
||||
|
||||
export interface UnicodeEmojiObject {
|
||||
diversityChildren?: UnicodeEmojiObjectDiversityChild[];
|
||||
hasDiversity?: boolean;
|
||||
hasMultiDiversity?: boolean;
|
||||
names: [string, ...string[]];
|
||||
surrogates: string;
|
||||
unicodeVersion?: number;
|
||||
}
|
||||
|
||||
export interface UnicodeEmojiObjectDiversityChild extends Pick<UnicodeEmojiObject, "names" | "surrogates" | "unicodeVersion"> {
|
||||
diversity: [string] | [string, string];
|
||||
hasDiversityParent?: boolean;
|
||||
hasMultiDiversityParent?: boolean;
|
||||
}
|
||||
|
||||
export interface GuildEmoji {
|
||||
allNamesString: string;
|
||||
animated: boolean;
|
||||
available: boolean;
|
||||
guildId: string;
|
||||
id: string;
|
||||
/** Only true for integrated emojis. */
|
||||
managed: boolean;
|
||||
name: string;
|
||||
originalName?: string;
|
||||
/** False for emoticons. */
|
||||
require_colons: boolean;
|
||||
roles: string[];
|
||||
type: EmojiType.GUILD;
|
||||
}
|
||||
|
||||
// Original name: EmojiTypes
|
||||
export enum EmojiType {
|
||||
UNICODE = 0,
|
||||
GUILD = 1,
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { CollectionChain } from "lodash";
|
||||
|
||||
import type { Defined } from "../../internal";
|
||||
import type { Emoji, EmojiType, GuildEmoji, UnicodeEmoji } from "./Emoji";
|
||||
|
||||
export declare class EmojiDisambiguations {
|
||||
constructor(guildId: string | null);
|
||||
|
||||
static _lastInstance: EmojiDisambiguations | null;
|
||||
static clear(guildId: string): void;
|
||||
static get(guildId?: string | null): EmojiDisambiguations;
|
||||
static reset(): void;
|
||||
static resetFavorites(): void;
|
||||
static resetFrequentlyUsed(): void;
|
||||
static resetFrequentlyUsedReactionEmojis(): void;
|
||||
|
||||
_buildDisambiguatedCustomEmoji(): void;
|
||||
ensureDisambiguated(): void;
|
||||
get favoriteEmojisWithoutFetchingLatest(): Emoji[];
|
||||
getById(emojiId: string): GuildEmoji | undefined;
|
||||
getByName<Type extends EmojiType>(emojiName: string):
|
||||
(Type extends EmojiType.GUILD ? GuildEmoji : UnicodeEmoji) | undefined;
|
||||
getCustomEmoji(): Defined<EmojiDisambiguations["customEmojis"]>;
|
||||
getCustomEmoticonRegex(): RegExp | null;
|
||||
getDisambiguatedEmoji(): Emoji[];
|
||||
getEmojiInPriorityOrderWithoutFetchingLatest(): Emoji[];
|
||||
getEmoticonByName(emoticonName: string): GuildEmoji | undefined;
|
||||
getEscapedCustomEmoticonNames(): string;
|
||||
getFrequentlyUsedEmojisWithoutFetchingLatest(): Emoji[];
|
||||
getFrequentlyUsedReactionEmojisWithoutFetchingLatest(): Emoji[];
|
||||
getGroupedCustomEmoji(): Defined<EmojiDisambiguations["groupedCustomEmojis"]>;
|
||||
getNewlyAddedEmojiForGuild(guildId: string): GuildEmoji[];
|
||||
getTopEmojiWithoutFetchingLatest(guildId: string): GuildEmoji[];
|
||||
nameMatchesChain(predicate: (value: string, index: number, array: string[]) => unknown): CollectionChain<string>;
|
||||
rebuildFavoriteEmojisWithoutFetchingLatest(): {
|
||||
favoriteNamesAndIds: Set<string>;
|
||||
favorites: Emoji[];
|
||||
};
|
||||
|
||||
customEmojis: { [emojiName: string]: GuildEmoji; } | undefined;
|
||||
disambiguatedEmoji: Emoji[] | null;
|
||||
emojisById: { [emojiId: string]: GuildEmoji; } | undefined;
|
||||
emojisByName: { [emojiName: string]: Emoji; } | undefined;
|
||||
emoticonRegex: RegExp | null;
|
||||
emoticonsByName: { [emoticonName: string]: GuildEmoji; } | undefined;
|
||||
escapedEmoticonNames: string | null;
|
||||
favoriteNamesAndIds: Set<string> | null;
|
||||
favorites: Emoji[] | null;
|
||||
frequentlyUsed: Emoji[] | null;
|
||||
frequentlyUsedReactionEmojis: Emoji[] | null;
|
||||
groupedCustomEmojis: { [guildId: string]: GuildEmoji; } | undefined;
|
||||
guildId: string | null;
|
||||
isFavoriteEmojiWithoutFetchingLatest: (emoji?: Emoji | null) => boolean;
|
||||
newlyAddedEmoji: { [guildId: string]: GuildEmoji; } | null;
|
||||
topEmojis: GuildEmoji[] | null;
|
||||
unicodeAliases: Record<string, string> | undefined;
|
||||
}
|
35
packages/discord-types/src/general/emojis/GuildEmojis.ts
Normal file
35
packages/discord-types/src/general/emojis/GuildEmojis.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { GuildEmoji } from "./Emoji";
|
||||
|
||||
export declare class GuildEmojis {
|
||||
constructor(
|
||||
guildId: string,
|
||||
userId: string,
|
||||
emojis: GuildEmoji[],
|
||||
canSeeServerSubIAP?: boolean /* = false */
|
||||
);
|
||||
|
||||
build(): void;
|
||||
get emojis(): GuildEmoji[];
|
||||
get emoticons(): GuildEmoji[];
|
||||
getEmoji(emojiId: string): GuildEmoji | undefined;
|
||||
getUsableEmoji(emojiId: string): GuildEmoji | null;
|
||||
isUsable(emoji: GuildEmoji): boolean;
|
||||
get rawEmojis(): GuildEmoji[];
|
||||
get usableEmojis(): GuildEmoji[];
|
||||
|
||||
_canSeeServerSubIAP: boolean;
|
||||
_dirty: boolean;
|
||||
_emojiMap: { [emojiId: string]: GuildEmoji; };
|
||||
_emojis: GuildEmoji[];
|
||||
_emoticons: GuildEmoji[];
|
||||
_totalUsable: number;
|
||||
_usableEmojis: GuildEmoji[];
|
||||
_userId: string;
|
||||
id: string;
|
||||
}
|
9
packages/discord-types/src/general/emojis/index.ts
Normal file
9
packages/discord-types/src/general/emojis/index.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export * from "./Emoji";
|
||||
export * from "./EmojiDisambiguations";
|
||||
export * from "./GuildEmojis";
|
27
packages/discord-types/src/general/index.ts
Normal file
27
packages/discord-types/src/general/index.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export * from "./Activity";
|
||||
export * from "./ApplicationCommand";
|
||||
export * from "./ApplicationRecord";
|
||||
export * from "./channels";
|
||||
export * from "./Clan";
|
||||
export * from "./CompanyRecord";
|
||||
export * from "./DisplayProfile";
|
||||
export * from "./Draft";
|
||||
export * from "./emojis";
|
||||
export * from "./Frecency";
|
||||
export * from "./GuildMember";
|
||||
export * from "./GuildMemberProfile";
|
||||
export * from "./GuildRecord";
|
||||
export * from "./messages";
|
||||
export * from "./misc";
|
||||
export * from "./Permissions";
|
||||
export * from "./ReadState";
|
||||
export * from "./Record";
|
||||
export * from "./Role";
|
||||
export * from "./UserProfile";
|
||||
export * from "./UserRecord";
|
195
packages/discord-types/src/general/messages/ChannelMessages.ts
Normal file
195
packages/discord-types/src/general/messages/ChannelMessages.ts
Normal file
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Nullish, Optional } from "../../internal";
|
||||
import type { MessageCache } from "./MessageCache";
|
||||
import type { MessageProperties, MessageRecord } from "./MessageRecord";
|
||||
|
||||
export type ChannelMessagesOwnProperties = Pick<ChannelMessages, "_after" | "_array" | "_before" | "_map" | "cached" | "channelId" | "error" | "focusTargetId" | "hasFetched" | "hasMoreAfter" | "hasMoreBefore" | "jumped" | "jumpedToPresent" | "jumpFlash" | "jumpReturnTargetId" | "jumpSequenceId" | "jumpTargetId" | "jumpTargetOffset" | "jumpType" | "loadingMore" | "ready" | "revealedMessageId">;
|
||||
|
||||
export declare class ChannelMessages {
|
||||
constructor(channelId: string);
|
||||
|
||||
static _channelMessages: { [channelId: string]: ChannelMessages; };
|
||||
static clear(channelId: string): void;
|
||||
static clearCache(channelId: string): void;
|
||||
static commit(channelMessages: ChannelMessages): void;
|
||||
/**
|
||||
* @param callback The iteratee. Iteration will terminate early if it returns false.
|
||||
*/
|
||||
static forEach(callback: (value: ChannelMessages, index: number, array: ChannelMessages[]) => unknown): void;
|
||||
static get(channelId: string): ChannelMessages | undefined;
|
||||
static getOrCreate(channelId: string): ChannelMessages;
|
||||
static hasPresent(channelId: string): boolean;
|
||||
|
||||
_clearMessages(): void;
|
||||
_merge(
|
||||
messages: readonly MessageRecord[],
|
||||
isBefore?: boolean /* = false */,
|
||||
clearCache?: boolean /* = false */
|
||||
): void;
|
||||
/** @throws {Error} `messages` must be sorted in descending order by ID. */
|
||||
addCachedMessages(messages: readonly MessageRecord[], cached: boolean): ChannelMessages;
|
||||
filter<T extends MessageRecord>(
|
||||
predicate: (value: MessageRecord, index: number, array: MessageRecord[]) => value is T,
|
||||
thisArg?: unknown
|
||||
): T[];
|
||||
filter(
|
||||
predicate: (value: MessageRecord, index: number, array: MessageRecord[]) => unknown,
|
||||
thisArg?: unknown
|
||||
): MessageRecord[];
|
||||
findNewest<T extends MessageRecord>(
|
||||
predicate: (value: MessageRecord, index: number, array: MessageRecord[]) => value is T
|
||||
): T | undefined;
|
||||
findNewest(
|
||||
predicate: (value: MessageRecord, index: number, array: MessageRecord[]) => unknown
|
||||
): MessageRecord | undefined;
|
||||
findOldest<T extends MessageRecord>(
|
||||
predicate: (value: MessageRecord, index: number, array: MessageRecord[]) => value is T
|
||||
): T | undefined;
|
||||
findOldest(
|
||||
predicate: (value: MessageRecord, index: number, array: MessageRecord[]) => unknown
|
||||
): MessageRecord | undefined;
|
||||
first(): MessageRecord | undefined;
|
||||
focusOnMessage(messageId: string): ChannelMessages;
|
||||
forAll(
|
||||
callback: (value: MessageRecord, index: number, array: MessageRecord[]) => void,
|
||||
thisArg?: unknown
|
||||
): void;
|
||||
forEach<BreakOnReturnFalse extends boolean | undefined = undefined>(
|
||||
callback: (value: MessageRecord, index: number, array: MessageRecord[]) =>
|
||||
[BreakOnReturnFalse] extends [false | undefined]
|
||||
// https://github.com/typescript-eslint/typescript-eslint/issues/8113
|
||||
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
|
||||
? void
|
||||
: unknown,
|
||||
thisArg?: unknown,
|
||||
breakOnReturnFalse?: BreakOnReturnFalse
|
||||
): void;
|
||||
get(messageId: string, searchCaches?: boolean /* = false */): MessageRecord | undefined;
|
||||
getAfter(messageId: string): MessageRecord | null;
|
||||
getByIndex(index: number): MessageRecord | undefined;
|
||||
/** If count is -1, all results will be returned. */
|
||||
getManyAfter(
|
||||
messageId: string,
|
||||
count: number,
|
||||
callback?: ((message: MessageRecord) => void) | null
|
||||
): MessageRecord[] | null;
|
||||
/** If count is -1, all results will be returned. */
|
||||
getManyBefore(
|
||||
messageId: string,
|
||||
count: number,
|
||||
callback?: ((message: MessageRecord) => void) | null
|
||||
): MessageRecord[] | null;
|
||||
has(messageId: string, searchCaches?: boolean): boolean;
|
||||
hasAfterCached(messageId: string): boolean;
|
||||
hasBeforeCached(messageId: string): boolean;
|
||||
hasPresent(): boolean;
|
||||
indexOf(messageId: string): number;
|
||||
jumpToMessage(
|
||||
messageId: string | null,
|
||||
jumpFlash?: boolean /* = true */,
|
||||
jumpTargetOffset?: number | null,
|
||||
jumpReturnTargetId?: string | null,
|
||||
jumpType?: JumpType | null /* = JumpType.ANIMATED */
|
||||
): ChannelMessages;
|
||||
jumpToPresent(countFromPresent: number): ChannelMessages;
|
||||
last(): MessageRecord | undefined;
|
||||
get length(): number;
|
||||
loadComplete(messageProperties: MessageProperties): ChannelMessages;
|
||||
loadFromCache(isBefore: boolean, extractCount: number): ChannelMessages;
|
||||
loadStart(jumpConfig?: {
|
||||
messageId?: string | Nullish;
|
||||
offset?: number | Nullish;
|
||||
present?: boolean | Nullish;
|
||||
returnMessageId?: string | Nullish;
|
||||
} | null): ChannelMessages;
|
||||
map<T>(
|
||||
callback: (value: MessageRecord, index: number, array: MessageRecord[]) => T,
|
||||
thisArg?: unknown
|
||||
): T[];
|
||||
merge(
|
||||
messages: readonly MessageRecord[],
|
||||
isBefore?: boolean /* = false */,
|
||||
clearCache?: boolean /* = false */
|
||||
): ChannelMessages;
|
||||
mergeDelta(
|
||||
messages?: readonly MessageRecord[] /* = [] */,
|
||||
messageProperties?: readonly MessageProperties[] /* = [] */,
|
||||
excludedMessageIds?: readonly string[] /* = [] */
|
||||
): ChannelMessages;
|
||||
mutate(
|
||||
mutaterOrObject?: ((channelMessages: ChannelMessages) => void)
|
||||
| Optional<Omit<ChannelMessagesOwnProperties, "_after" | "_array" | "_before" | "_map" | "channelId">>,
|
||||
deep?: boolean /* = false */
|
||||
): ChannelMessages;
|
||||
receiveMessage(
|
||||
messageProperties: MessageProperties,
|
||||
truncateTop?: boolean /* = true */
|
||||
): ChannelMessages | this;
|
||||
receivePushNotification(messageProperties: MessageProperties): ChannelMessages | this;
|
||||
receiveReactionInAppNotification(messageProperties: MessageProperties): ChannelMessages | this;
|
||||
reduce(
|
||||
callback: (
|
||||
previousValue: MessageRecord,
|
||||
currentValue: MessageRecord,
|
||||
currentIndex: number,
|
||||
array: MessageRecord[]
|
||||
) => MessageRecord,
|
||||
initialValue?: MessageRecord
|
||||
): MessageRecord;
|
||||
reduce<T>(
|
||||
callback: (
|
||||
previousValue: MessageRecord,
|
||||
currentValue: T,
|
||||
currentIndex: number,
|
||||
array: MessageRecord[]
|
||||
) => T,
|
||||
initialValue: T
|
||||
): T;
|
||||
remove(messageId: string): ChannelMessages;
|
||||
removeMany(messageIds: readonly string[]): ChannelMessages | this;
|
||||
replace(messageId: string, message: MessageRecord): ChannelMessages | this;
|
||||
reset(messages: MessageRecord[]): ChannelMessages;
|
||||
some(
|
||||
predicate: (value: MessageRecord, index: number, array: MessageRecord[]) => unknown,
|
||||
thisArg?: unknown
|
||||
): boolean;
|
||||
toArray(): MessageRecord[];
|
||||
truncate(count: number, mutateDeep?: boolean /* = true */): ChannelMessages | this;
|
||||
truncateBottom(count: number, mutateDeep?: boolean /* = true */): ChannelMessages | this;
|
||||
truncateTop(count: number, mutateDeep?: boolean /* = true */): ChannelMessages | this;
|
||||
update(messageId: string, updater: (message: MessageRecord) => MessageRecord): ChannelMessages | this;
|
||||
|
||||
_after: MessageCache;
|
||||
_array: MessageRecord[];
|
||||
_before: MessageCache;
|
||||
_map: { [messageId: string]: MessageRecord; };
|
||||
cached: boolean;
|
||||
channelId: string;
|
||||
error: boolean;
|
||||
focusTargetId: string | undefined;
|
||||
hasFetched: boolean;
|
||||
hasMoreAfter: boolean;
|
||||
hasMoreBefore: boolean;
|
||||
jumped: boolean;
|
||||
jumpedToPresent: boolean;
|
||||
jumpFlash: boolean;
|
||||
jumpReturnTargetId: string | Nullish;
|
||||
jumpSequenceId: number;
|
||||
jumpTargetId: string | null;
|
||||
jumpTargetOffset: number;
|
||||
jumpType: JumpType;
|
||||
loadingMore: boolean;
|
||||
ready: boolean;
|
||||
revealedMessageId: string | null;
|
||||
}
|
||||
|
||||
// Original name: JumpTypes
|
||||
export enum JumpType {
|
||||
ANIMATED = "ANIMATED",
|
||||
INSTANT = "INSTANT",
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Nullish } from "../../internal";
|
||||
import type { RecordBase } from "../Record";
|
||||
import type { UserRecord } from "../UserRecord";
|
||||
|
||||
export type InteractionRecordOwnProperties = Pick<InteractionRecord, "displayName" | "id" | "name" | "type" | "user">;
|
||||
|
||||
export type InteractionProperties = Omit<InteractionRecordOwnProperties, "displayName">
|
||||
& { name_localized?: string | Nullish; };
|
||||
|
||||
export declare class InteractionRecord<
|
||||
OwnProperties extends InteractionRecordOwnProperties = InteractionRecordOwnProperties
|
||||
> extends RecordBase<OwnProperties> {
|
||||
constructor(interaction: InteractionProperties);
|
||||
|
||||
static createFromServer(
|
||||
interactionFromServer: Omit<InteractionProperties, "user"> & {
|
||||
/** @todo This is not a UserRecord; it is a user object from the API. */
|
||||
user: Record<string, any>;
|
||||
}
|
||||
): InteractionRecord;
|
||||
|
||||
displayName: string;
|
||||
id: string;
|
||||
name: string;
|
||||
type: InteractionType;
|
||||
user: UserRecord;
|
||||
}
|
||||
|
||||
// Original name: InteractionTypes
|
||||
export enum InteractionType {
|
||||
PING = 1, // From the API documentation
|
||||
APPLICATION_COMMAND = 2,
|
||||
MESSAGE_COMPONENT = 3,
|
||||
APPLICATION_COMMAND_AUTOCOMPLETE = 4,
|
||||
MODAL_SUBMIT = 5,
|
||||
}
|
35
packages/discord-types/src/general/messages/MessageCache.ts
Normal file
35
packages/discord-types/src/general/messages/MessageCache.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { MessageRecord } from "./MessageRecord";
|
||||
|
||||
export declare class MessageCache {
|
||||
constructor(isCacheBefore: boolean);
|
||||
|
||||
cache(messages: readonly MessageRecord[], wasAtEdge?: boolean /* = false */): void;
|
||||
clear(): void;
|
||||
clone(): MessageCache;
|
||||
extract(count: number): MessageRecord[];
|
||||
extractAll(): MessageRecord[];
|
||||
forEach(
|
||||
callback: (value: MessageRecord, index: number, array: MessageRecord[]) => void,
|
||||
thisArg?: unknown
|
||||
): void;
|
||||
get(messageId: string): MessageRecord | undefined;
|
||||
has(messageId: string): boolean;
|
||||
get length(): number;
|
||||
remove(messageId: string): void;
|
||||
removeMany(messageIds: readonly string[]): void;
|
||||
replace(messageId: string, message: MessageRecord): void;
|
||||
update(messageId: string, updater: (message: MessageRecord) => MessageRecord): void;
|
||||
get wasAtEdge(): boolean;
|
||||
set wasAtEdge(wasAtEdge: boolean);
|
||||
|
||||
_isCacheBefore: boolean;
|
||||
_map: { [messageId: string]: MessageRecord; };
|
||||
_messages: MessageRecord[];
|
||||
_wasAtEdge: boolean;
|
||||
}
|
291
packages/discord-types/src/general/messages/MessageRecord.ts
Normal file
291
packages/discord-types/src/general/messages/MessageRecord.ts
Normal file
|
@ -0,0 +1,291 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Duration, Moment } from "moment";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
import type { Nullish, Optional, PartialOnUndefined, SnakeCasedProperties } from "../../internal";
|
||||
import type { ApplicationCommand, ApplicationCommandType } from "../ApplicationCommand";
|
||||
import type { ApplicationIntegrationType } from "../ApplicationRecord";
|
||||
import type { ChannelRecord, ChannelType } from "../channels/ChannelRecord";
|
||||
import type { UserRecord } from "../UserRecord";
|
||||
import type { InteractionRecord, InteractionType } from "./InteractionRecord";
|
||||
import type { MessageSnapshotRecord } from "./MessageSnapshotRecord";
|
||||
import type { MinimalMessageRecord, MinimalMessageRecordOwnProperties } from "./MinimalMessageRecord";
|
||||
|
||||
export type MessageRecordOwnProperties = MinimalMessageRecordOwnProperties & Pick<MessageRecord, "activity" | "activityInstance" | "application" | "applicationId" | "author" | "blocked" | "bot" | "call" | "changelogId" | "channel_id" | "colorString" | "customRenderedContent" | "giftCodes" | "giftInfo" | "id" | "interaction" | "interactionData" | "interactionError" | "interactionMetadata" | "isSearchHit" | "isUnsupported" | "loggingName" | "mentionChannels" | "mentioned" | "mentionEveryone" | "mentionRoles" | "mentions" | "messageReference" | "messageSnapshots" | "nick" | "nonce" | "pinned" | "poll" | "purchaseNotification" | "reactions" | "referralTrialOfferId" | "roleSubscriptionData" | "state" | "tts" | "webhookId">;
|
||||
|
||||
export type MessageProperties = Optional<PartialOnUndefined<MessageRecordOwnProperties>, Nullish, "author" | "channel_id" | "id" | "colorString" | "giftInfo" | "nick" | "roleSubscriptionData" | "purchaseNotification" | "poll", true>
|
||||
& SnakeCasedProperties<Optional<Pick<MessageRecordOwnProperties, "applicationId" | "activityInstance" | "giftInfo" | "changelogId">, Nullish>>
|
||||
& { hit?: boolean | Nullish; };
|
||||
|
||||
export declare class MessageRecord<
|
||||
OwnProperties extends MessageRecordOwnProperties = MessageRecordOwnProperties
|
||||
> extends MinimalMessageRecord<OwnProperties> {
|
||||
constructor(messageProperties: MessageProperties);
|
||||
|
||||
addReaction(
|
||||
emoji: MessageReactionEmoji,
|
||||
me?: boolean /* = false */,
|
||||
deafultBurstColors?: string[] /* = [] */,
|
||||
type?: ReactionType /* = ReactionType.NORMAL */
|
||||
): this;
|
||||
addReactionBatch(
|
||||
reactions: readonly {
|
||||
emoji: MessageReactionEmoji;
|
||||
users: readonly string[];
|
||||
}[],
|
||||
meId: string
|
||||
): this;
|
||||
canDeleteOwnMessage(userId: string): boolean;
|
||||
getChannelId(): string;
|
||||
getContentMessage(): MinimalMessageRecord | this | undefined;
|
||||
getReaction(emoji: MessageReactionEmoji): MessageReaction | undefined;
|
||||
isCommandType(): boolean;
|
||||
isEdited(): boolean;
|
||||
isFirstMessageInForumPost(channel: ChannelRecord): boolean;
|
||||
isInteractionPlaceholder(): boolean;
|
||||
isPoll(): boolean;
|
||||
isSystemDM(): boolean;
|
||||
isUIKitComponents(): boolean;
|
||||
removeReaction(
|
||||
emoji: MessageReactionEmoji,
|
||||
me?: boolean /* = false */,
|
||||
type?: ReactionType /* = ReactionType.NORMAL */
|
||||
): this;
|
||||
removeReactionsForEmoji(emoji: MessageReactionEmoji): this;
|
||||
toJS(): OwnProperties & SnakeCasedProperties<Pick<OwnProperties, "editedTimestamp" | "mentionEveryone" | "webhookId">>;
|
||||
userHasReactedWithEmoji(emoji: MessageReactionEmoji, burst?: boolean /* = false */): boolean;
|
||||
|
||||
activity: MessageActivity | null;
|
||||
activityInstance: { id: string; } | null;
|
||||
/** @todo This is not an ApplicationRecord; it is an application object from the API. */
|
||||
application: Record<string, any> | null;
|
||||
applicationId: string | null;
|
||||
author: UserRecord;
|
||||
blocked: boolean;
|
||||
bot: boolean;
|
||||
call: MessageCall | null;
|
||||
changelogId: string | null;
|
||||
channel_id: string;
|
||||
colorString: string | undefined;
|
||||
customRenderedContent: MessageCustomRenderedContent | Nullish;
|
||||
giftCodes: string[];
|
||||
giftInfo: MessageGiftInfo | undefined;
|
||||
id: string;
|
||||
interaction: InteractionRecord | null;
|
||||
interactionData: MessageInteractionData | null;
|
||||
interactionError: string | null;
|
||||
interactionMetadata: MessageInteractionMetadata | null;
|
||||
isSearchHit: boolean;
|
||||
isUnsupported: boolean;
|
||||
loggingName: string | null;
|
||||
mentionChannels: ChannelMention[];
|
||||
mentioned: boolean;
|
||||
mentionEveryone: boolean;
|
||||
mentionRoles: string[];
|
||||
mentions: string[];
|
||||
/** Only non-null for MessageRecords with type MessageType.REPLY or MessageType.THREAD_STARTER_MESSAGE. */
|
||||
messageReference: MessageReference | null;
|
||||
messageSnapshots: MessageSnapshotRecord[];
|
||||
nick: string | undefined;
|
||||
nonce: string | number | null;
|
||||
pinned: boolean;
|
||||
poll: MessagePoll | undefined;
|
||||
purchaseNotification: MessagePurchaseNotification | undefined;
|
||||
reactions: MessageReaction[];
|
||||
referralTrialOfferId: string | null;
|
||||
roleSubscriptionData: MessageRoleSubscriptionData | undefined;
|
||||
state: MessageState;
|
||||
tts: boolean;
|
||||
webhookId: string | null;
|
||||
}
|
||||
|
||||
export interface MessageActivity {
|
||||
party_id?: string;
|
||||
type: ActivityActionType;
|
||||
}
|
||||
|
||||
// Original name: ActivityActionTypes
|
||||
export enum ActivityActionType {
|
||||
JOIN = 1,
|
||||
SPECTATE = 2,
|
||||
LISTEN = 3,
|
||||
WATCH = 4,
|
||||
JOIN_REQUEST = 5,
|
||||
}
|
||||
|
||||
export interface MessageCall {
|
||||
duration: Duration | null;
|
||||
endedTimestamp: Moment | null;
|
||||
participants: string[];
|
||||
}
|
||||
|
||||
export interface MessageCustomRenderedContent {
|
||||
content: ReactNode;
|
||||
hasSpoilerEmbeds: boolean;
|
||||
}
|
||||
|
||||
/** @todo Some properties may either not be nullable or not be optional. */
|
||||
export interface MessageGiftInfo {
|
||||
emoji?: MessageReactionEmoji | null;
|
||||
/** @todo May have more properties. */
|
||||
sound?: { id: string; } | null;
|
||||
}
|
||||
|
||||
export interface MessageInteractionData extends Pick<ApplicationCommand<ApplicationCommandType.CHAT>, "id" | "name" | "options" | "type"> {
|
||||
/** @todo May not be nullable or optional. */
|
||||
application_command?: ApplicationCommand<ApplicationCommandType.CHAT> | null;
|
||||
}
|
||||
|
||||
export interface MessageInteractionMetadata {
|
||||
authorizing_integration_owners: Partial<Record<ApplicationIntegrationType, string>>;
|
||||
id: string;
|
||||
interacted_message_id?: string;
|
||||
original_response_message_id?: string;
|
||||
triggering_interaction_metadata?: MessageInteractionMetadata;
|
||||
type: InteractionType;
|
||||
/** @todo This is not a UserRecord; it is a user object from the API. */
|
||||
user: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface ChannelMention {
|
||||
guild_id: string;
|
||||
id: string;
|
||||
name: string;
|
||||
type: ChannelType;
|
||||
}
|
||||
|
||||
export interface MessageReference {
|
||||
channel_id: string;
|
||||
guild_id?: string;
|
||||
message_id?: string;
|
||||
type: MessageReferenceType;
|
||||
}
|
||||
|
||||
// Original name: MessageReferenceTypes
|
||||
export enum MessageReferenceType {
|
||||
DEFAULT = 0,
|
||||
FORWARD = 1,
|
||||
}
|
||||
|
||||
export interface MessagePoll {
|
||||
allow_multiselect: boolean;
|
||||
answers: MessagePollAnswer[];
|
||||
expiry: Moment;
|
||||
layout_type: PollLayoutType;
|
||||
question: MessagePollMedia;
|
||||
results?: MessagePollResults;
|
||||
}
|
||||
|
||||
export interface MessagePollAnswer {
|
||||
answer_id: number;
|
||||
poll_media: MessagePollMedia;
|
||||
}
|
||||
|
||||
// Original name: PollLayoutTypes
|
||||
export enum PollLayoutType {
|
||||
UNKNOWN = 0,
|
||||
DEFAULT = 1,
|
||||
IMAGE_ONLY_ANSWERS = 2,
|
||||
}
|
||||
|
||||
export interface MessagePollMedia {
|
||||
emoji?: MessageReactionEmoji;
|
||||
text?: string;
|
||||
}
|
||||
|
||||
export interface MessagePollResults {
|
||||
answer_counts: MessagePollAnswerCount[];
|
||||
is_finalized: boolean;
|
||||
}
|
||||
|
||||
export interface MessagePollAnswerCount {
|
||||
count: number;
|
||||
id: number;
|
||||
me_voted: boolean;
|
||||
}
|
||||
|
||||
/** @todo May have more properties. Some properties may either not be nullable or not be optional. */
|
||||
export interface MessagePurchaseNotification {
|
||||
guild_product_purchase?: {
|
||||
listing_id?: string | null;
|
||||
product_name?: string | null;
|
||||
} | null;
|
||||
type: PurchaseNotificationType;
|
||||
}
|
||||
|
||||
export enum PurchaseNotificationType {
|
||||
GUILD_PRODUCT = 0,
|
||||
}
|
||||
|
||||
export type MessageReaction = MessageNonVoteReaction | MessageVoteReaction;
|
||||
|
||||
export interface MessageReactionBase {
|
||||
burst_count: number;
|
||||
count: number;
|
||||
count_details: MessageReactionCountDetails;
|
||||
emoji: MessageReactionEmoji;
|
||||
me: boolean;
|
||||
me_burst: boolean;
|
||||
}
|
||||
|
||||
export interface MessageNonVoteReaction extends MessageReactionBase {
|
||||
burst_colors: string[];
|
||||
burst_me?: boolean;
|
||||
count_details: MessageNonVoteReactionCountDetails;
|
||||
}
|
||||
|
||||
export interface MessageVoteReaction extends MessageReactionBase {
|
||||
count_details: MessageVoteReactionCountDetails;
|
||||
me_vote: boolean;
|
||||
}
|
||||
|
||||
export type MessageReactionEmoji = MessageReactionUnicodeEmoji | MessageReactionGuildEmoji;
|
||||
|
||||
export interface MessageReactionUnicodeEmoji {
|
||||
animated?: false;
|
||||
id?: null;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface MessageReactionGuildEmoji {
|
||||
animated?: boolean;
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export type MessageReactionCountDetails = MessageNonVoteReactionCountDetails | MessageVoteReactionCountDetails;
|
||||
|
||||
export interface MessageNonVoteReactionCountDetails {
|
||||
burst: number;
|
||||
normal: number;
|
||||
}
|
||||
|
||||
export interface MessageVoteReactionCountDetails {
|
||||
vote: number;
|
||||
}
|
||||
|
||||
// Original name: ReactionTypes
|
||||
export enum ReactionType {
|
||||
NORMAL = 0,
|
||||
BURST = 1,
|
||||
VOTE = 2,
|
||||
}
|
||||
|
||||
export interface MessageRoleSubscriptionData {
|
||||
is_renewal: boolean;
|
||||
role_subscription_listing_id: string;
|
||||
tier_name: string;
|
||||
total_months_subscribed: number;
|
||||
}
|
||||
|
||||
// Original name: MessageStates
|
||||
export enum MessageState {
|
||||
SEND_FAILED = "SEND_FAILED",
|
||||
SENDING = "SENDING",
|
||||
SENT = "SENT",
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { RecordBase } from "../Record";
|
||||
import type { MinimalMessageProperties, MinimalMessageRecord } from "./MinimalMessageRecord";
|
||||
|
||||
export type MessageSnapshotRecordOwnProperties = Pick<MessageSnapshotRecord, "message">;
|
||||
|
||||
export interface MessageSnapshotProperties {
|
||||
message: MinimalMessageProperties;
|
||||
}
|
||||
|
||||
export declare class MessageSnapshotRecord<
|
||||
OwnProperties extends MessageSnapshotRecordOwnProperties = MessageSnapshotRecordOwnProperties
|
||||
> extends RecordBase<OwnProperties> {
|
||||
constructor(messageSnapshotProperties: MessageSnapshotProperties);
|
||||
|
||||
message: MinimalMessageRecord;
|
||||
}
|
|
@ -0,0 +1,542 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Moment } from "moment";
|
||||
|
||||
import type { Nullish, Optional, SnakeCasedProperties } from "../../internal";
|
||||
import type { ChannelType } from "../channels/ChannelRecord";
|
||||
import type { RecordBase } from "../Record";
|
||||
|
||||
export type MinimalMessageRecordOwnProperties = Pick<MinimalMessageRecord, "attachments" | "codedLinks" | "components" | "content" | "editedTimestamp" | "embeds" | "flags" | "stickerItems" | "stickers" | "timestamp" | "type">;
|
||||
|
||||
export type MinimalMessageProperties = Optional<MinimalMessageRecordOwnProperties, Nullish>
|
||||
& SnakeCasedProperties<Optional<Pick<MinimalMessageRecordOwnProperties, "stickerItems">, Nullish>>;
|
||||
|
||||
export declare class MinimalMessageRecord<
|
||||
OwnProperties extends MinimalMessageRecordOwnProperties = MinimalMessageRecordOwnProperties
|
||||
> extends RecordBase<OwnProperties> {
|
||||
constructor(minimalMessageProperties: MinimalMessageProperties);
|
||||
|
||||
hasFlag(flag: MessageFlags): boolean;
|
||||
|
||||
attachments: MessageAttachment[];
|
||||
codedLinks: CodedLink[];
|
||||
components: MessageComponent[];
|
||||
content: string;
|
||||
editedTimestamp: Date | null;
|
||||
embeds: MessageEmbed[];
|
||||
flags: MessageFlags;
|
||||
stickerItems: StickerItem[];
|
||||
stickers: Sticker[];
|
||||
timestamp: Date;
|
||||
type: MessageType;
|
||||
}
|
||||
|
||||
export interface MessageAttachment {
|
||||
content_scan_version?: number;
|
||||
content_type?: string;
|
||||
description?: string;
|
||||
duration_secs?: number;
|
||||
ephemeral?: boolean;
|
||||
filename: string;
|
||||
flags?: MessageAttachmentFlags;
|
||||
height?: number | null;
|
||||
id: string;
|
||||
placeholder?: string;
|
||||
placeholder_version?: number;
|
||||
proxy_url: string;
|
||||
size: number;
|
||||
spoiler: boolean;
|
||||
url: string;
|
||||
waveform?: string;
|
||||
width?: number | null;
|
||||
}
|
||||
|
||||
export enum MessageAttachmentFlags {
|
||||
IS_CLIP = 1 << 0,
|
||||
IS_THUMBNAIL = 1 << 1,
|
||||
IS_REMIX = 1 << 2,
|
||||
IS_SPOILER = 1 << 3,
|
||||
CONTAINS_EXPLICIT_MEDIA = 1 << 4,
|
||||
}
|
||||
|
||||
export interface CodedLink {
|
||||
code: string;
|
||||
type: CodedLinkType;
|
||||
}
|
||||
|
||||
export enum CodedLinkType {
|
||||
ACTIVITY_BOOKMARK = "ACTIVITY_BOOKMARK",
|
||||
APP_DIRECTORY_PROFILE = "APP_DIRECTORY_PROFILE",
|
||||
APP_DIRECTORY_STOREFRONT = "APP_DIRECTORY_STOREFRONT",
|
||||
APP_DIRECTORY_STOREFRONT_SKU = "APP_DIRECTORY_STOREFRONT_SKU",
|
||||
BUILD_OVERRIDE = "BUILD_OVERRIDE",
|
||||
CHANNEL_LINK = "CHANNEL_LINK",
|
||||
EMBEDDED_ACTIVITY_INVITE = "EMBEDDED_ACTIVITY_INVITE",
|
||||
EVENT = "EVENT",
|
||||
GUILD_PRODUCT = "GUILD_PRODUCT",
|
||||
INVITE = "INVITE",
|
||||
MANUAL_BUILD_OVERRIDE = "MANUAL_BUILD_OVERRIDE",
|
||||
QUESTS_EMBED = "QUESTS_EMBED",
|
||||
SERVER_SHOP = "SERVER_SHOP",
|
||||
TEMPLATE = "TEMPLATE",
|
||||
}
|
||||
|
||||
export type MessageComponent = MessageActionRowComponent | MessageButtonComponent | MessageSelectComponent | MessageTextInputComponent | MessageTextComponent | MessageMediaGalleryComponent | MessageSeparatorComponent | MessageContentInventoryEntryComponent;
|
||||
|
||||
export interface MessageComponentBase {
|
||||
id: string;
|
||||
type: MessageComponentType;
|
||||
}
|
||||
|
||||
export interface MessageActionRowComponent extends MessageComponentBase {
|
||||
components: Exclude<MessageComponent, MessageActionRowComponent>[];
|
||||
type: MessageComponentType.ACTION_ROW;
|
||||
}
|
||||
|
||||
export type MessageButtonComponent = MessageNonLinkButtonComponent | MessageLinkButtonComponent;
|
||||
|
||||
export interface MessageButtonComponentBase extends MessageComponentBase {
|
||||
customId: string | undefined;
|
||||
disabled: boolean | undefined;
|
||||
emoji: MessageComponentEmoji | undefined;
|
||||
label: string | undefined;
|
||||
style: MessageButtonComponentStyle;
|
||||
type: MessageComponentType.BUTTON;
|
||||
url: string | undefined;
|
||||
}
|
||||
|
||||
export interface MessageNonLinkButtonComponent extends MessageButtonComponentBase {
|
||||
customId: string;
|
||||
style: Exclude<MessageButtonComponentStyle, MessageButtonComponentStyle.LINK>;
|
||||
url: undefined;
|
||||
}
|
||||
|
||||
export interface MessageLinkButtonComponent extends MessageButtonComponentBase {
|
||||
customId: undefined;
|
||||
style: MessageButtonComponentStyle.LINK;
|
||||
url: string;
|
||||
}
|
||||
|
||||
// Original name: ButtonStyle
|
||||
export enum MessageButtonComponentStyle {
|
||||
PRIMARY = 1,
|
||||
SECONDARY = 2,
|
||||
SUCCESS = 3,
|
||||
DESTRUCTIVE = 4,
|
||||
LINK = 5,
|
||||
PREMIUM = 6,
|
||||
}
|
||||
|
||||
export type MessageSelectComponent = MessageStringSelectComponent | MessageSnowflakeSelectComponent;
|
||||
|
||||
export interface MessageSelectComponentBase extends MessageComponentBase {
|
||||
customId: string;
|
||||
disabled: boolean | undefined;
|
||||
maxValues: number | undefined;
|
||||
minValues: number | undefined;
|
||||
placeholder: string;
|
||||
type: MessageComponentType.STRING_SELECT | MessageComponentType.USER_SELECT | MessageComponentType.ROLE_SELECT | MessageComponentType.MENTIONABLE_SELECT | MessageComponentType.CHANNEL_SELECT;
|
||||
}
|
||||
|
||||
export interface MessageStringSelectComponent extends MessageSelectComponentBase {
|
||||
options: MessageSelectComponentMenuOption<MessageSelectComponentOptionType.STRING>[];
|
||||
type: MessageComponentType.STRING_SELECT;
|
||||
}
|
||||
|
||||
export interface MessageSelectComponentMenuOption<
|
||||
OptionType extends MessageSelectComponentOptionType = MessageSelectComponentOptionType
|
||||
> {
|
||||
default: boolean | undefined;
|
||||
description: string | undefined;
|
||||
emoji: MessageComponentEmoji | undefined;
|
||||
label: string;
|
||||
type: OptionType;
|
||||
value: string;
|
||||
}
|
||||
|
||||
// Original name: SelectOptionType
|
||||
export enum MessageSelectComponentOptionType {
|
||||
STRING = 1,
|
||||
USER = 2,
|
||||
ROLE = 3,
|
||||
CHANNEL = 4,
|
||||
GUILD = 5,
|
||||
}
|
||||
|
||||
export type MessageSnowflakeSelectComponent = MessageUserSelectComponent | MessageRoleSelectComponent | MessageMentionableSelectComponent | MessageChannelSelectComponent;
|
||||
|
||||
export interface MessageSnowflakeSelectComponentBase extends MessageSelectComponentBase {
|
||||
defaultValues: MessageSelectComponentDefaultValue[];
|
||||
type: MessageComponentType.USER_SELECT | MessageComponentType.ROLE_SELECT | MessageComponentType.MENTIONABLE_SELECT | MessageComponentType.CHANNEL_SELECT;
|
||||
}
|
||||
|
||||
export interface MessageUserSelectComponent extends MessageSnowflakeSelectComponentBase {
|
||||
defaultValues: MessageSelectComponentDefaultValue<MessageSelectComponentDefaultValueType.USER>[];
|
||||
type: MessageComponentType.USER_SELECT;
|
||||
}
|
||||
|
||||
export interface MessageRoleSelectComponent extends MessageSnowflakeSelectComponentBase {
|
||||
defaultValues: MessageSelectComponentDefaultValue<MessageSelectComponentDefaultValueType.ROLE>[];
|
||||
type: MessageComponentType.ROLE_SELECT;
|
||||
}
|
||||
|
||||
export interface MessageMentionableSelectComponent extends MessageSnowflakeSelectComponentBase {
|
||||
defaultValues: MessageSelectComponentDefaultValue<MessageSelectComponentDefaultValueType.ROLE | MessageSelectComponentDefaultValueType.USER>[];
|
||||
type: MessageComponentType.MENTIONABLE_SELECT;
|
||||
}
|
||||
|
||||
export interface MessageChannelSelectComponent extends MessageSnowflakeSelectComponentBase {
|
||||
channelTypes: ChannelType[] | undefined;
|
||||
defaultValues: MessageSelectComponentDefaultValue<MessageSelectComponentDefaultValueType.CHANNEL>[];
|
||||
type: MessageComponentType.CHANNEL_SELECT;
|
||||
}
|
||||
|
||||
export interface MessageSelectComponentDefaultValue<
|
||||
DefaultValueType extends MessageSelectComponentDefaultValueType = MessageSelectComponentDefaultValueType
|
||||
> {
|
||||
id: string;
|
||||
type: DefaultValueType;
|
||||
}
|
||||
|
||||
// Original name: SnowflakeSelectDefaultValueTypes
|
||||
export enum MessageSelectComponentDefaultValueType {
|
||||
CHANNEL = "channel",
|
||||
ROLE = "role",
|
||||
USER = "user",
|
||||
}
|
||||
|
||||
export interface MessageTextInputComponent extends MessageComponentBase {
|
||||
customId: string;
|
||||
disabled: boolean | undefined;
|
||||
label: string;
|
||||
maxLength: number | undefined;
|
||||
minLength: number | undefined;
|
||||
placeholder: string | undefined;
|
||||
required: boolean;
|
||||
style: MessageTextInputComponentStyle;
|
||||
type: MessageComponentType.INPUT_TEXT;
|
||||
value: string | undefined;
|
||||
}
|
||||
|
||||
// Original name: TextComponentStyle
|
||||
export enum MessageTextInputComponentStyle {
|
||||
SMALL = 1,
|
||||
PARAGRAPH = 2,
|
||||
}
|
||||
|
||||
export interface MessageTextComponent extends MessageComponentBase {
|
||||
/** @todo May not be undefined. */
|
||||
content: string | undefined;
|
||||
type: MessageComponentType.TEXT;
|
||||
}
|
||||
|
||||
export interface MessageMediaGalleryComponent extends MessageComponentBase {
|
||||
items: {
|
||||
/** @todo May not be undefined. */
|
||||
description: string | undefined;
|
||||
media: MessageMediaGalleryComponentItem;
|
||||
/** @todo May not be undefined. */
|
||||
spoiler: boolean | undefined;
|
||||
}[];
|
||||
type: MessageComponentType.MEDIA_GALLERY;
|
||||
}
|
||||
export interface MessageMediaGalleryComponentItem {
|
||||
contentScanMetadata: {
|
||||
contentScanFlags: ContentScanFlags;
|
||||
/** @todo May not be undefined. */
|
||||
version: number | undefined;
|
||||
} | undefined;
|
||||
contentType: string;
|
||||
height: number;
|
||||
placeholder: string | undefined;
|
||||
/** @todo May not be undefined. */
|
||||
placeholderVersion: number | undefined;
|
||||
proxyUrl: string;
|
||||
url: string;
|
||||
width: number;
|
||||
}
|
||||
|
||||
export enum ContentScanFlags {
|
||||
EXPLICIT = 1,
|
||||
}
|
||||
|
||||
export interface MessageSeparatorComponent extends MessageComponentBase {
|
||||
divider: boolean;
|
||||
spacing: SeparatorSpacingSize;
|
||||
type: MessageComponentType.SEPARATOR;
|
||||
}
|
||||
|
||||
export enum SeparatorSpacingSize {
|
||||
SMALL = 1,
|
||||
LARGE = 2,
|
||||
}
|
||||
|
||||
export interface MessageContentInventoryEntryComponent extends MessageComponentBase {
|
||||
/** @todo */
|
||||
contentInventoryEntry: Record<string, any>;
|
||||
type: MessageComponentType.CONTENT_INVENTORY_ENTRY;
|
||||
}
|
||||
|
||||
export type MessageComponentEmoji = MessageComponentUnicodeEmoji | MessageComponentGuildEmoji;
|
||||
|
||||
export interface MessageComponentUnicodeEmoji {
|
||||
animated: false | undefined;
|
||||
id: undefined;
|
||||
name: string;
|
||||
src: undefined;
|
||||
}
|
||||
|
||||
export interface MessageComponentGuildEmoji {
|
||||
animated: boolean | undefined;
|
||||
id: string;
|
||||
name: string;
|
||||
src: string | undefined;
|
||||
}
|
||||
|
||||
// Original name: ComponentType
|
||||
// Renamed to avoid name conflicts with ComponentType from React.
|
||||
export enum MessageComponentType {
|
||||
ACTION_ROW = 1,
|
||||
BUTTON = 2,
|
||||
STRING_SELECT = 3,
|
||||
INPUT_TEXT = 4,
|
||||
USER_SELECT = 5,
|
||||
ROLE_SELECT = 6,
|
||||
MENTIONABLE_SELECT = 7,
|
||||
CHANNEL_SELECT = 8,
|
||||
TEXT = 10,
|
||||
MEDIA_GALLERY = 12,
|
||||
SEPARATOR = 14,
|
||||
CONTENT_INVENTORY_ENTRY = 16,
|
||||
}
|
||||
|
||||
export type MessageEmbed = {
|
||||
author?: MessageEmbedAuthor;
|
||||
color?: string;
|
||||
/** @todo May not be undefined. */
|
||||
contentScanVersion: number | undefined;
|
||||
fields: MessageEmbedField[];
|
||||
flags: MessageEmbedFlags | undefined;
|
||||
footer?: MessageEmbedFooter;
|
||||
id: string;
|
||||
image?: MessageEmbedImage;
|
||||
provider?: MessageEmbedProvider;
|
||||
rawDescription: string | undefined;
|
||||
rawTitle: string | undefined;
|
||||
referenceId: string | undefined;
|
||||
thumbnail?: MessageEmbedThumbnail;
|
||||
timestamp?: Moment;
|
||||
type: MessageEmbedType | undefined;
|
||||
url: string | undefined;
|
||||
} & ({} | {
|
||||
provider: MessageEmbedProvider;
|
||||
thumbnail: MessageEmbedThumbnail;
|
||||
video: MessageEmbedVideo;
|
||||
});
|
||||
|
||||
export interface MessageEmbedAuthor {
|
||||
iconProxyURL: string | undefined;
|
||||
iconURL: string | undefined;
|
||||
name: string;
|
||||
url: string | undefined;
|
||||
}
|
||||
|
||||
export interface MessageEmbedField {
|
||||
inline: boolean | undefined;
|
||||
rawName: string;
|
||||
rawValue: string;
|
||||
}
|
||||
|
||||
export enum MessageEmbedFlags {
|
||||
CONTAINS_EXPLICIT_MEDIA = 1 << 4,
|
||||
IS_CONTENT_INVENTORY_ENTRY = 1 << 5,
|
||||
}
|
||||
|
||||
export interface MessageEmbedFooter {
|
||||
iconProxyURL: string | undefined;
|
||||
iconURL: string | undefined;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface MessageEmbedImage {
|
||||
/** Always greater than 0. */
|
||||
height: number;
|
||||
placeholder: string | undefined;
|
||||
placeholderVersion: number | undefined;
|
||||
proxyURL: string | undefined;
|
||||
url: string;
|
||||
/** Always greater than 0. */
|
||||
width: number;
|
||||
}
|
||||
|
||||
export interface MessageEmbedProvider {
|
||||
name: string;
|
||||
url: string | undefined;
|
||||
}
|
||||
|
||||
export type MessageEmbedThumbnail = {
|
||||
/** Always greater than 0. */
|
||||
height: number;
|
||||
url: string;
|
||||
/** Always greater than 0. */
|
||||
width: number;
|
||||
} & ({} | {
|
||||
placeholder: string | undefined;
|
||||
placeholderVersion: number | undefined;
|
||||
proxyURL: string | undefined;
|
||||
});
|
||||
|
||||
// Original name: MessageEmbedTypes
|
||||
export enum MessageEmbedType {
|
||||
APPLICATION_NEWS = "application_news",
|
||||
ARTICLE = "article",
|
||||
AUTO_MODERATION_MESSAGE = "auto_moderation_message",
|
||||
AUTO_MODERATION_NOTIFICATION = "auto_moderation_notification",
|
||||
GAMING_PROFILE = "gaming_profile",
|
||||
GIFT = "gift",
|
||||
GIFV = "gifv",
|
||||
IMAGE = "image",
|
||||
LINK = "link",
|
||||
POLL_RESULT = "poll_result",
|
||||
POST_PREVIEW = "post_preview",
|
||||
RICH = "rich",
|
||||
SAFETY_POLICY_NOTICE = "safety_policy_notice",
|
||||
SAFETY_SYSTEM_NOTIFICATION = "safety_system_notification",
|
||||
TEXT = "text",
|
||||
TWEET = "tweet",
|
||||
VIDEO = "video",
|
||||
VOICE_CHANNEL = "voice_channel",
|
||||
}
|
||||
|
||||
export type MessageEmbedVideo = {
|
||||
/** Always greater than 0. */
|
||||
height: number;
|
||||
placeholder: string | undefined;
|
||||
placeholderVersion: number | undefined;
|
||||
/** Always greater than 0. */
|
||||
width: number;
|
||||
} & ({
|
||||
proxyURL: string;
|
||||
url: string | undefined;
|
||||
} | {
|
||||
proxyURL: string | undefined;
|
||||
url: string;
|
||||
});
|
||||
|
||||
export enum MessageFlags {
|
||||
CROSSPOSTED = 1 << 0,
|
||||
IS_CROSSPOST = 1 << 1,
|
||||
SUPPRESS_EMBEDS = 1 << 2,
|
||||
SOURCE_MESSAGE_DELETED = 1 << 3,
|
||||
URGENT = 1 << 4,
|
||||
HAS_THREAD = 1 << 5,
|
||||
EPHEMERAL = 1 << 6,
|
||||
LOADING = 1 << 7,
|
||||
FAILED_TO_MENTION_SOME_ROLES_IN_THREAD = 1 << 8,
|
||||
GUILD_FEED_HIDDEN = 1 << 9,
|
||||
SHOULD_SHOW_LINK_NOT_DISCORD_WARNING = 1 << 10,
|
||||
SUPPRESS_NOTIFICATIONS = 1 << 12,
|
||||
IS_VOICE_MESSAGE = 1 << 13,
|
||||
HAS_SNAPSHOT = 1 << 14,
|
||||
IS_UIKIT_COMPONENTS = 1 << 15,
|
||||
}
|
||||
|
||||
export interface StickerItem {
|
||||
format_type: StickerFormat;
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export enum StickerFormat {
|
||||
PNG = 1,
|
||||
APNG = 2,
|
||||
LOTTIE = 3,
|
||||
GIF = 4,
|
||||
}
|
||||
|
||||
export type Sticker = StandardSticker | GuildSticker;
|
||||
|
||||
export interface StickerBase {
|
||||
asset?: "";
|
||||
description: string | null;
|
||||
format_type: StickerFormat;
|
||||
id: string;
|
||||
name: string;
|
||||
tags: string;
|
||||
type: MetaStickerType;
|
||||
}
|
||||
|
||||
export interface StandardSticker extends StickerBase {
|
||||
pack_id: string;
|
||||
sort_value: number;
|
||||
}
|
||||
|
||||
export interface GuildSticker extends StickerBase {
|
||||
/** @todo May actually not be optional. */
|
||||
available?: boolean;
|
||||
guild_id: string;
|
||||
/** @todo This is not a UserRecord; it is a user object from the API. */
|
||||
user: Record<string, any>;
|
||||
}
|
||||
|
||||
export enum MetaStickerType {
|
||||
STANDARD = 1,
|
||||
GUILD = 2,
|
||||
}
|
||||
|
||||
// Original name: MessageTypes
|
||||
export enum MessageType {
|
||||
DEFAULT = 0,
|
||||
RECIPIENT_ADD = 1,
|
||||
RECIPIENT_REMOVE = 2,
|
||||
CALL = 3,
|
||||
CHANNEL_NAME_CHANGE = 4,
|
||||
CHANNEL_ICON_CHANGE = 5,
|
||||
CHANNEL_PINNED_MESSAGE = 6,
|
||||
USER_JOIN = 7,
|
||||
GUILD_BOOST = 8,
|
||||
GUILD_BOOST_TIER_1 = 9,
|
||||
GUILD_BOOST_TIER_2 = 10,
|
||||
GUILD_BOOST_TIER_3 = 11,
|
||||
CHANNEL_FOLLOW_ADD = 12,
|
||||
GUILD_STREAM = 13,
|
||||
GUILD_DISCOVERY_DISQUALIFIED = 14,
|
||||
GUILD_DISCOVERY_REQUALIFIED = 15,
|
||||
GUILD_DISCOVERY_GRACE_PERIOD_INITIAL_WARNING = 16,
|
||||
GUILD_DISCOVERY_GRACE_PERIOD_FINAL_WARNING = 17,
|
||||
THREAD_CREATED = 18,
|
||||
REPLY = 19,
|
||||
CHAT_INPUT_COMMAND = 20,
|
||||
THREAD_STARTER_MESSAGE = 21,
|
||||
GUILD_INVITE_REMINDER = 22,
|
||||
CONTEXT_MENU_COMMAND = 23,
|
||||
AUTO_MODERATION_ACTION = 24,
|
||||
ROLE_SUBSCRIPTION_PURCHASE = 25,
|
||||
INTERACTION_PREMIUM_UPSELL = 26,
|
||||
STAGE_START = 27,
|
||||
STAGE_END = 28,
|
||||
STAGE_SPEAKER = 29,
|
||||
STAGE_RAISE_HAND = 30,
|
||||
STAGE_TOPIC = 31,
|
||||
GUILD_APPLICATION_PREMIUM_SUBSCRIPTION = 32,
|
||||
PRIVATE_CHANNEL_INTEGRATION_ADDED = 33,
|
||||
PRIVATE_CHANNEL_INTEGRATION_REMOVED = 34,
|
||||
PREMIUM_REFERRAL = 35,
|
||||
GUILD_INCIDENT_ALERT_MODE_ENABLED = 36,
|
||||
GUILD_INCIDENT_ALERT_MODE_DISABLED = 37,
|
||||
GUILD_INCIDENT_REPORT_RAID = 38,
|
||||
GUILD_INCIDENT_REPORT_FALSE_ALARM = 39,
|
||||
GUILD_DEADCHAT_REVIVE_PROMPT = 40,
|
||||
CUSTOM_GIFT = 41,
|
||||
GUILD_GAMING_STATS_PROMPT = 42,
|
||||
PURCHASE_NOTIFICATION = 44,
|
||||
VOICE_HANGOUT_INVITE = 45,
|
||||
POLL_RESULT = 46,
|
||||
CHANGELOG = 47,
|
||||
NITRO_NOTIFICATION = 48,
|
||||
CHANNEL_LINKED_TO_LOBBY = 49,
|
||||
}
|
12
packages/discord-types/src/general/messages/index.ts
Normal file
12
packages/discord-types/src/general/messages/index.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export * from "./ChannelMessages";
|
||||
export * from "./InteractionRecord";
|
||||
export * from "./MessageCache";
|
||||
export * from "./MessageRecord";
|
||||
export * from "./MessageSnapshotRecord";
|
||||
export * from "./MinimalMessageRecord";
|
9
packages/discord-types/src/general/misc.ts
Normal file
9
packages/discord-types/src/general/misc.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export interface IconSource {
|
||||
uri: string;
|
||||
}
|
127
packages/discord-types/src/i18n/FormattedMessage.ts
Normal file
127
packages/discord-types/src/i18n/FormattedMessage.ts
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type MessageFormat from "intl-messageformat";
|
||||
import type { ReactElement, ReactNode } from "react";
|
||||
import type { State } from "simple-markdown";
|
||||
|
||||
import type { IsAny, IsDomainFinite, Stringable, StringProperties, UnionToIntersection } from "../internal";
|
||||
|
||||
export type FormattedMessageArgs = RecordArgs | TupleArgs | string | number;
|
||||
|
||||
export declare class FormattedMessage<
|
||||
Args extends FormattedMessageArgs = FormattedMessageArgs,
|
||||
Markdown extends boolean | undefined = boolean | undefined
|
||||
> {
|
||||
/**
|
||||
* @throws {SyntaxError} Argument `message` must be syntactically valid.
|
||||
* @see {@link https://formatjs.io/docs/core-concepts/icu-syntax/}
|
||||
* @throws {RangeError} Locale identifiers provided to argument `locales` must be structurally valid.
|
||||
* @see {@link https://tc39.es/ecma402/#sec-isstructurallyvalidlanguagetag}
|
||||
*/
|
||||
constructor(
|
||||
message: string,
|
||||
locales?: string | readonly string[] /* = MessageFormat.defaultLocale */,
|
||||
...hasMarkdown: undefined extends Markdown
|
||||
? [hasMarkdown?: Markdown]
|
||||
: [hasMarkdown: Markdown]
|
||||
);
|
||||
|
||||
/**
|
||||
* @throws {RangeError | TypeError}
|
||||
* @see {@link format}
|
||||
*/
|
||||
astFormat(...args: FormatArgs<Args>): ASTNode;
|
||||
/**
|
||||
* @throws {RangeError} Values provided to arguments with type date or time must be valid time values.
|
||||
* @throws {TypeError} Values provided to arguments with type plural, select, or selectordinal must match one of their matches.
|
||||
*/
|
||||
format(...args: FormatArgs<Args>): Markdown extends true
|
||||
? (string | ReactElement)[]
|
||||
: string;
|
||||
getContext<Values extends RecordArgs>(values: Values): [
|
||||
{ [Key in keyof Values]: Values[Key] | (Key & keyof MessageValues<Args> extends never ? never : number); },
|
||||
Record<number, Values[keyof Values & keyof MessageValues<Args>]>
|
||||
];
|
||||
/**
|
||||
* @throws {RangeError | TypeError}
|
||||
* @see {@link format}
|
||||
*/
|
||||
plainFormat(...args: FormatArgs<Args>): string;
|
||||
|
||||
hasMarkdown: Markdown;
|
||||
intlMessage: MessageFormat;
|
||||
message: string;
|
||||
}
|
||||
|
||||
type RecordArgs = Record<string | number, GenericValue>;
|
||||
type TupleArgs = readonly [stringableArgs: string | number, hookArgs: string | number];
|
||||
|
||||
type GenericValue = Stringable | HookValue;
|
||||
type HookValue = (result: ReactNode, key: State["key"]) => ReactNode;
|
||||
|
||||
type FormatArgs<Args extends FormattedMessageArgs>
|
||||
= unknown extends IsAny<Args>
|
||||
? [values?: RecordArgs]
|
||||
: [Args] extends [never]
|
||||
? []
|
||||
: keyof MessageValues<Args> extends never
|
||||
? []
|
||||
: unknown extends IsDomainFinite<keyof MessageValues<Args>>
|
||||
? [values: MessageValues<Args>]
|
||||
: [values: never];
|
||||
|
||||
type MessageValues<Args extends FormattedMessageArgs> = UnionToIntersection<
|
||||
Args extends string | number
|
||||
? Record<Args, Stringable>
|
||||
: Args extends TupleArgs
|
||||
? Record<Args[0], Stringable> & Record<Args[1], HookValue>
|
||||
: Required<StringProperties<Args>>
|
||||
>;
|
||||
|
||||
/** @todo Add types for every type of ASTNode. */
|
||||
export interface ASTNode<Type extends ASTNodeType = ASTNodeType> extends Record<string, any> {
|
||||
type: Type;
|
||||
}
|
||||
|
||||
// Original name: AST_KEY
|
||||
/** @todo There may be more undocumented types. */
|
||||
export enum ASTNodeType {
|
||||
ATTACHMENT_LINK = "attachmentLink",
|
||||
AUTOLINK = "autolink",
|
||||
BLOCK_QUOTE = "blockQuote",
|
||||
LINE_BREAK = "br",
|
||||
CHANNEL = "channel",
|
||||
CHANNEL_MENTION = "channelMention",
|
||||
CODE_BLOCK = "codeBlock",
|
||||
COMMAND_MENTION = "commandMention",
|
||||
CUSTOM_EMOJI = "customEmoji",
|
||||
ITALICS = "em",
|
||||
EMOJI = "emoji",
|
||||
ESCAPE = "escape",
|
||||
GUILD = "guild",
|
||||
HEADING = "heading",
|
||||
HIGHLIGHT = "highlight",
|
||||
HOOK = "hook", // Undocumented
|
||||
IMAGE = "image",
|
||||
INLINE_CODE = "inlineCode",
|
||||
LINK = "link",
|
||||
LIST = "list",
|
||||
MENTION = "mention",
|
||||
NEWLINE = "newline",
|
||||
PARAGRAPH = "paragraph",
|
||||
ROLE_MENTION = "roleMention",
|
||||
STRIKETHROUGH = "s",
|
||||
SOUNDBOARD = "soundboard",
|
||||
SPOILER = "spoiler",
|
||||
STATIC_ROUTE_LINK = "staticRouteLink",
|
||||
STRONG = "strong",
|
||||
SUBTEXT = "subtext",
|
||||
TEXT = "text",
|
||||
TIMESTAMP = "timestamp",
|
||||
UNDERLINE = "u",
|
||||
URL = "url",
|
||||
}
|
89
packages/discord-types/src/i18n/I18N.ts
Normal file
89
packages/discord-types/src/i18n/I18N.ts
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { EventEmitter } from "events";
|
||||
|
||||
import type { Nullish } from "../internal";
|
||||
import type { FormattedMessage } from "./FormattedMessage";
|
||||
import type { I18NMessages } from "./I18NMessages";
|
||||
import type { Provider, ProviderParsedMessagesGetter } from "./Provider";
|
||||
import type { UpdateRulesSetter } from "./utils";
|
||||
|
||||
export declare class I18N<
|
||||
Messages extends Record<never, string | FormattedMessage> = I18NMessages,
|
||||
Async extends boolean = boolean
|
||||
> extends EventEmitter {
|
||||
constructor(options: {
|
||||
getLanguages: () => I18NLanguage[];
|
||||
getMessages: I18NMessagesGetter<keyof Messages, Async>;
|
||||
initialLocale?: string | Nullish /* = this.getDefaultLocale() */;
|
||||
});
|
||||
|
||||
/**
|
||||
* @throws {Error} If argument `defaultMessages` is omitted, the messages for the given locale must be loaded.
|
||||
*/
|
||||
_applyMessagesForLocale(
|
||||
messages: Record<keyof Messages, string>,
|
||||
locale: string,
|
||||
defaultMessages?: Record<keyof Messages, string> /* = this._findMessages() */
|
||||
): void;
|
||||
_fetchMessages(locale: string): ReturnType<I18NMessagesGetter<keyof Messages, Async>>;
|
||||
/**
|
||||
* @throws {Error} The messages for the given locale must be loaded.
|
||||
*/
|
||||
_findMessages(locale: string): Record<keyof Messages, string>;
|
||||
_loadMessagesForLocale(locale: string): void;
|
||||
getAvailableLocales(): I18NLocale[];
|
||||
getDefaultLocale(): string;
|
||||
getLanguages(): I18NLanguage[];
|
||||
getLocale(): string;
|
||||
getLocaleInfo(): I18NLanguage;
|
||||
setLocale(locale: string): void;
|
||||
setUpdateRules(...args: Parameters<UpdateRulesSetter>): void;
|
||||
updateMessagesForExperiment(
|
||||
locale: string,
|
||||
updater: (messages: Record<keyof Messages, string>) => Record<keyof Messages, string>
|
||||
): void;
|
||||
|
||||
_chosenLocale: string;
|
||||
_getMessages: I18NMessagesGetter<keyof Messages, Async>;
|
||||
_getParsedMessages: ProviderParsedMessagesGetter;
|
||||
_handleNewListener: (eventType: string | number) => void;
|
||||
_languages: I18NLanguage[];
|
||||
_provider: Provider<Messages>;
|
||||
_requestedLocale: string | undefined;
|
||||
initialLanguageLoad: Promise<void>;
|
||||
loadPromise: Promise<void>;
|
||||
/**
|
||||
* Values will never be undefined.
|
||||
* @see {@link https://github.com/microsoft/TypeScript/issues/47594}
|
||||
*/
|
||||
Messages: I18NMessages & Record<PropertyKey, string>;
|
||||
resolveLanguageLoaded: () => void;
|
||||
}
|
||||
|
||||
export type I18NMessagesGetter<
|
||||
MessagesKeys extends PropertyKey = PropertyKey,
|
||||
Async extends boolean = boolean
|
||||
> = (locale: string) => Async extends true
|
||||
? Promise<Record<MessagesKeys, string>>
|
||||
: Record<MessagesKeys, string>;
|
||||
|
||||
export interface I18NLanguage {
|
||||
code: string;
|
||||
enabled: boolean;
|
||||
enabledAPI?: boolean;
|
||||
englishName: string;
|
||||
name: string;
|
||||
postgresLang: string;
|
||||
}
|
||||
|
||||
export interface I18NLocale {
|
||||
localizedName: string;
|
||||
name: string;
|
||||
/** Locale identifier */
|
||||
value: string;
|
||||
}
|
164
packages/discord-types/src/i18n/I18NMessages.ts
Normal file
164
packages/discord-types/src/i18n/I18NMessages.ts
Normal file
File diff suppressed because one or more lines are too long
42
packages/discord-types/src/i18n/Provider.ts
Normal file
42
packages/discord-types/src/i18n/Provider.ts
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { FormattedMessage } from "./FormattedMessage";
|
||||
|
||||
type GenericMessages<Key extends PropertyKey = PropertyKey> = Record<Key, string | FormattedMessage>;
|
||||
|
||||
// Original name: ProxyProvider
|
||||
export declare class Provider<Messages extends GenericMessages<never> = GenericMessages> {
|
||||
constructor(getParsedMessages: ProviderParsedMessagesGetter<Messages>);
|
||||
|
||||
getMessages(): Messages & Record<PropertyKey, string>;
|
||||
refresh(context: ProviderContext<keyof Messages>): void;
|
||||
|
||||
_context: ProviderContext<keyof Messages>;
|
||||
_createProxy: (
|
||||
context?: ProviderContext<keyof Messages> /* = this._context */
|
||||
) => Messages & Record<PropertyKey, string>;
|
||||
_getParsedMessages: ProviderParsedMessagesGetter<Messages>;
|
||||
/**
|
||||
* Values will never be undefined.
|
||||
* @see {@link https://github.com/microsoft/TypeScript/issues/47594}
|
||||
*/
|
||||
_parsedMessages: Messages & Record<PropertyKey, string>;
|
||||
}
|
||||
|
||||
export interface ProviderContext<MessageKeys extends PropertyKey = PropertyKey> {
|
||||
defaultMessages: Partial<Record<MessageKeys, string>>;
|
||||
locale: string;
|
||||
messages: Partial<Record<MessageKeys, string>>;
|
||||
}
|
||||
|
||||
export type ProviderParsedMessagesGetter<
|
||||
Messages extends GenericMessages<never> = GenericMessages
|
||||
> = <Key extends PropertyKey>(
|
||||
context: ProviderContext<keyof Messages>,
|
||||
key: Key,
|
||||
createProxy: Provider<Messages>["_createProxy"]
|
||||
) => Key extends keyof Messages ? Messages[Key] : string;
|
11
packages/discord-types/src/i18n/index.ts
Normal file
11
packages/discord-types/src/i18n/index.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export * from "./FormattedMessage";
|
||||
export * from "./I18N";
|
||||
export * from "./I18NMessages";
|
||||
export * from "./Provider";
|
||||
export * from "./utils";
|
24
packages/discord-types/src/i18n/utils.ts
Normal file
24
packages/discord-types/src/i18n/utils.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { ParserRules } from "simple-markdown";
|
||||
|
||||
import type { FormattedMessage, FormattedMessageArgs } from "./FormattedMessage";
|
||||
|
||||
// For getSystemLocale
|
||||
export type SystemLocaleGetter = () => string;
|
||||
|
||||
// For setUpdateRules
|
||||
export type UpdateRulesSetter = (updater: (rules: ParserRules) => ParserRules) => void;
|
||||
|
||||
// For getMessage
|
||||
export interface MessageFactory {
|
||||
<Args extends FormattedMessageArgs = FormattedMessageArgs, Markdown extends boolean = boolean>(
|
||||
message: string,
|
||||
locales?: string | readonly string[]
|
||||
): FormattedMessage<Args, Markdown>;
|
||||
(message?: null, locales?: string | readonly string[]): "";
|
||||
}
|
10
packages/discord-types/src/index.ts
Normal file
10
packages/discord-types/src/index.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export * from "./flux";
|
||||
export * from "./general";
|
||||
export * from "./i18n";
|
||||
export * from "./stores";
|
106
packages/discord-types/src/internal.ts
Normal file
106
packages/discord-types/src/internal.ts
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
/** @internal */
|
||||
export type Defined<T> = Exclude<T, undefined>;
|
||||
|
||||
/** @internal */
|
||||
export type GenericConstructor = new (...args: never) => unknown;
|
||||
|
||||
/** @internal */
|
||||
export type IsAny<T> = 0 extends 1 & T ? unknown : never;
|
||||
|
||||
/** @internal */
|
||||
export type IsDomainFinite<T extends PropertyKey>
|
||||
= unknown extends (
|
||||
T extends unknown
|
||||
? {} extends Record<T, unknown>
|
||||
? unknown
|
||||
: never
|
||||
: never
|
||||
)
|
||||
? never
|
||||
: unknown;
|
||||
|
||||
/** @internal */
|
||||
export type Nullish = null | undefined;
|
||||
|
||||
/** @internal */
|
||||
export type OmitIndexSignature<T>
|
||||
= { [Key in keyof T as {} extends Record<Key, unknown> ? never : Key]: T[Key]; };
|
||||
|
||||
/** @internal */
|
||||
export type OmitOptional<T>
|
||||
= { [Key in keyof T as T extends Record<Key, unknown> ? Key : never]: T[Key]; };
|
||||
|
||||
/** @internal */
|
||||
export type Optional<T, Value = undefined, Keys extends keyof T = keyof T, ExcludeKeys extends boolean = false>
|
||||
= ExcludeKeys extends true
|
||||
? Pick<T, Keys> & { [Key in Exclude<keyof T, Keys>]?: T[Key] | Value; }
|
||||
: Omit<T, Keys> & { [Key in Keys]?: T[Key] | Value; };
|
||||
|
||||
/** @internal */
|
||||
export type OptionalTuple<T extends readonly unknown[], Value = undefined>
|
||||
= { [Key in keyof T]?: T[Key] | Value; };
|
||||
|
||||
/** @internal */
|
||||
export type PartialOnUndefined<T> = Partial<T>
|
||||
& { [Key in keyof T as undefined extends T[Key] ? never : Key]: T[Key]; };
|
||||
|
||||
type SnakeCase<T extends string, InAcronym extends boolean = false>
|
||||
= T extends `${infer First}${infer Second}${infer Rest}`
|
||||
? InAcronym extends true
|
||||
? Second extends Uppercase<string>
|
||||
? `${Lowercase<First>}${SnakeCase<`${Second}${Rest}`, true>}`
|
||||
: `_${Lowercase<First>}${SnakeCase<`${Second}${Rest}`>}`
|
||||
: First extends Lowercase<string>
|
||||
? Second extends Lowercase<string>
|
||||
? `${First}${SnakeCase<`${Second}${Rest}`>}`
|
||||
: `${First}_${SnakeCase<`${Second}${Rest}`>}`
|
||||
: Second extends Uppercase<string>
|
||||
? `${Lowercase<First>}${SnakeCase<`${Second}${Rest}`, true>}`
|
||||
: `${Lowercase<First>}${SnakeCase<`${Second}${Rest}`>}`
|
||||
: Lowercase<T>;
|
||||
|
||||
/** @internal */
|
||||
export type SnakeCasedProperties<T>
|
||||
= { [Key in keyof T as Key extends string ? SnakeCase<Key> : Key]: T[Key]; };
|
||||
|
||||
type StringablePrimitive = string | bigint | number | boolean | Nullish;
|
||||
|
||||
/** @internal */
|
||||
export type Stringable
|
||||
= { [Symbol.toPrimitive]: (hint: "default" | "string") => StringablePrimitive; }
|
||||
| ({ toString: () => StringablePrimitive; } | { valueOf: () => StringablePrimitive; })
|
||||
& { [Symbol.toPrimitive]?: Nullish; };
|
||||
|
||||
/** @internal */
|
||||
export type StringProperties<T>
|
||||
= { [Key in keyof T as Exclude<Key, symbol>]: T[Key]; };
|
||||
|
||||
/** @internal */
|
||||
export type Subtract<T, U> = {
|
||||
[TKey in keyof T as keyof {
|
||||
[UKey in keyof U as UKey extends TKey
|
||||
? TKey extends UKey
|
||||
? UKey
|
||||
: never
|
||||
: never
|
||||
]: never;
|
||||
} extends never
|
||||
? TKey
|
||||
: never
|
||||
]: T[TKey];
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
export type UnionToIntersection<Union> = (
|
||||
Union extends unknown
|
||||
? (arg: Union) => unknown
|
||||
: never
|
||||
) extends ((arg: infer Intersection) => unknown)
|
||||
? Intersection & Union
|
||||
: never;
|
23
packages/discord-types/src/stores/ApplicationStore.ts
Normal file
23
packages/discord-types/src/stores/ApplicationStore.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Store } from "../flux/Store";
|
||||
import type { ApplicationRecord, ApplicationType } from "../general/ApplicationRecord";
|
||||
import type { Nullish } from "../internal";
|
||||
|
||||
export declare class ApplicationStore extends Store {
|
||||
static displayName: "ApplicationStore";
|
||||
|
||||
_getAllApplications(): ApplicationRecord[];
|
||||
didFetchingApplicationFail(applicationId: string): boolean;
|
||||
getApplication(applicationId: string): ApplicationRecord | undefined;
|
||||
getApplicationByName(applicationName?: string | null): ApplicationRecord | undefined;
|
||||
getApplicationLastUpdated(applicationId: string): number | undefined;
|
||||
getFetchingOrFailedFetchingIds(): string[];
|
||||
getGuildApplication(guildId: string | Nullish, applicationType: ApplicationType): ApplicationRecord | undefined;
|
||||
getGuildApplicationIds(guildId?: string | null): string[];
|
||||
isFetchingApplication(applicationId: string): boolean;
|
||||
}
|
41
packages/discord-types/src/stores/ChannelStore.ts
Normal file
41
packages/discord-types/src/stores/ChannelStore.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Store } from "../flux/Store";
|
||||
import type { ChannelRecord, GuildChannelRecord } from "../general/channels/ChannelRecord";
|
||||
import type { DMChannelRecord, PrivateChannelRecord } from "../general/channels/PrivateChannelRecord";
|
||||
import type { ThreadChannelRecord } from "../general/channels/ThreadChannelRecord";
|
||||
|
||||
export declare class ChannelStore extends Store {
|
||||
static displayName: "ChannelStore";
|
||||
|
||||
getAllThreadsForParent(channelId: string): ThreadChannelRecord[];
|
||||
/** @todo May not return a ChannelRecord. */
|
||||
getBasicChannel(channelId?: string | null): ChannelRecord | null;
|
||||
getChannel(channelId?: string | null): ChannelRecord | undefined;
|
||||
getChannelIds(guildId?: string | null): string[];
|
||||
getDebugInfo(): {
|
||||
guildSizes: string[];
|
||||
loadedGuildIds: string[];
|
||||
/** @todo */
|
||||
pendingGuildLoads: any[];
|
||||
};
|
||||
getDMChannelFromUserId(userId?: string | null): DMChannelRecord | undefined;
|
||||
getDMFromUserId(userId?: string | null): string | undefined;
|
||||
getDMUserIds(): string[];
|
||||
getGuildChannelsVersion(guildId: string): number;
|
||||
getInitialOverlayState(): { [channelId: string]: ChannelRecord; };
|
||||
/** @todo The returned object may not have ChannelRecords. */
|
||||
getMutableBasicGuildChannelsForGuild(guildId: string): { [channelId: string]: GuildChannelRecord; };
|
||||
getMutableDMsByUserIds(): { [userId: string]: string; };
|
||||
getMutableGuildChannelsForGuild(guildId: string): { [channelId: string]: GuildChannelRecord; };
|
||||
getMutablePrivateChannels(): { [channelId: string]: PrivateChannelRecord; };
|
||||
getPrivateChannelsVersion(): number;
|
||||
getSortedPrivateChannels(): PrivateChannelRecord[];
|
||||
hasChannel(channelId: string): boolean;
|
||||
initialize(): void;
|
||||
loadAllGuildAndPrivateChannelsFromDisk(): { [channelId: string]: GuildChannelRecord | PrivateChannelRecord; };
|
||||
}
|
33
packages/discord-types/src/stores/DraftStore.ts
Normal file
33
packages/discord-types/src/stores/DraftStore.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { PersistedStore } from "../flux/PersistedStore";
|
||||
import type { Draft, DraftForumThreadSettings, DraftNonForumThreadSettings, DraftType } from "../general/Draft";
|
||||
import type { GenericConstructor, Nullish } from "../internal";
|
||||
|
||||
export interface DraftStoreState {
|
||||
[userId: string]: { [channelId: string]: { [Type in DraftType]?: Draft<Type>; }; };
|
||||
}
|
||||
|
||||
export declare class DraftStore<
|
||||
Constructor extends GenericConstructor = typeof DraftStore,
|
||||
State extends DraftStoreState = DraftStoreState
|
||||
> extends PersistedStore<Constructor, State> {
|
||||
static displayName: "DraftStore";
|
||||
static persistKey: "DraftStore";
|
||||
|
||||
getDraft(channelId: string, draftType: DraftType): string;
|
||||
getRecentlyEditedDrafts<Type extends DraftType>(draftType: Type): {
|
||||
channelId: string;
|
||||
draft: "draft" extends keyof Draft<Type> ? Draft<Type>["draft"] : undefined;
|
||||
timestamp: number;
|
||||
}[];
|
||||
getState(): State;
|
||||
getThreadDraftWithParentMessageId(messageId: string): DraftNonForumThreadSettings | Nullish;
|
||||
getThreadSettings<ForumThread extends boolean = boolean>(threadId: string):
|
||||
(ForumThread extends true ? DraftForumThreadSettings : DraftNonForumThreadSettings) | Nullish;
|
||||
initialize(state?: State | null): void;
|
||||
}
|
88
packages/discord-types/src/stores/EmojiStore.ts
Normal file
88
packages/discord-types/src/stores/EmojiStore.ts
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { PersistedStore } from "../flux/PersistedStore";
|
||||
import type { ChannelRecord } from "../general/channels/ChannelRecord";
|
||||
import type { Emoji, GuildEmoji } from "../general/emojis/Emoji";
|
||||
import type { EmojiDisambiguations } from "../general/emojis/EmojiDisambiguations";
|
||||
import type { GuildEmojis } from "../general/emojis/GuildEmojis";
|
||||
import type { Frecency } from "../general/Frecency";
|
||||
import type { GenericConstructor, Nullish } from "../internal";
|
||||
|
||||
export interface EmojiStoreState {
|
||||
emojiReactionPendingUsages: EmojiUsage[];
|
||||
expandedSectionsByGuildIds: Set<string>;
|
||||
pendingUsages: EmojiUsage[];
|
||||
}
|
||||
|
||||
export interface EmojiUsage {
|
||||
key: string;
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
export declare class EmojiStore<
|
||||
Constructor extends GenericConstructor = typeof EmojiStore,
|
||||
State extends EmojiStoreState = EmojiStoreState
|
||||
> extends PersistedStore<Constructor, State> {
|
||||
static displayName: "EmojiStore";
|
||||
static persistKey: "EmojiStoreV2";
|
||||
|
||||
get categories(): string[];
|
||||
get diversitySurrogate(): string;
|
||||
get emojiFrecencyWithoutFetchingLatest(): Frecency<string, Emoji>;
|
||||
get emojiReactionFrecencyWithoutFetchingLatest(): Frecency<string, Emoji>;
|
||||
get expandedSectionsByGuildIds(): EmojiStoreState["expandedSectionsByGuildIds"];
|
||||
getCustomEmojiById(emojiId: string): GuildEmoji | undefined;
|
||||
getDisambiguatedEmojiContext(guildId?: string | null): EmojiDisambiguations;
|
||||
getEmojiAutosuggestion(channel?: ChannelRecord): Emoji[];
|
||||
getGuildEmoji(guildId: string): GuildEmoji[];
|
||||
getGuilds(): { [guildId: string]: GuildEmojis; };
|
||||
getNewlyAddedEmoji(guildId?: string | null): GuildEmoji[];
|
||||
/** If count is less than or equal to 0, all results will be returned. */
|
||||
getSearchResultsOrder(emojis: Emoji[], query: string, count: number): Emoji[];
|
||||
getState(): State;
|
||||
getTopEmoji(guildId?: string | null): GuildEmoji[];
|
||||
getTopEmojisMetadata(guildId: string): GuildTopEmojisMetadata | undefined;
|
||||
getUsableCustomEmojiById(emojiId: string): GuildEmoji | undefined;
|
||||
getUsableGuildEmoji(guildId: string): GuildEmoji[];
|
||||
hasFavoriteEmojis(guildId?: string | null): boolean;
|
||||
hasPendingUsage(): boolean;
|
||||
hasUsableEmojiInAnyGuild(): boolean;
|
||||
initialize(state?: State | null): void;
|
||||
get loadState(): number;
|
||||
/** If count is less than or equal to 0, all unlocked results will be returned. */
|
||||
searchWithoutFetchingLatest(options: {
|
||||
channel?: ChannelRecord | Nullish;
|
||||
count?: number | undefined /* = 0 */;
|
||||
includeExternalGuilds?: boolean | undefined /* = true */;
|
||||
intention: EmojiIntention;
|
||||
matchComparator?: ((value: string, index: number, array: string[]) => unknown) | Nullish;
|
||||
query: string;
|
||||
}): {
|
||||
locked: GuildEmoji[];
|
||||
unlocked: Emoji[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface GuildTopEmojisMetadata {
|
||||
emojiIds: string[];
|
||||
topEmojisTTL: number;
|
||||
}
|
||||
|
||||
export enum EmojiIntention {
|
||||
REACTION = 0,
|
||||
STATUS = 1,
|
||||
COMMUNITY_CONTENT = 2,
|
||||
CHAT = 3,
|
||||
GUILD_STICKER_RELATED_EMOJI = 4,
|
||||
GUILD_ROLE_BENEFIT_EMOJI = 5,
|
||||
SOUNDBOARD = 6,
|
||||
VOICE_CHANNEL_TOPIC = 7,
|
||||
GIFT = 8,
|
||||
AUTO_SUGGESTION = 9,
|
||||
POLLS = 10,
|
||||
PROFILE = 11,
|
||||
}
|
88
packages/discord-types/src/stores/GuildChannelStore.ts
Normal file
88
packages/discord-types/src/stores/GuildChannelStore.ts
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Store } from "../flux/Store";
|
||||
import { ChannelType, type GuildChannelRecord, type GuildSelectableChannelRecord } from "../general/channels/ChannelRecord";
|
||||
import type { GuildCategoryChannelRecord } from "../general/channels/GuildTextualChannelRecord";
|
||||
import type { GuildVocalChannelRecord } from "../general/channels/GuildVocalChannelRecord";
|
||||
|
||||
export declare class GuildChannelStore extends Store {
|
||||
static displayName: "GuildChannelStore";
|
||||
|
||||
getAllGuilds(): { [guildId: string]: GuildChannels | undefined; };
|
||||
getChannels(guildId?: string | null): GuildChannels;
|
||||
getDefaultChannel<SearchVocal extends boolean | undefined = undefined>(
|
||||
guild: string,
|
||||
searchVocal?: SearchVocal /* = false */,
|
||||
permissions?: /* Permissions */ bigint /* = Permissions.VIEW_CHANNEL */
|
||||
): ChannelFromSearchVocal<SearchVocal> | null;
|
||||
getDirectoryChannelIds(guildId: string): string[];
|
||||
getFirstChannel<SearchVocal extends boolean | undefined = undefined>(
|
||||
guildId: string,
|
||||
predicate: (
|
||||
value: ChannelFromSearchVocal<SearchVocal>,
|
||||
index: number,
|
||||
array: ChannelFromSearchVocal<SearchVocal>[]
|
||||
) => unknown,
|
||||
searchVocal?: SearchVocal /* = false */
|
||||
): ChannelFromSearchVocal<SearchVocal> | null;
|
||||
getFirstChannelOfType<Type extends GuildChannelType>(
|
||||
guildId: string,
|
||||
predicate: (
|
||||
value: ChannelFromGuildChannelType<Type>,
|
||||
index: number,
|
||||
array: ChannelFromGuildChannelType<Type>[]
|
||||
) => unknown,
|
||||
type: Type
|
||||
): ChannelFromGuildChannelType<Type> | null;
|
||||
getSelectableChannelIds(guildId: string): string[];
|
||||
getSelectableChannels(guildId: string): GuildChannel<GuildSelectableChannelRecord>[];
|
||||
getSFWDefaultChannel<SearchVocal extends boolean | undefined = undefined>(
|
||||
guild: string,
|
||||
searchVocal?: SearchVocal /* = false */,
|
||||
permissions?: /* Permissions */ bigint /* = Permissions.VIEW_CHANNEL */
|
||||
): ChannelFromSearchVocal<SearchVocal> | null;
|
||||
getTextChannelNameDisambiguations(guildId?: string | null): {
|
||||
[channelId: string]: { id: string; name: string; };
|
||||
};
|
||||
getVocalChannelIds(guildId: string): string[];
|
||||
hasCategories(guildId: string): boolean;
|
||||
hasChannels(guildId: string): boolean;
|
||||
hasElevatedPermissions(guildId: string): boolean;
|
||||
hasSelectableChannel(guildId: string, channelId: string): boolean;
|
||||
initialize(): void;
|
||||
}
|
||||
|
||||
export interface GuildChannels {
|
||||
count: number;
|
||||
[GuildChannelType.CATEGORY]: GuildChannel<GuildCategoryChannelRecord>[];
|
||||
[GuildChannelType.SELECTABLE]: GuildChannel<GuildSelectableChannelRecord>[];
|
||||
[GuildChannelType.VOCAL]: GuildChannel<GuildVocalChannelRecord>[];
|
||||
/** The ID of the guild. */
|
||||
id: string;
|
||||
}
|
||||
|
||||
// Does not actually exist.
|
||||
export enum GuildChannelType {
|
||||
CATEGORY = ChannelType.GUILD_CATEGORY,
|
||||
SELECTABLE = "SELECTABLE",
|
||||
VOCAL = "VOCAL",
|
||||
}
|
||||
|
||||
export interface GuildChannel<Channel extends GuildChannelRecord = GuildChannelRecord> {
|
||||
channel: Channel;
|
||||
comparator: number;
|
||||
}
|
||||
|
||||
type ChannelFromSearchVocal<SearchVocal extends boolean | undefined>
|
||||
= GuildSelectableChannelRecord
|
||||
| (SearchVocal extends true ? GuildVocalChannelRecord : never);
|
||||
|
||||
type ChannelFromGuildChannelType<Type extends GuildChannelType> = {
|
||||
[GuildChannelType.CATEGORY]: GuildCategoryChannelRecord;
|
||||
[GuildChannelType.SELECTABLE]: GuildSelectableChannelRecord;
|
||||
[GuildChannelType.VOCAL]: GuildVocalChannelRecord;
|
||||
}[Type];
|
36
packages/discord-types/src/stores/GuildMemberStore.ts
Normal file
36
packages/discord-types/src/stores/GuildMemberStore.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Store } from "../flux/Store";
|
||||
import type { GuildMember } from "../general/GuildMember";
|
||||
import type { Nullish } from "../internal";
|
||||
|
||||
export declare class GuildMemberStore extends Store {
|
||||
static displayName: "GuildMemberStore";
|
||||
|
||||
getCommunicationDisabledUserMap(): { [userId: string]: string; };
|
||||
getCommunicationDisabledVersion(): number;
|
||||
getMember(guildId: string, userId: string): GuildMember | null;
|
||||
getMemberIds(guildId?: string | null): string[];
|
||||
getMemberRoleWithPendingUpdates(guildId: string, userId: string): string[];
|
||||
getMembers(guildId?: string | null): GuildMember[];
|
||||
getMemberVersion(): number;
|
||||
getMutableAllGuildsAndMembers(): { [guildId: string]: { [userId: string]: GuildMember; }; };
|
||||
getNick(guildId?: string | null, userId?: string | null): string | null;
|
||||
getNicknameGuildsMapping(userId: string): { [nickname: string]: string[]; };
|
||||
getNicknames(userId: string): string[];
|
||||
getPendingRoleUpdates(guildId: string): {
|
||||
added: string[];
|
||||
removed: string[];
|
||||
};
|
||||
getSelfMember(guildId: string): GuildMember | Nullish;
|
||||
getTrueMember(guildId: string, userId: string): GuildMember | Nullish;
|
||||
initialize(): void;
|
||||
isCurrentUserGuest(guildId?: string | null): boolean;
|
||||
isGuestOrLurker(guildId?: string | null, userId?: string | null): boolean;
|
||||
isMember(guildId?: string | null, userId?: string | null): boolean;
|
||||
memberOf(userId: string): string[];
|
||||
}
|
23
packages/discord-types/src/stores/GuildStore.ts
Normal file
23
packages/discord-types/src/stores/GuildStore.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Store } from "../flux/Store";
|
||||
import type { GuildRecord } from "../general/GuildRecord";
|
||||
import type { Role } from "../general/Role";
|
||||
|
||||
export declare class GuildStore extends Store {
|
||||
static displayName: "GuildStore";
|
||||
|
||||
getAllGuildsRoles(): { [guildId: string]: { [roleId: string]: Role; }; };
|
||||
getGeoRestrictedGuilds(): { [guildId: string]: GuildRecord; };
|
||||
getGuild(guildId?: string | null): GuildRecord | undefined;
|
||||
getGuildCount(): number;
|
||||
getGuildIds(): string[];
|
||||
getGuilds(): { [guildId: string]: GuildRecord; };
|
||||
getRole(guildId: string, roleId: string): Role | undefined;
|
||||
getRoles(guildId: string): { [roleId: string]: Role; };
|
||||
isLoaded(): boolean;
|
||||
}
|
30
packages/discord-types/src/stores/MessageStore.ts
Normal file
30
packages/discord-types/src/stores/MessageStore.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* discord-types
|
||||
* Copyright (C) 2024 Vencord project contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Store } from "../flux/Store";
|
||||
import type { ChannelMessages } from "../general/messages/ChannelMessages";
|
||||
import type { MessageRecord } from "../general/messages/MessageRecord";
|
||||
import type { Nullish } from "../internal";
|
||||
|
||||
export declare class MessageStore extends Store {
|
||||
static displayName: "MessageStore";
|
||||
|
||||
focusedMessageId(channelId: string): string | undefined;
|
||||
getLastCommandMessage(channelId: string): MessageRecord | undefined;
|
||||
getLastEditableMessage(channelId: string): MessageRecord | undefined;
|
||||
getLastMessage(channelId: string): MessageRecord | undefined;
|
||||
getLastNonCurrentUserMessage(channelId: string): MessageRecord | undefined;
|
||||
getMessage(channelId: string, messageId: string): MessageRecord | undefined;
|
||||
getMessages(channelId: string): ChannelMessages;
|
||||
hasCurrentUserSentMessage(channelId: string): boolean;
|
||||
hasCurrentUserSentMessageSinceAppStart(): boolean;
|
||||
hasPresent(channelId: string): boolean;
|
||||
initialize(): void;
|
||||
isLoadingMessages(channelId: string): boolean;
|
||||
isReady(channelId: string): boolean;
|
||||
jumpedMessageId(channelId: string): string | Nullish;
|
||||
whenReady(channelId: string, callback: () => void): void;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue