Ran eslint

Signed-off-by: Scott Gould <greysilly7@gmail.com>
This commit is contained in:
Scott Gould 2024-09-19 08:21:12 -04:00
parent a81bc02a5a
commit a5b521e373
No known key found for this signature in database
34 changed files with 11972 additions and 12065 deletions

View file

@ -1,310 +0,0 @@
const globals = require("globals");
const unicorn = require("eslint-plugin-unicorn");
const sonarjs = require("eslint-plugin-sonarjs");
const stylistic = require("@stylistic/eslint-plugin-js");
const htmlESLint = require("@html-eslint/eslint-plugin");
const html = require("eslint-plugin-html");
const tsParser = require("@typescript-eslint/parser");
const linterOptions = {
reportUnusedDisableDirectives: "error"
};
const global = {
...globals.browser
};
const rules = {
"array-callback-return": 2,
"block-scoped-var": 2,
"default-case-last": 2,
"default-param-last": 1,
"dot-notation": 1,
"func-name-matching": 2,
"func-style": 0,
"no-array-constructor": 2,
"no-compare-neg-zero": 2,
"no-const-assign": 2,
"no-constructor-return": 2,
"no-dupe-args": 1,
"no-dupe-keys": 2,
"no-duplicate-case": 2,
"no-div-regex": 2,
"no-eq-null": 2,
"no-extra-boolean-cast": 2,
"no-extra-bind": 2,
"no-extend-native": 2,
"no-empty-pattern": 2,
"no-duplicate-imports": 2,
"no-fallthrough": 2,
"no-func-assign": 2,
"no-import-assign": 2,
"no-invalid-regexp": 2,
"no-invalid-this": 2,
"no-implicit-coercion": [2, {
string: false
}],
"no-implied-eval": 2,
"no-loss-of-precision": 2,
"no-multi-assign": 1,
"no-negated-condition": 1,
"no-new-native-nonconstructor": 2,
"no-new-object": 2,
"no-obj-calls": 2,
"no-self-assign": 2,
"no-unreachable": 1,
"no-unreachable-loop": 1,
"no-unsafe-finally": 2,
"no-unused-vars": 1,
"no-useless-computed-key": 2,
"no-useless-rename": 1,
"no-useless-escape": 1,
"no-unused-expressions": 1,
"no-useless-return": 1,
"no-useless-call": 2,
"no-use-before-define": 0,
"no-useless-concat": 1,
"no-useless-backreference": 1,
"no-useless-catch": 1,
"no-unneeded-ternary": 1,
"no-undef": [2, {
typeof: true
}],
"no-undef-init": 2,
"no-useless-constructor": 1,
"no-redeclare": 1,
"no-shadow-restricted-names": 2,
"no-empty-static-block": 1,
"no-throw-literal": 2,
"no-template-curly-in-string": 1,
"no-unsafe-optional-chaining": 2,
"no-unmodified-loop-condition": 1,
"no-promise-executor-return": 2,
"no-warning-comments": 1,
"no-var": 1,
"no-new-func": 2,
"no-new-wrappers": 2,
"no-multi-str": 2,
"no-shadow": [1, {
builtinGlobals: false
}],
"no-self-compare": 2,
"no-regex-spaces": 1,
"no-constant-binary-expression": 2,
"no-sequences": 2,
"no-irregular-whitespace": [2, {
skipRegExps: true
}],
"no-constant-condition": 1,
"no-unsafe-negation": 2,
"no-lone-blocks": 2,
"object-shorthand": 1,
"prefer-arrow-callback": 1,
"prefer-const": 1,
"use-isnan": 1,
"valid-typeof": 2,
yoda: 2,
"@stylistic/array-bracket-spacing": 2,
"@stylistic/arrow-parens": [2, "as-needed"],
"@stylistic/arrow-spacing": [2, { before: false, after: false }],
"@stylistic/block-spacing": [2, "never"],
"@stylistic/brace-style": 1,
"@stylistic/comma-style": 2,
"@stylistic/computed-property-spacing": 2,
"@stylistic/dot-location": [2, "property"],
"@stylistic/function-call-spacing": 2,
"@stylistic/generator-star-spacing": 2,
"@stylistic/key-spacing": 2,
"@stylistic/indent": [1, "tab"],
"@stylistic/keyword-spacing": [1, { before: false, after: false }],
"@stylistic/new-parens": 2,
"@stylistic/no-mixed-operators": [2, {
groups: [["*", "/"], ["+", "-"]]
}],
"@stylistic/no-extra-semi": 1,
"@stylistic/no-multi-spaces": 1,
"@stylistic/no-mixed-spaces-and-tabs": 2,
"@stylistic/no-floating-decimal": 2,
"@stylistic/no-whitespace-before-property": 2,
"@stylistic/no-trailing-spaces": 1,
"@stylistic/max-statements-per-line": 1,
"@stylistic/max-len": [1, {
code: 200
}],
"@stylistic/quote-props": [2, "as-needed"],
"@stylistic/quotes": [1, "double", {
avoidEscape: false
}],
"@stylistic/padded-blocks": [2, "never"],
"@stylistic/rest-spread-spacing": 2,
"@stylistic/semi": 1,
"@stylistic/space-before-blocks": [2, "never"],
"@stylistic/space-before-function-paren": [2, {
named: "never",
anonymous: "never",
asyncArrow: "always"
}],
"@stylistic/space-in-parens": 2,
"@stylistic/space-unary-ops": 2,
"@stylistic/yield-star-spacing": 2,
"unicorn/error-message": 2,
"unicorn/new-for-builtins": 2,
"unicorn/consistent-empty-array-spread": 2,
"unicorn/consistent-destructuring": 2,
"unicorn/consistent-function-scoping": 2,
"unicorn/no-array-method-this-argument": 2,
"unicorn/no-lonely-if": 1,
"unicorn/no-invalid-fetch-options": 2,
"unicorn/no-instanceof-array": 2,
"unicorn/no-magic-array-flat-depth": 2,
"unicorn/no-nested-ternary": 2,
"unicorn/no-new-buffer": 2,
"unicorn/no-console-spaces": 2,
"unicorn/no-for-loop": 2,
"unicorn/no-useless-undefined": 2,
"unicorn/no-unreadable-iife": 2,
"unicorn/no-unnecessary-await": 2,
"unicorn/no-unreadable-array-destructuring": 2,
"unicorn/no-useless-switch-case": 2,
"unicorn/no-typeof-undefined": 2,
"unicorn/no-useless-fallback-in-spread": 2,
"unicorn/no-useless-length-check": 2,
"unicorn/no-useless-spread": 2,
"unicorn/no-useless-promise-resolve-reject": 2,
"unicorn/no-zero-fractions": 2,
"unicorn/prefer-array-find": 1,
"unicorn/prefer-array-index-of": 1,
"unicorn/prefer-includes": 1,
"unicorn/prefer-logical-operator-over-ternary": 1,
"unicorn/prefer-date-now": 1,
"unicorn/prefer-default-parameters": 1,
"unicorn/prefer-array-some": 1,
"unicorn/prefer-blob-reading-methods": 1,
"unicorn/prefer-at": 1,
"unicorn/prefer-optional-catch-binding": 1,
"unicorn/prefer-regexp-test": 1,
"unicorn/prefer-set-has": 1,
"unicorn/prefer-set-size": 1,
"unicorn/prefer-keyboard-event-key": 1,
"unicorn/prefer-negative-index": 1,
"unicorn/prefer-node-protocol": 1,
"unicorn/prefer-number-properties": [1, {
checkInfinity: true
}],
"unicorn/prefer-prototype-methods": 1,
"unicorn/prefer-string-trim-start-end": 1,
"unicorn/prefer-string-starts-ends-with": 1,
"unicorn/prefer-structured-clone": 1,
"unicorn/throw-new-error": 2,
"unicorn/require-number-to-fixed-digits-argument": 2,
"unicorn/switch-case-braces": [1, "avoid"],
"unicorn/text-encoding-identifier-case": 2,
"unicorn/no-await-in-promise-methods": 2,
"unicorn/no-single-promise-in-promise-methods": 2,
"unicorn/no-negation-in-equality-check": 2,
"unicorn/no-length-as-slice-end": 2,
"sonarjs/no-extra-arguments": 2,
"sonarjs/no-empty-collection": 2,
"sonarjs/no-element-overwrite": 2,
"sonarjs/no-use-of-empty-return-value": 2,
"sonarjs/no-all-duplicated-branches": 2,
"sonarjs/no-ignored-return": 2,
"sonarjs/no-identical-expressions": 2,
"sonarjs/no-one-iteration-loop": 2,
"sonarjs/non-existent-operator": 2,
"sonarjs/no-redundant-boolean": 2,
"sonarjs/no-unused-collection": 1,
"sonarjs/prefer-immediate-return": 2,
"sonarjs/no-inverted-boolean-check": 2,
"sonarjs/no-redundant-jump": 2,
"sonarjs/no-same-line-conditional": 2,
"sonarjs/prefer-object-literal": 2,
"sonarjs/no-collection-size-mischeck": 2,
"sonarjs/prefer-while": 2,
"sonarjs/no-gratuitous-expressions": 2,
"sonarjs/no-duplicated-branches": 2
};
module.exports = [
{
linterOptions,
languageOptions: {
parser: tsParser,
globals: global
},
files: ["webpage/*.ts"],
ignores: ["!*.js", "!*.ts"],
plugins: {
unicorn,
sonarjs,
"@stylistic": stylistic
},
rules
},{
linterOptions,
languageOptions: {
parser: tsParser,
globals: globals.node
},
files: ["*.js", "*.ts"],
plugins: {
unicorn,
sonarjs,
"@stylistic": stylistic
},
rules
},{
linterOptions,
languageOptions: {
globals: global,
parser: require("@html-eslint/parser")
},
files: ["**/*.html"],
plugins: {
unicorn,
sonarjs,
"@stylistic": stylistic,
"@html-eslint": htmlESLint,
html
},
settings: {
"html/html-extensions": [".html"]
},
rules: {
...rules,
"@html-eslint/require-meta-charset": 2,
"@html-eslint/require-button-type": 2,
"@html-eslint/no-restricted-attrs": 2,
"@html-eslint/no-multiple-h1": 1,
"@html-eslint/require-meta-description": 1,
"@html-eslint/no-skip-heading-levels": 2,
"@html-eslint/require-frame-title": 2,
"@html-eslint/no-non-scalable-viewport": 2,
"@html-eslint/no-positive-tabindex": 2,
"@html-eslint/require-meta-viewport": 2,
"@html-eslint/no-abstract-roles": 2,
"@html-eslint/no-aria-hidden-body": 2,
"@html-eslint/no-accesskey-attrs": 2,
"@html-eslint/no-multiple-empty-lines": 2,
"@html-eslint/no-trailing-spaces": 2,
"@html-eslint/indent": [1, "tab"],
"@html-eslint/no-duplicate-attrs": 2,
"@html-eslint/no-inline-styles": 1,
"@html-eslint/no-duplicate-id": 2,
"@html-eslint/no-script-style-type": 2,
"@html-eslint/require-li-container": 2,
"@html-eslint/require-closing-tags": 2,
"@html-eslint/require-doctype": 2,
"@html-eslint/require-lang": 2,
"@html-eslint/require-title": 2,
"@html-eslint/no-extra-spacing-attrs": 2,
"@html-eslint/quotes": 2,
"@html-eslint/require-img-alt": 1
}
}
];

183
eslint.config.mjs Normal file
View file

@ -0,0 +1,183 @@
// @ts-check
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
import html from "@html-eslint/eslint-plugin";
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.stylisticTypeChecked,
html.configs["flat/recommended"],
{
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
files: ["**/*.ts", "**/*.html"],
rules: {
"array-callback-return": 2,
"block-scoped-var": 2,
"default-case-last": 2,
"default-param-last": 1,
"dot-notation": 1,
"func-name-matching": 2,
"func-style": 0,
"no-array-constructor": 2,
"no-compare-neg-zero": 2,
"no-const-assign": 2,
"no-constructor-return": 2,
"no-dupe-args": 1,
"no-dupe-keys": 2,
"no-duplicate-case": 2,
"no-div-regex": 2,
"no-eq-null": 2,
"no-extra-boolean-cast": 2,
"no-extra-bind": 2,
"no-extend-native": 2,
"no-empty-pattern": 2,
"no-duplicate-imports": 2,
"no-fallthrough": 2,
"no-func-assign": 2,
"no-import-assign": 2,
"no-invalid-regexp": 2,
"no-invalid-this": 2,
"no-implicit-coercion": [
2,
{
string: false,
},
],
"no-implied-eval": 2,
"no-loss-of-precision": 2,
"no-multi-assign": 1,
"no-negated-condition": 1,
"no-new-native-nonconstructor": 2,
"no-new-object": 2,
"no-obj-calls": 2,
"no-self-assign": 2,
"no-unreachable": 1,
"no-unreachable-loop": 1,
"no-unsafe-finally": 2,
"no-unused-vars": 1,
"no-useless-computed-key": 2,
"no-useless-rename": 1,
"no-useless-escape": 1,
"no-unused-expressions": 1,
"no-useless-return": 1,
"no-useless-call": 2,
"no-use-before-define": 0,
"no-useless-concat": 1,
"no-useless-backreference": 1,
"no-useless-catch": 1,
"no-unneeded-ternary": 1,
"no-undef": [
2,
{
typeof: true,
},
],
"no-undef-init": 2,
"no-useless-constructor": 1,
"no-redeclare": 1,
"no-shadow-restricted-names": 2,
"no-empty-static-block": 1,
"no-throw-literal": 2,
"no-template-curly-in-string": 1,
"no-unsafe-optional-chaining": 2,
"no-unmodified-loop-condition": 1,
"no-promise-executor-return": 2,
"no-warning-comments": 1,
"no-var": 1,
"no-new-func": 2,
"no-new-wrappers": 2,
"no-multi-str": 2,
"no-shadow": [
1,
{
builtinGlobals: false,
},
],
"no-self-compare": 2,
"no-regex-spaces": 1,
"no-constant-binary-expression": 2,
"no-sequences": 2,
"no-irregular-whitespace": [
2,
{
skipRegExps: true,
},
],
"no-constant-condition": 1,
"no-unsafe-negation": 2,
"no-lone-blocks": 2,
"object-shorthand": 1,
"prefer-arrow-callback": 1,
"prefer-const": 1,
"use-isnan": 1,
"valid-typeof": 2,
yoda: 2,
"@stylistic/array-bracket-spacing": 2,
"@stylistic/arrow-parens": [2, "as-needed"],
"@stylistic/arrow-spacing": [2, { before: false, after: false }],
"@stylistic/block-spacing": [2, "never"],
"@stylistic/brace-style": 1,
"@stylistic/comma-style": 2,
"@stylistic/computed-property-spacing": 2,
"@stylistic/dot-location": [2, "property"],
"@stylistic/function-call-spacing": 2,
"@stylistic/generator-star-spacing": 2,
"@stylistic/key-spacing": 2,
"@stylistic/indent": [1, "tab"],
"@stylistic/keyword-spacing": [1, { before: false, after: false }],
"@stylistic/new-parens": 2,
"@stylistic/no-mixed-operators": [
2,
{
groups: [
["*", "/"],
["+", "-"],
],
},
],
"@stylistic/no-extra-semi": 1,
"@stylistic/no-multi-spaces": 1,
"@stylistic/no-mixed-spaces-and-tabs": 2,
"@stylistic/no-floating-decimal": 2,
"@stylistic/no-whitespace-before-property": 2,
"@stylistic/no-trailing-spaces": 1,
"@stylistic/max-statements-per-line": 1,
"@stylistic/max-len": [
1,
{
code: 200,
},
],
"@stylistic/quote-props": [2, "as-needed"],
"@stylistic/quotes": [
1,
"double",
{
avoidEscape: false,
},
],
"@stylistic/padded-blocks": [2, "never"],
"@stylistic/rest-spread-spacing": 2,
"@stylistic/semi": 1,
"@stylistic/space-before-blocks": [2, "never"],
"@stylistic/space-before-function-paren": [
2,
{
named: "never",
anonymous: "never",
asyncArrow: "always",
},
],
"@stylistic/space-in-parens": 2,
"@stylistic/space-unary-ops": 2,
"@stylistic/yield-star-spacing": 2,
},
}
);

240
package-lock.json generated
View file

@ -15,7 +15,7 @@
"ts-to-jsdoc": "^2.2.0" "ts-to-jsdoc": "^2.2.0"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.7.0", "@eslint/js": "^9.10.0",
"@html-eslint/eslint-plugin": "^0.25.0", "@html-eslint/eslint-plugin": "^0.25.0",
"@html-eslint/parser": "^0.25.0", "@html-eslint/parser": "^0.25.0",
"@stylistic/eslint-plugin": "^2.3.0", "@stylistic/eslint-plugin": "^2.3.0",
@ -23,7 +23,7 @@
"@types/eslint__js": "^8.42.3", "@types/eslint__js": "^8.42.3",
"@types/express": "^4.17.21", "@types/express": "^4.17.21",
"@types/node-fetch": "^2.6.11", "@types/node-fetch": "^2.6.11",
"eslint": "^8.57.0", "eslint": "^8.57.1",
"eslint-plugin-html": "^8.1.1", "eslint-plugin-html": "^8.1.1",
"eslint-plugin-sonarjs": "^1.0.4", "eslint-plugin-sonarjs": "^1.0.4",
"eslint-plugin-unicorn": "^55.0.0", "eslint-plugin-unicorn": "^55.0.0",
@ -31,8 +31,8 @@
"gulp-copy": "^5.0.0", "gulp-copy": "^5.0.0",
"gulp-typescript": "^6.0.0-alpha.1", "gulp-typescript": "^6.0.0-alpha.1",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"typescript": "^5.5.4", "typescript": "^5.6.2",
"typescript-eslint": "^7.17.0" "typescript-eslint": "^7.18.0"
} }
}, },
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
@ -290,10 +290,11 @@
"dev": true "dev": true
}, },
"node_modules/@eslint/js": { "node_modules/@eslint/js": {
"version": "9.7.0", "version": "9.10.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.7.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.10.0.tgz",
"integrity": "sha512-ChuWDQenef8OSFnvuxv0TCVxEwmu3+hPNKvM9B34qpM0rDRbjL8t5QkQeHHeAfsKQjuH9wS82WeCi1J/owatng==", "integrity": "sha512-fuXtbiP5GWIn8Fz+LWoOMVf/Jxm+aajZYkhi6CuEm4SxymFM+eUWzbO9qXT+L0iCkL5+KGYMCSGxo686H19S1g==",
"dev": true, "dev": true,
"license": "MIT",
"engines": { "engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
} }
@ -326,6 +327,7 @@
"resolved": "https://registry.npmjs.org/@html-eslint/eslint-plugin/-/eslint-plugin-0.25.0.tgz", "resolved": "https://registry.npmjs.org/@html-eslint/eslint-plugin/-/eslint-plugin-0.25.0.tgz",
"integrity": "sha512-5DlvqO8bbe90cKSfFDuEblyrEnhAdgNTjWxXeUxt/XXC2OuMC8CsxzLZjtK3+0X6yM8m4xcE3fymCPwg7zdcXQ==", "integrity": "sha512-5DlvqO8bbe90cKSfFDuEblyrEnhAdgNTjWxXeUxt/XXC2OuMC8CsxzLZjtK3+0X6yM8m4xcE3fymCPwg7zdcXQ==",
"dev": true, "dev": true,
"license": "MIT",
"engines": { "engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
} }
@ -335,6 +337,7 @@
"resolved": "https://registry.npmjs.org/@html-eslint/parser/-/parser-0.25.0.tgz", "resolved": "https://registry.npmjs.org/@html-eslint/parser/-/parser-0.25.0.tgz",
"integrity": "sha512-dj6U1klMorS/g1QFI6j15AXknsqMDtdingSF6Sdtm1Z7WOVISfDwVyeNbb+JLUG+ATo9aECPQP5A7MHqgP6J9A==", "integrity": "sha512-dj6U1klMorS/g1QFI6j15AXknsqMDtdingSF6Sdtm1Z7WOVISfDwVyeNbb+JLUG+ATo9aECPQP5A7MHqgP6J9A==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"es-html-parser": "^0.0.9" "es-html-parser": "^0.0.9"
}, },
@ -343,13 +346,14 @@
} }
}, },
"node_modules/@humanwhocodes/config-array": { "node_modules/@humanwhocodes/config-array": {
"version": "0.11.14", "version": "0.13.0",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
"integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
"deprecated": "Use @eslint/config-array instead", "deprecated": "Use @eslint/config-array instead",
"dev": true, "dev": true,
"license": "Apache-2.0",
"dependencies": { "dependencies": {
"@humanwhocodes/object-schema": "^2.0.2", "@humanwhocodes/object-schema": "^2.0.3",
"debug": "^4.3.1", "debug": "^4.3.1",
"minimatch": "^3.0.5" "minimatch": "^3.0.5"
}, },
@ -362,18 +366,20 @@
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
} }
}, },
"node_modules/@humanwhocodes/config-array/node_modules/debug": { "node_modules/@humanwhocodes/config-array/node_modules/debug": {
"version": "4.3.5", "version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"ms": "2.1.2" "ms": "^2.1.3"
}, },
"engines": { "engines": {
"node": ">=6.0" "node": ">=6.0"
@ -389,6 +395,7 @@
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true, "dev": true,
"license": "ISC",
"dependencies": { "dependencies": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
}, },
@ -397,10 +404,11 @@
} }
}, },
"node_modules/@humanwhocodes/config-array/node_modules/ms": { "node_modules/@humanwhocodes/config-array/node_modules/ms": {
"version": "2.1.2", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true "dev": true,
"license": "MIT"
}, },
"node_modules/@humanwhocodes/module-importer": { "node_modules/@humanwhocodes/module-importer": {
"version": "1.0.1", "version": "1.0.1",
@ -420,7 +428,8 @@
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
"deprecated": "Use @eslint/object-schema instead", "deprecated": "Use @eslint/object-schema instead",
"dev": true "dev": true,
"license": "BSD-3-Clause"
}, },
"node_modules/@jridgewell/resolve-uri": { "node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2", "version": "3.1.2",
@ -653,6 +662,7 @@
"resolved": "https://registry.npmjs.org/@types/eslint__js/-/eslint__js-8.42.3.tgz", "resolved": "https://registry.npmjs.org/@types/eslint__js/-/eslint__js-8.42.3.tgz",
"integrity": "sha512-alfG737uhmPdnvkrLdZLcEKJ/B8s9Y4hrZ+YAdzUeoArBlSUERA2E87ROfOaS4jd/C45fzOoZzidLc1IPwLqOw==", "integrity": "sha512-alfG737uhmPdnvkrLdZLcEKJ/B8s9Y4hrZ+YAdzUeoArBlSUERA2E87ROfOaS4jd/C45fzOoZzidLc1IPwLqOw==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"@types/eslint": "*" "@types/eslint": "*"
} }
@ -774,16 +784,17 @@
} }
}, },
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "7.17.0", "version": "7.18.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.17.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz",
"integrity": "sha512-pyiDhEuLM3PuANxH7uNYan1AaFs5XE0zw1hq69JBvGvE7gSuEoQl1ydtEe/XQeoC3GQxLXyOVa5kNOATgM638A==", "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/regexpp": "^4.10.0", "@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "7.17.0", "@typescript-eslint/scope-manager": "7.18.0",
"@typescript-eslint/type-utils": "7.17.0", "@typescript-eslint/type-utils": "7.18.0",
"@typescript-eslint/utils": "7.17.0", "@typescript-eslint/utils": "7.18.0",
"@typescript-eslint/visitor-keys": "7.17.0", "@typescript-eslint/visitor-keys": "7.18.0",
"graphemer": "^1.4.0", "graphemer": "^1.4.0",
"ignore": "^5.3.1", "ignore": "^5.3.1",
"natural-compare": "^1.4.0", "natural-compare": "^1.4.0",
@ -807,15 +818,16 @@
} }
}, },
"node_modules/@typescript-eslint/parser": { "node_modules/@typescript-eslint/parser": {
"version": "7.17.0", "version": "7.18.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.17.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz",
"integrity": "sha512-puiYfGeg5Ydop8eusb/Hy1k7QmOU6X3nvsqCgzrB2K4qMavK//21+PzNE8qeECgNOIoertJPUC1SpegHDI515A==", "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==",
"dev": true, "dev": true,
"license": "BSD-2-Clause",
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "7.17.0", "@typescript-eslint/scope-manager": "7.18.0",
"@typescript-eslint/types": "7.17.0", "@typescript-eslint/types": "7.18.0",
"@typescript-eslint/typescript-estree": "7.17.0", "@typescript-eslint/typescript-estree": "7.18.0",
"@typescript-eslint/visitor-keys": "7.17.0", "@typescript-eslint/visitor-keys": "7.18.0",
"debug": "^4.3.4" "debug": "^4.3.4"
}, },
"engines": { "engines": {
@ -835,12 +847,13 @@
} }
}, },
"node_modules/@typescript-eslint/parser/node_modules/debug": { "node_modules/@typescript-eslint/parser/node_modules/debug": {
"version": "4.3.5", "version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"ms": "2.1.2" "ms": "^2.1.3"
}, },
"engines": { "engines": {
"node": ">=6.0" "node": ">=6.0"
@ -852,19 +865,21 @@
} }
}, },
"node_modules/@typescript-eslint/parser/node_modules/ms": { "node_modules/@typescript-eslint/parser/node_modules/ms": {
"version": "2.1.2", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true "dev": true,
"license": "MIT"
}, },
"node_modules/@typescript-eslint/scope-manager": { "node_modules/@typescript-eslint/scope-manager": {
"version": "7.17.0", "version": "7.18.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.17.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz",
"integrity": "sha512-0P2jTTqyxWp9HiKLu/Vemr2Rg1Xb5B7uHItdVZ6iAenXmPo4SZ86yOPCJwMqpCyaMiEHTNqizHfsbmCFT1x9SA==", "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "7.17.0", "@typescript-eslint/types": "7.18.0",
"@typescript-eslint/visitor-keys": "7.17.0" "@typescript-eslint/visitor-keys": "7.18.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || >=20.0.0" "node": "^18.18.0 || >=20.0.0"
@ -875,13 +890,14 @@
} }
}, },
"node_modules/@typescript-eslint/type-utils": { "node_modules/@typescript-eslint/type-utils": {
"version": "7.17.0", "version": "7.18.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.17.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz",
"integrity": "sha512-XD3aaBt+orgkM/7Cei0XNEm1vwUxQ958AOLALzPlbPqb8C1G8PZK85tND7Jpe69Wualri81PLU+Zc48GVKIMMA==", "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/typescript-estree": "7.17.0", "@typescript-eslint/typescript-estree": "7.18.0",
"@typescript-eslint/utils": "7.17.0", "@typescript-eslint/utils": "7.18.0",
"debug": "^4.3.4", "debug": "^4.3.4",
"ts-api-utils": "^1.3.0" "ts-api-utils": "^1.3.0"
}, },
@ -902,12 +918,13 @@
} }
}, },
"node_modules/@typescript-eslint/type-utils/node_modules/debug": { "node_modules/@typescript-eslint/type-utils/node_modules/debug": {
"version": "4.3.5", "version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"ms": "2.1.2" "ms": "^2.1.3"
}, },
"engines": { "engines": {
"node": ">=6.0" "node": ">=6.0"
@ -919,16 +936,18 @@
} }
}, },
"node_modules/@typescript-eslint/type-utils/node_modules/ms": { "node_modules/@typescript-eslint/type-utils/node_modules/ms": {
"version": "2.1.2", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true "dev": true,
"license": "MIT"
}, },
"node_modules/@typescript-eslint/types": { "node_modules/@typescript-eslint/types": {
"version": "7.17.0", "version": "7.18.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.17.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz",
"integrity": "sha512-a29Ir0EbyKTKHnZWbNsrc/gqfIBqYPwj3F2M+jWE/9bqfEHg0AMtXzkbUkOG6QgEScxh2+Pz9OXe11jHDnHR7A==", "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==",
"dev": true, "dev": true,
"license": "MIT",
"engines": { "engines": {
"node": "^18.18.0 || >=20.0.0" "node": "^18.18.0 || >=20.0.0"
}, },
@ -938,13 +957,14 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree": { "node_modules/@typescript-eslint/typescript-estree": {
"version": "7.17.0", "version": "7.18.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.17.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz",
"integrity": "sha512-72I3TGq93t2GoSBWI093wmKo0n6/b7O4j9o8U+f65TVD0FS6bI2180X5eGEr8MA8PhKMvYe9myZJquUT2JkCZw==", "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==",
"dev": true, "dev": true,
"license": "BSD-2-Clause",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "7.17.0", "@typescript-eslint/types": "7.18.0",
"@typescript-eslint/visitor-keys": "7.17.0", "@typescript-eslint/visitor-keys": "7.18.0",
"debug": "^4.3.4", "debug": "^4.3.4",
"globby": "^11.1.0", "globby": "^11.1.0",
"is-glob": "^4.0.3", "is-glob": "^4.0.3",
@ -966,12 +986,13 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": {
"version": "4.3.5", "version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"ms": "2.1.2" "ms": "^2.1.3"
}, },
"engines": { "engines": {
"node": ">=6.0" "node": ">=6.0"
@ -983,21 +1004,23 @@
} }
}, },
"node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": {
"version": "2.1.2", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true "dev": true,
"license": "MIT"
}, },
"node_modules/@typescript-eslint/utils": { "node_modules/@typescript-eslint/utils": {
"version": "7.17.0", "version": "7.18.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.17.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz",
"integrity": "sha512-r+JFlm5NdB+JXc7aWWZ3fKSm1gn0pkswEwIYsrGPdsT2GjsRATAKXiNtp3vgAAO1xZhX8alIOEQnNMl3kbTgJw==", "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.4.0", "@eslint-community/eslint-utils": "^4.4.0",
"@typescript-eslint/scope-manager": "7.17.0", "@typescript-eslint/scope-manager": "7.18.0",
"@typescript-eslint/types": "7.17.0", "@typescript-eslint/types": "7.18.0",
"@typescript-eslint/typescript-estree": "7.17.0" "@typescript-eslint/typescript-estree": "7.18.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || >=20.0.0" "node": "^18.18.0 || >=20.0.0"
@ -1011,12 +1034,13 @@
} }
}, },
"node_modules/@typescript-eslint/visitor-keys": { "node_modules/@typescript-eslint/visitor-keys": {
"version": "7.17.0", "version": "7.18.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.17.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz",
"integrity": "sha512-RVGC9UhPOCsfCdI9pU++K4nD7to+jTcMIbXTSOcrLqUEW6gF2pU1UUbYJKc9cvcRSK1UDeMJ7pdMxf4bhMpV/A==", "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/types": "7.17.0", "@typescript-eslint/types": "7.18.0",
"eslint-visitor-keys": "^3.4.3" "eslint-visitor-keys": "^3.4.3"
}, },
"engines": { "engines": {
@ -1032,6 +1056,7 @@
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true, "dev": true,
"license": "Apache-2.0",
"engines": { "engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}, },
@ -1257,6 +1282,7 @@
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
"dev": true, "dev": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=8" "node": ">=8"
} }
@ -2024,6 +2050,7 @@
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"path-type": "^4.0.0" "path-type": "^4.0.0"
}, },
@ -2239,16 +2266,17 @@
} }
}, },
"node_modules/eslint": { "node_modules/eslint": {
"version": "8.57.0", "version": "8.57.1",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
"integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1", "@eslint-community/regexpp": "^4.6.1",
"@eslint/eslintrc": "^2.1.4", "@eslint/eslintrc": "^2.1.4",
"@eslint/js": "8.57.0", "@eslint/js": "8.57.1",
"@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/config-array": "^0.13.0",
"@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8", "@nodelib/fs.walk": "^1.2.8",
"@ungap/structured-clone": "^1.2.0", "@ungap/structured-clone": "^1.2.0",
@ -2391,10 +2419,11 @@
} }
}, },
"node_modules/eslint/node_modules/@eslint/js": { "node_modules/eslint/node_modules/@eslint/js": {
"version": "8.57.0", "version": "8.57.1",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
"integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
"dev": true, "dev": true,
"license": "MIT",
"engines": { "engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
} }
@ -3135,6 +3164,7 @@
"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
"integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"array-union": "^2.1.0", "array-union": "^2.1.0",
"dir-glob": "^3.0.1", "dir-glob": "^3.0.1",
@ -4743,6 +4773,7 @@
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"dev": true, "dev": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=8" "node": ">=8"
} }
@ -5458,6 +5489,7 @@
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true, "dev": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=8" "node": ">=8"
} }
@ -5893,10 +5925,11 @@
} }
}, },
"node_modules/typescript": { "node_modules/typescript": {
"version": "5.5.4", "version": "5.6.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz",
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==",
"dev": true, "dev": true,
"license": "Apache-2.0",
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@ -5906,14 +5939,15 @@
} }
}, },
"node_modules/typescript-eslint": { "node_modules/typescript-eslint": {
"version": "7.17.0", "version": "7.18.0",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.17.0.tgz", "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.18.0.tgz",
"integrity": "sha512-spQxsQvPguduCUfyUvLItvKqK3l8KJ/kqs5Pb/URtzQ5AC53Z6us32St37rpmlt2uESG23lOFpV4UErrmy4dZQ==", "integrity": "sha512-PonBkP603E3tt05lDkbOMyaxJjvKqQrXsnow72sVeOFINDE/qNmnnd+f9b4N+U7W6MXnnYyrhtmF2t08QWwUbA==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"@typescript-eslint/eslint-plugin": "7.17.0", "@typescript-eslint/eslint-plugin": "7.18.0",
"@typescript-eslint/parser": "7.17.0", "@typescript-eslint/parser": "7.18.0",
"@typescript-eslint/utils": "7.17.0" "@typescript-eslint/utils": "7.18.0"
}, },
"engines": { "engines": {
"node": "^18.18.0 || >=20.0.0" "node": "^18.18.0 || >=20.0.0"

View file

@ -18,7 +18,7 @@
"ts-to-jsdoc": "^2.2.0" "ts-to-jsdoc": "^2.2.0"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.7.0", "@eslint/js": "^9.10.0",
"@html-eslint/eslint-plugin": "^0.25.0", "@html-eslint/eslint-plugin": "^0.25.0",
"@html-eslint/parser": "^0.25.0", "@html-eslint/parser": "^0.25.0",
"@stylistic/eslint-plugin": "^2.3.0", "@stylistic/eslint-plugin": "^2.3.0",
@ -26,7 +26,7 @@
"@types/eslint__js": "^8.42.3", "@types/eslint__js": "^8.42.3",
"@types/express": "^4.17.21", "@types/express": "^4.17.21",
"@types/node-fetch": "^2.6.11", "@types/node-fetch": "^2.6.11",
"eslint": "^8.57.0", "eslint": "^8.57.1",
"eslint-plugin-html": "^8.1.1", "eslint-plugin-html": "^8.1.1",
"eslint-plugin-sonarjs": "^1.0.4", "eslint-plugin-sonarjs": "^1.0.4",
"eslint-plugin-unicorn": "^55.0.0", "eslint-plugin-unicorn": "^55.0.0",
@ -34,7 +34,7 @@
"gulp-copy": "^5.0.0", "gulp-copy": "^5.0.0",
"gulp-typescript": "^6.0.0-alpha.1", "gulp-typescript": "^6.0.0-alpha.1",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"typescript": "^5.5.4", "typescript": "^5.6.2",
"typescript-eslint": "^7.17.0" "typescript-eslint": "^7.18.0"
} }
} }

View file

@ -13,21 +13,21 @@ const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
interface Instance { interface Instance {
name: string; name: string;
[key: string]: any; [key: string]: any;
} }
const app = express(); const app = express();
import instances from "./webpage/instances.json" with { type: "json" }; import instances from "./webpage/instances.json" with { type: "json" };
const instanceNames = new Map<string, Instance>(); const instanceNames = new Map<string, Instance>();
for (const instance of instances) { for (const instance of instances) {
instanceNames.set(instance.name, instance); instanceNames.set(instance.name, instance);
} }
app.use(compression()); app.use(compression());
async function updateInstances(): Promise<void> { async function updateInstances(): Promise<void> {
try { try {
const response = await fetch( const response = await fetch(
"https://raw.githubusercontent.com/spacebarchat/spacebarchat/master/instances/instances.json" "https://raw.githubusercontent.com/spacebarchat/spacebarchat/master/instances/instances.json"
@ -51,11 +51,11 @@ async function updateInstances(): Promise<void> {
} catch (error) { } catch (error) {
console.error("Error updating instances:", error); console.error("Error updating instances:", error);
} }
} }
updateInstances(); updateInstances();
app.use("/getupdates", (_req: Request, res: Response) => { app.use("/getupdates", (_req: Request, res: Response) => {
try { try {
const stats = fs.statSync(path.join(__dirname, "webpage")); const stats = fs.statSync(path.join(__dirname, "webpage"));
res.send(stats.mtimeMs.toString()); res.send(stats.mtimeMs.toString());
@ -63,18 +63,18 @@ app.use("/getupdates", (_req: Request, res: Response) => {
console.error("Error getting updates:", error); console.error("Error getting updates:", error);
res.status(500).send("Error getting updates"); res.status(500).send("Error getting updates");
} }
}); });
app.use("/services/oembed", (req: Request, res: Response) => { app.use("/services/oembed", (req: Request, res: Response) => {
inviteResponse(req, res); inviteResponse(req, res);
}); });
app.use("/uptime", (req: Request, res: Response) => { app.use("/uptime", (req: Request, res: Response) => {
const instanceUptime = uptime[req.query.name as string]; const instanceUptime = uptime[req.query.name as string];
res.send(instanceUptime); res.send(instanceUptime);
}); });
app.use("/", async (req: Request, res: Response) => { app.use("/", async (req: Request, res: Response) => {
const scheme = req.secure ? "https" : "http"; const scheme = req.secure ? "https" : "http";
const host = `${scheme}://${req.get("Host")}`; const host = `${scheme}://${req.get("Host")}`;
const ref = host + req.originalUrl; const ref = host + req.originalUrl;
@ -110,11 +110,11 @@ app.use("/", async (req: Request, res: Response) => {
} else { } else {
res.sendFile(path.join(__dirname, "webpage", "index.html")); res.sendFile(path.join(__dirname, "webpage", "index.html"));
} }
}); });
const PORT = process.env.PORT || Number(process.argv[2]) || 8080; const PORT = process.env.PORT || Number(process.argv[2]) || 8080;
app.listen(PORT, () => { app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`); console.log(`Server running on port ${PORT}`);
}); });
export { getApiUrls }; export { getApiUrls };

View file

@ -8,59 +8,59 @@ const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
interface UptimeEntry { interface UptimeEntry {
time: number; time: number;
online: boolean; online: boolean;
} }
interface UptimeObject { interface UptimeObject {
[key: string]: UptimeEntry[]; [key: string]: UptimeEntry[];
} }
interface Instance { interface Instance {
name: string; name: string;
urls?: { api: string }; urls?: { api: string };
url?: string; url?: string;
online?: boolean; online?: boolean;
uptime?: { uptime?: {
daytime: number; daytime: number;
weektime: number; weektime: number;
alltime: number; alltime: number;
}; };
} }
let uptimeObject: UptimeObject = loadUptimeObject(); let uptimeObject: UptimeObject = loadUptimeObject();
export { uptimeObject as uptime }; export { uptimeObject as uptime };
function loadUptimeObject(): UptimeObject { function loadUptimeObject(): UptimeObject {
const filePath = path.join(__dirname, "..", "uptime.json"); const filePath = path.join(__dirname, "..", "uptime.json");
if (fs.existsSync(filePath)) { if (fs.existsSync(filePath)) {
try { try {
return JSON.parse(fs.readFileSync(filePath, "utf8")); return JSON.parse(fs.readFileSync(filePath, "utf8"));
} catch (error) { } catch (error) {
console.error("Error reading uptime.json:", error); console.error("Error reading uptime.json:", error);
return {}; return {};
} }
} }
return {}; return {};
} }
function saveUptimeObject(): void { function saveUptimeObject(): void {
fs.writeFile( fs.writeFile(
`${__dirname}/uptime.json`, `${__dirname}/uptime.json`,
JSON.stringify(uptimeObject), JSON.stringify(uptimeObject),
(error) => { (error) => {
if (error) { if (error) {
console.error("Error saving uptime.json:", error); console.error("Error saving uptime.json:", error);
} }
} }
); );
} }
function removeUndefinedKey(): void { function removeUndefinedKey(): void {
if (uptimeObject.undefined) { if (uptimeObject.undefined) {
delete uptimeObject.undefined; delete uptimeObject.undefined;
saveUptimeObject(); saveUptimeObject();
} }
} }
removeUndefinedKey(); removeUndefinedKey();
@ -72,12 +72,12 @@ export async function observe(instances: Instance[]): Promise<void> {
); );
await Promise.allSettled(instancePromises); await Promise.allSettled(instancePromises);
updateInactiveInstances(activeInstances); updateInactiveInstances(activeInstances);
} }
async function resolveInstance( async function resolveInstance(
instance: Instance, instance: Instance,
activeInstances: Set<string> activeInstances: Set<string>
): Promise<void> { ): Promise<void> {
try { try {
calcStats(instance); calcStats(instance);
const api = await getApiUrl(instance); const api = await getApiUrl(instance);
@ -90,9 +90,9 @@ async function resolveInstance(
} catch (error) { } catch (error) {
console.error("Error resolving instance:", error); console.error("Error resolving instance:", error);
} }
} }
async function getApiUrl(instance: Instance): Promise<string | null> { async function getApiUrl(instance: Instance): Promise<string | null> {
if (instance.urls) { if (instance.urls) {
return instance.urls.api; return instance.urls.api;
} }
@ -101,28 +101,28 @@ async function getApiUrl(instance: Instance): Promise<string | null> {
return urls ? urls.api : null; return urls ? urls.api : null;
} }
return null; return null;
} }
function handleUnresolvedApi(instance: Instance): void { function handleUnresolvedApi(instance: Instance): void {
setStatus(instance, false); setStatus(instance, false);
console.warn(`${instance.name} does not resolve api URL`, instance); console.warn(`${instance.name} does not resolve api URL`, instance);
setTimeout(() => resolveInstance(instance, new Set()), 1000 * 60 * 30); setTimeout(() => resolveInstance(instance, new Set()), 1000 * 60 * 30);
} }
function scheduleHealthCheck(instance: Instance, api: string): void { function scheduleHealthCheck(instance: Instance, api: string): void {
const checkInterval = 1000 * 60 * 30; const checkInterval = 1000 * 60 * 30;
const initialDelay = Math.random() * 1000 * 60 * 10; const initialDelay = Math.random() * 1000 * 60 * 10;
setTimeout(() => { setTimeout(() => {
checkHealth(instance, api); checkHealth(instance, api);
setInterval(() => checkHealth(instance, api), checkInterval); setInterval(() => checkHealth(instance, api), checkInterval);
}, initialDelay); }, initialDelay);
} }
async function checkHealth( async function checkHealth(
instance: Instance, instance: Instance,
api: string, api: string,
tries = 0 tries = 0
): Promise<void> { ): Promise<void> {
try { try {
const response = await fetch(`${api}ping`, { method: "HEAD" }); const response = await fetch(`${api}ping`, { method: "HEAD" });
if (response.ok || tries > 3) { if (response.ok || tries > 3) {
@ -138,25 +138,25 @@ async function checkHealth(
retryHealthCheck(instance, api, tries); retryHealthCheck(instance, api, tries);
} }
} }
} }
function retryHealthCheck( function retryHealthCheck(
instance: Instance, instance: Instance,
api: string, api: string,
tries: number tries: number
): void { ): void {
setTimeout(() => checkHealth(instance, api, tries + 1), 30000); setTimeout(() => checkHealth(instance, api, tries + 1), 30000);
} }
function updateInactiveInstances(activeInstances: Set<string>): void { function updateInactiveInstances(activeInstances: Set<string>): void {
for (const key of Object.keys(uptimeObject)) { for (const key of Object.keys(uptimeObject)) {
if (!activeInstances.has(key)) { if (!activeInstances.has(key)) {
setStatus(key, false); setStatus(key, false);
} }
} }
} }
function calcStats(instance: Instance): void { function calcStats(instance: Instance): void {
const obj = uptimeObject[instance.name]; const obj = uptimeObject[instance.name];
if (!obj) return; if (!obj) return;
@ -199,15 +199,15 @@ function calcStats(instance: Instance): void {
weektime, weektime,
online online
); );
} }
function calculateUptimeStats( function calculateUptimeStats(
totalTimePassed: number, totalTimePassed: number,
alltime: number, alltime: number,
daytime: number, daytime: number,
weektime: number, weektime: number,
online: boolean online: boolean
): { daytime: number; weektime: number; alltime: number } { ): { daytime: number; weektime: number; alltime: number } {
const dayInMs = 1000 * 60 * 60 * 24; const dayInMs = 1000 * 60 * 60 * 24;
const weekInMs = dayInMs * 7; const weekInMs = dayInMs * 7;
@ -229,9 +229,9 @@ function calculateUptimeStats(
} }
return { daytime, weektime, alltime }; return { daytime, weektime, alltime };
} }
function setStatus(instance: string | Instance, status: boolean): void { function setStatus(instance: string | Instance, status: boolean): void {
const name = typeof instance === "string" ? instance : instance.name; const name = typeof instance === "string" ? instance : instance.name;
let obj = uptimeObject[name]; let obj = uptimeObject[name];
@ -248,4 +248,4 @@ function setStatus(instance: string | Instance, status: boolean): void {
if (typeof instance !== "string") { if (typeof instance !== "string") {
calcStats(instance); calcStats(instance);
} }
} }

View file

@ -2,22 +2,22 @@ import fetch from "node-fetch";
import { Request, Response } from "express"; import { Request, Response } from "express";
interface ApiUrls { interface ApiUrls {
api: string; api: string;
gateway: string; gateway: string;
cdn: string; cdn: string;
wellknown: string; wellknown: string;
} }
interface Invite { interface Invite {
guild: { guild: {
name: string; name: string;
description?: string; description?: string;
icon?: string; icon?: string;
id: string; id: string;
}; };
inviter?: { inviter?: {
username: string; username: string;
}; };
} }
export async function getApiUrls(url: string): Promise<ApiUrls | null> { export async function getApiUrls(url: string): Promise<ApiUrls | null> {
@ -45,12 +45,12 @@ export async function getApiUrls(url: string): Promise<ApiUrls | null> {
console.error("Error fetching API URLs:", error); console.error("Error fetching API URLs:", error);
return null; return null;
} }
} }
export async function inviteResponse( export async function inviteResponse(
req: Request, req: Request,
res: Response res: Response
): Promise<void> { ): Promise<void> {
let url: URL; let url: URL;
if (URL.canParse(req.query.url as string)) { if (URL.canParse(req.query.url as string)) {
url = new URL(req.query.url as string); url = new URL(req.query.url as string);
@ -111,4 +111,4 @@ export async function inviteResponse(
}; };
res.json(jsonResponse); res.json(jsonResponse);
} }
} }

View file

@ -1,164 +1,164 @@
import { getBulkInfo } from "./login.js"; import { getBulkInfo } from "./login.js";
class Voice { class Voice {
audioCtx: AudioContext; audioCtx: AudioContext;
info: { wave: string | Function; freq: number }; info: { wave: string | Function; freq: number };
playing: boolean; playing: boolean;
myArrayBuffer: AudioBuffer; myArrayBuffer: AudioBuffer;
gainNode: GainNode; gainNode: GainNode;
buffer: Float32Array; buffer: Float32Array;
source: AudioBufferSourceNode; source: AudioBufferSourceNode;
constructor(wave: string | Function, freq: number, volume = 1) { constructor(wave: string | Function, freq: number, volume = 1) {
this.audioCtx = new window.AudioContext(); this.audioCtx = new window.AudioContext();
this.info = { wave, freq }; this.info = { wave, freq };
this.playing = false; this.playing = false;
this.myArrayBuffer = this.audioCtx.createBuffer( this.myArrayBuffer = this.audioCtx.createBuffer(
1, 1,
this.audioCtx.sampleRate, this.audioCtx.sampleRate,
this.audioCtx.sampleRate this.audioCtx.sampleRate
); );
this.gainNode = this.audioCtx.createGain(); this.gainNode = this.audioCtx.createGain();
this.gainNode.gain.value = volume; this.gainNode.gain.value = volume;
this.gainNode.connect(this.audioCtx.destination); this.gainNode.connect(this.audioCtx.destination);
this.buffer = this.myArrayBuffer.getChannelData(0); this.buffer = this.myArrayBuffer.getChannelData(0);
this.source = this.audioCtx.createBufferSource(); this.source = this.audioCtx.createBufferSource();
this.source.buffer = this.myArrayBuffer; this.source.buffer = this.myArrayBuffer;
this.source.loop = true; this.source.loop = true;
this.source.start(); this.source.start();
this.updateWave(); this.updateWave();
} }
get wave(): string | Function { get wave(): string | Function {
return this.info.wave; return this.info.wave;
} }
get freq(): number { get freq(): number {
return this.info.freq; return this.info.freq;
} }
set wave(wave: string | Function) { set wave(wave: string | Function) {
this.info.wave = wave; this.info.wave = wave;
this.updateWave(); this.updateWave();
} }
set freq(freq: number) { set freq(freq: number) {
this.info.freq = freq; this.info.freq = freq;
this.updateWave(); this.updateWave();
} }
updateWave(): void { updateWave(): void {
const func = this.waveFunction(); const func = this.waveFunction();
for (let i = 0; i < this.buffer.length; i++) { for (let i = 0; i < this.buffer.length; i++) {
this.buffer[i] = func(i / this.audioCtx.sampleRate, this.freq); this.buffer[i] = func(i / this.audioCtx.sampleRate, this.freq);
} }
} }
waveFunction(): Function { waveFunction(): Function {
if (typeof this.wave === "function") { if (typeof this.wave === "function") {
return this.wave; return this.wave;
} }
switch (this.wave) { switch (this.wave) {
case "sin": case "sin":
return (t: number, freq: number) => { return (t: number, freq: number) => {
return Math.sin(t * Math.PI * 2 * freq); return Math.sin(t * Math.PI * 2 * freq);
}; };
case "triangle": case "triangle":
return (t: number, freq: number) => { return (t: number, freq: number) => {
return Math.abs(((4 * t * freq) % 4) - 2) - 1; return Math.abs(((4 * t * freq) % 4) - 2) - 1;
}; };
case "sawtooth": case "sawtooth":
return (t: number, freq: number) => { return (t: number, freq: number) => {
return ((t * freq) % 1) * 2 - 1; return ((t * freq) % 1) * 2 - 1;
}; };
case "square": case "square":
return (t: number, freq: number) => { return (t: number, freq: number) => {
return (t * freq) % 2 < 1 ? 1 : -1; return (t * freq) % 2 < 1 ? 1 : -1;
}; };
case "white": case "white":
return (_t: number, _freq: number) => { return (_t: number, _freq: number) => {
return Math.random() * 2 - 1; return Math.random() * 2 - 1;
}; };
case "noise": case "noise":
return (_t: number, _freq: number) => { return (_t: number, _freq: number) => {
return 0; return 0;
}; };
} }
return new Function(); return new Function();
} }
play(): void { play(): void {
if (this.playing) { if (this.playing) {
return; return;
} }
this.source.connect(this.gainNode); this.source.connect(this.gainNode);
this.playing = true; this.playing = true;
} }
stop(): void { stop(): void {
if (this.playing) { if (this.playing) {
this.source.disconnect(); this.source.disconnect();
this.playing = false; this.playing = false;
} }
} }
static noises(noise: string): void { static noises(noise: string): void {
switch (noise) { switch (noise) {
case "three": { case "three": {
const voicy = new Voice("sin", 800); const voicy = new Voice("sin", 800);
voicy.play(); voicy.play();
setTimeout((_) => { setTimeout((_) => {
voicy.freq = 1000; voicy.freq = 1000;
}, 50); }, 50);
setTimeout((_) => { setTimeout((_) => {
voicy.freq = 1300; voicy.freq = 1300;
}, 100); }, 100);
setTimeout((_) => { setTimeout((_) => {
voicy.stop(); voicy.stop();
}, 150); }, 150);
break; break;
} }
case "zip": { case "zip": {
const voicy = new Voice((t: number, freq: number) => { const voicy = new Voice((t: number, freq: number) => {
return Math.sin((t + 2) ** Math.cos(t * 4) * Math.PI * 2 * freq); return Math.sin((t + 2) ** Math.cos(t * 4) * Math.PI * 2 * freq);
}, 700); }, 700);
voicy.play(); voicy.play();
setTimeout((_) => { setTimeout((_) => {
voicy.stop(); voicy.stop();
}, 150); }, 150);
break; break;
} }
case "square": { case "square": {
const voicy = new Voice("square", 600, 0.4); const voicy = new Voice("square", 600, 0.4);
voicy.play(); voicy.play();
setTimeout((_) => { setTimeout((_) => {
voicy.freq = 800; voicy.freq = 800;
}, 50); }, 50);
setTimeout((_) => { setTimeout((_) => {
voicy.freq = 1000; voicy.freq = 1000;
}, 100); }, 100);
setTimeout((_) => { setTimeout((_) => {
voicy.stop(); voicy.stop();
}, 150); }, 150);
break; break;
} }
case "beep": { case "beep": {
const voicy = new Voice("sin", 800); const voicy = new Voice("sin", 800);
voicy.play(); voicy.play();
setTimeout((_) => { setTimeout((_) => {
voicy.stop(); voicy.stop();
}, 50); }, 50);
setTimeout((_) => { setTimeout((_) => {
voicy.play(); voicy.play();
}, 100); }, 100);
setTimeout((_) => { setTimeout((_) => {
voicy.stop(); voicy.stop();
}, 150); }, 150);
break; break;
} }
} }
} }
static get sounds() { static get sounds() {
return ["three", "zip", "square", "beep"]; return ["three", "zip", "square", "beep"];
} }
static setNotificationSound(sound: string) { static setNotificationSound(sound: string) {
const userinfos = getBulkInfo(); const userinfos = getBulkInfo();
userinfos.preferences.notisound = sound; userinfos.preferences.notisound = sound;
localStorage.setItem("userinfos", JSON.stringify(userinfos)); localStorage.setItem("userinfos", JSON.stringify(userinfos));
} }
static getNotificationSound() { static getNotificationSound() {
const userinfos = getBulkInfo(); const userinfos = getBulkInfo();
return userinfos.preferences.notisound; return userinfos.preferences.notisound;
} }
} }
export { Voice }; export { Voice };

View file

@ -11,32 +11,32 @@ import { Role, RoleList } from "./role.js";
import { InfiniteScroller } from "./infiniteScroller.js"; import { InfiniteScroller } from "./infiniteScroller.js";
import { SnowFlake } from "./snowflake.js"; import { SnowFlake } from "./snowflake.js";
import { import {
channeljson, channeljson,
embedjson, embedjson,
messageCreateJson, messageCreateJson,
messagejson, messagejson,
readyjson, readyjson,
startTypingjson, startTypingjson,
} from "./jsontypes.js"; } from "./jsontypes.js";
import { MarkDown } from "./markdown.js"; import { MarkDown } from "./markdown.js";
import { Member } from "./member.js"; import { Member } from "./member.js";
declare global { declare global {
interface NotificationOptions { interface NotificationOptions {
image?: string | null | undefined; image?: string | null | undefined;
} }
} }
class Channel extends SnowFlake { class Channel extends SnowFlake {
editing!: Message | null; editing!: Message | null;
type!: number; type!: number;
owner!: Guild; owner!: Guild;
headers!: Localuser["headers"]; headers!: Localuser["headers"];
name!: string; name!: string;
parent_id?: string; parent_id?: string;
parent: Channel | undefined; parent: Channel | undefined;
children!: Channel[]; children!: Channel[];
guild_id!: string; guild_id!: string;
permission_overwrites!: Map<string, Permissions>; permission_overwrites!: Map<string, Permissions>;
permission_overwritesar!: [Role, Permissions][]; permission_overwritesar!: [Role, Permissions][];
topic!: string; topic!: string;
nsfw!: boolean; nsfw!: boolean;
@ -1410,6 +1410,6 @@ class Channel extends SnowFlake {
); );
} }
} }
} }
Channel.setupcontextmenu(); Channel.setupcontextmenu();
export { Channel }; export { Channel };

View file

@ -102,6 +102,6 @@ class Contextmenu<x, y> {
obj.style.top = docheight - box.height + "px"; obj.style.top = docheight - box.height + "px";
} }
} }
} }
Contextmenu.setup(); Contextmenu.setup();
export { Contextmenu }; export { Contextmenu };

View file

@ -1,273 +1,273 @@
type dialogjson = type dialogjson =
| ["hdiv", ...dialogjson[]] | ["hdiv", ...dialogjson[]]
| ["vdiv", ...dialogjson[]] | ["vdiv", ...dialogjson[]]
| ["img", string, [number, number] | undefined | ["fit"]] | ["img", string, [number, number] | undefined | ["fit"]]
| ["checkbox", string, boolean, (this: HTMLInputElement, e: Event) => unknown] | ["checkbox", string, boolean, (this: HTMLInputElement, e: Event) => unknown]
| ["button", string, string, (this: HTMLButtonElement, e: Event) => unknown] | ["button", string, string, (this: HTMLButtonElement, e: Event) => unknown]
| ["mdbox", string, string, (this: HTMLTextAreaElement, e: Event) => unknown] | ["mdbox", string, string, (this: HTMLTextAreaElement, e: Event) => unknown]
| ["textbox", string, string, (this: HTMLInputElement, e: Event) => unknown] | ["textbox", string, string, (this: HTMLInputElement, e: Event) => unknown]
| ["fileupload", string, (this: HTMLInputElement, e: Event) => unknown] | ["fileupload", string, (this: HTMLInputElement, e: Event) => unknown]
| ["text", string] | ["text", string]
| ["title", string] | ["title", string]
| ["radio", string, string[], (this: unknown, e: string) => unknown, number] | ["radio", string, string[], (this: unknown, e: string) => unknown, number]
| ["html", HTMLElement] | ["html", HTMLElement]
| [ | [
"select", "select",
string, string,
string[], string[],
(this: HTMLSelectElement, e: Event) => unknown, (this: HTMLSelectElement, e: Event) => unknown,
number number
] ]
| ["tabs", [string, dialogjson][]]; | ["tabs", [string, dialogjson][]];
class Dialog { class Dialog {
layout: dialogjson; layout: dialogjson;
onclose: Function; onclose: Function;
onopen: Function; onopen: Function;
html: HTMLDivElement; html: HTMLDivElement;
background!: HTMLDivElement; background!: HTMLDivElement;
constructor( constructor(
layout: dialogjson, layout: dialogjson,
onclose = (_: any) => {}, onclose = (_: any) => {},
onopen = (_: any) => {} onopen = (_: any) => {}
) { ) {
this.layout = layout; this.layout = layout;
this.onclose = onclose; this.onclose = onclose;
this.onopen = onopen; this.onopen = onopen;
const div = document.createElement("div"); const div = document.createElement("div");
div.appendChild(this.tohtml(layout)); div.appendChild(this.tohtml(layout));
this.html = div; this.html = div;
this.html.classList.add("centeritem"); this.html.classList.add("centeritem");
if (!(layout[0] === "img")) { if (!(layout[0] === "img")) {
this.html.classList.add("nonimagecenter"); this.html.classList.add("nonimagecenter");
} }
} }
tohtml(array: dialogjson): HTMLElement { tohtml(array: dialogjson): HTMLElement {
switch (array[0]) { switch (array[0]) {
case "img": case "img":
const img = document.createElement("img"); const img = document.createElement("img");
img.src = array[1]; img.src = array[1];
if (array[2] != undefined) { if (array[2] != undefined) {
if (array[2].length === 2) { if (array[2].length === 2) {
img.width = array[2][0]; img.width = array[2][0];
img.height = array[2][1]; img.height = array[2][1];
} else if (array[2][0] === "fit") { } else if (array[2][0] === "fit") {
img.classList.add("imgfit"); img.classList.add("imgfit");
} }
} }
return img; return img;
case "hdiv": case "hdiv":
const hdiv = document.createElement("div"); const hdiv = document.createElement("div");
hdiv.classList.add("flexltr"); hdiv.classList.add("flexltr");
for (const thing of array) { for (const thing of array) {
if (thing === "hdiv") { if (thing === "hdiv") {
continue; continue;
} }
hdiv.appendChild(this.tohtml(thing)); hdiv.appendChild(this.tohtml(thing));
} }
return hdiv; return hdiv;
case "vdiv": case "vdiv":
const vdiv = document.createElement("div"); const vdiv = document.createElement("div");
vdiv.classList.add("flexttb"); vdiv.classList.add("flexttb");
for (const thing of array) { for (const thing of array) {
if (thing === "vdiv") { if (thing === "vdiv") {
continue; continue;
} }
vdiv.appendChild(this.tohtml(thing)); vdiv.appendChild(this.tohtml(thing));
} }
return vdiv; return vdiv;
case "checkbox": { case "checkbox": {
const div = document.createElement("div"); const div = document.createElement("div");
const checkbox = document.createElement("input"); const checkbox = document.createElement("input");
div.appendChild(checkbox); div.appendChild(checkbox);
const label = document.createElement("span"); const label = document.createElement("span");
checkbox.checked = array[2]; checkbox.checked = array[2];
label.textContent = array[1]; label.textContent = array[1];
div.appendChild(label); div.appendChild(label);
checkbox.addEventListener("change", array[3]); checkbox.addEventListener("change", array[3]);
checkbox.type = "checkbox"; checkbox.type = "checkbox";
return div; return div;
} }
case "button": { case "button": {
const div = document.createElement("div"); const div = document.createElement("div");
const input = document.createElement("button"); const input = document.createElement("button");
const label = document.createElement("span"); const label = document.createElement("span");
input.textContent = array[2]; input.textContent = array[2];
label.textContent = array[1]; label.textContent = array[1];
div.appendChild(label); div.appendChild(label);
div.appendChild(input); div.appendChild(input);
input.addEventListener("click", array[3]); input.addEventListener("click", array[3]);
return div; return div;
} }
case "mdbox": { case "mdbox": {
const div = document.createElement("div"); const div = document.createElement("div");
const input = document.createElement("textarea"); const input = document.createElement("textarea");
input.value = array[2]; input.value = array[2];
const label = document.createElement("span"); const label = document.createElement("span");
label.textContent = array[1]; label.textContent = array[1];
input.addEventListener("input", array[3]); input.addEventListener("input", array[3]);
div.appendChild(label); div.appendChild(label);
div.appendChild(document.createElement("br")); div.appendChild(document.createElement("br"));
div.appendChild(input); div.appendChild(input);
return div; return div;
} }
case "textbox": { case "textbox": {
const div = document.createElement("div"); const div = document.createElement("div");
const input = document.createElement("input"); const input = document.createElement("input");
input.value = array[2]; input.value = array[2];
input.type = "text"; input.type = "text";
const label = document.createElement("span"); const label = document.createElement("span");
label.textContent = array[1]; label.textContent = array[1];
console.log(array[3]); console.log(array[3]);
input.addEventListener("input", array[3]); input.addEventListener("input", array[3]);
div.appendChild(label); div.appendChild(label);
div.appendChild(input); div.appendChild(input);
return div; return div;
} }
case "fileupload": { case "fileupload": {
const div = document.createElement("div"); const div = document.createElement("div");
const input = document.createElement("input"); const input = document.createElement("input");
input.type = "file"; input.type = "file";
const label = document.createElement("span"); const label = document.createElement("span");
label.textContent = array[1]; label.textContent = array[1];
div.appendChild(label); div.appendChild(label);
div.appendChild(input); div.appendChild(input);
input.addEventListener("change", array[2]); input.addEventListener("change", array[2]);
console.log(array); console.log(array);
return div; return div;
} }
case "text": { case "text": {
const span = document.createElement("span"); const span = document.createElement("span");
span.textContent = array[1]; span.textContent = array[1];
return span; return span;
} }
case "title": { case "title": {
const span = document.createElement("span"); const span = document.createElement("span");
span.classList.add("title"); span.classList.add("title");
span.textContent = array[1]; span.textContent = array[1];
return span; return span;
} }
case "radio": { case "radio": {
const div = document.createElement("div"); const div = document.createElement("div");
const fieldset = document.createElement("fieldset"); const fieldset = document.createElement("fieldset");
fieldset.addEventListener("change", () => { fieldset.addEventListener("change", () => {
let i = -1; let i = -1;
for (const thing of Array.from(fieldset.children)) { for (const thing of Array.from(fieldset.children)) {
i++; i++;
if (i === 0) { if (i === 0) {
continue; continue;
} }
const checkbox = thing.children[0].children[0] as HTMLInputElement; const checkbox = thing.children[0].children[0] as HTMLInputElement;
if (checkbox.checked) { if (checkbox.checked) {
array[3](checkbox.value); array[3](checkbox.value);
} }
} }
}); });
const legend = document.createElement("legend"); const legend = document.createElement("legend");
legend.textContent = array[1]; legend.textContent = array[1];
fieldset.appendChild(legend); fieldset.appendChild(legend);
let i = 0; let i = 0;
for (const thing of array[2]) { for (const thing of array[2]) {
const div = document.createElement("div"); const div = document.createElement("div");
const input = document.createElement("input"); const input = document.createElement("input");
input.classList.add("radio"); input.classList.add("radio");
input.type = "radio"; input.type = "radio";
input.name = array[1]; input.name = array[1];
input.value = thing; input.value = thing;
if (i === array[4]) { if (i === array[4]) {
input.checked = true; input.checked = true;
} }
const label = document.createElement("label"); const label = document.createElement("label");
label.appendChild(input); label.appendChild(input);
const span = document.createElement("span"); const span = document.createElement("span");
span.textContent = thing; span.textContent = thing;
label.appendChild(span); label.appendChild(span);
div.appendChild(label); div.appendChild(label);
fieldset.appendChild(div); fieldset.appendChild(div);
i++; i++;
} }
div.appendChild(fieldset); div.appendChild(fieldset);
return div; return div;
} }
case "html": case "html":
return array[1]; return array[1];
case "select": { case "select": {
const div = document.createElement("div"); const div = document.createElement("div");
const label = document.createElement("label"); const label = document.createElement("label");
const select = document.createElement("select"); const select = document.createElement("select");
label.textContent = array[1]; label.textContent = array[1];
div.append(label); div.append(label);
div.appendChild(select); div.appendChild(select);
for (const thing of array[2]) { for (const thing of array[2]) {
const option = document.createElement("option"); const option = document.createElement("option");
option.textContent = thing; option.textContent = thing;
select.appendChild(option); select.appendChild(option);
} }
select.selectedIndex = array[4]; select.selectedIndex = array[4];
select.addEventListener("change", array[3]); select.addEventListener("change", array[3]);
return div; return div;
} }
case "tabs": { case "tabs": {
const table = document.createElement("div"); const table = document.createElement("div");
table.classList.add("flexttb"); table.classList.add("flexttb");
const tabs = document.createElement("div"); const tabs = document.createElement("div");
tabs.classList.add("flexltr"); tabs.classList.add("flexltr");
tabs.classList.add("tabbed-head"); tabs.classList.add("tabbed-head");
table.appendChild(tabs); table.appendChild(tabs);
const content = document.createElement("div"); const content = document.createElement("div");
content.classList.add("tabbed-content"); content.classList.add("tabbed-content");
table.appendChild(content); table.appendChild(content);
let shown: HTMLElement | undefined; let shown: HTMLElement | undefined;
for (const thing of array[1]) { for (const thing of array[1]) {
const button = document.createElement("button"); const button = document.createElement("button");
button.textContent = thing[0]; button.textContent = thing[0];
tabs.appendChild(button); tabs.appendChild(button);
const html = this.tohtml(thing[1]); const html = this.tohtml(thing[1]);
content.append(html); content.append(html);
if (!shown) { if (!shown) {
shown = html; shown = html;
} else { } else {
html.style.display = "none"; html.style.display = "none";
} }
button.addEventListener("click", (_) => { button.addEventListener("click", (_) => {
if (shown) { if (shown) {
shown.style.display = "none"; shown.style.display = "none";
} }
html.style.display = ""; html.style.display = "";
shown = html; shown = html;
}); });
} }
return table; return table;
} }
default: default:
console.error( console.error(
"can't find element:" + array[0], "can't find element:" + array[0],
" full element:", " full element:",
array array
); );
return document.createElement("span"); return document.createElement("span");
} }
} }
show() { show() {
this.onopen(); this.onopen();
console.log("fullscreen"); console.log("fullscreen");
this.background = document.createElement("div"); this.background = document.createElement("div");
this.background.classList.add("background"); this.background.classList.add("background");
document.body.appendChild(this.background); document.body.appendChild(this.background);
document.body.appendChild(this.html); document.body.appendChild(this.html);
this.background.onclick = (_) => { this.background.onclick = (_) => {
this.hide(); this.hide();
}; };
} }
hide() { hide() {
document.body.removeChild(this.background); document.body.removeChild(this.background);
document.body.removeChild(this.html); document.body.removeChild(this.html);
} }
} }
export { Dialog }; export { Dialog };

View file

@ -4,75 +4,75 @@ import { Message } from "./message.js";
import { Localuser } from "./localuser.js"; import { Localuser } from "./localuser.js";
import { User } from "./user.js"; import { User } from "./user.js";
import { import {
channeljson, channeljson,
dirrectjson, dirrectjson,
memberjson, memberjson,
messagejson, messagejson,
} from "./jsontypes.js"; } from "./jsontypes.js";
import { Permissions } from "./permissions.js"; import { Permissions } from "./permissions.js";
import { SnowFlake } from "./snowflake.js"; import { SnowFlake } from "./snowflake.js";
import { Contextmenu } from "./contextmenu.js"; import { Contextmenu } from "./contextmenu.js";
class Direct extends Guild { class Direct extends Guild {
declare channelids: { [key: string]: Group }; declare channelids: { [key: string]: Group };
getUnixTime(): number { getUnixTime(): number {
throw new Error("Do not call this for Direct, it does not make sense"); throw new Error("Do not call this for Direct, it does not make sense");
} }
constructor(json: dirrectjson[], owner: Localuser) { constructor(json: dirrectjson[], owner: Localuser) {
super(-1, owner, null); super(-1, owner, null);
this.message_notifications = 0; this.message_notifications = 0;
this.owner = owner; this.owner = owner;
if (!this.localuser) { if (!this.localuser) {
console.error("Owner was not included, please fix"); console.error("Owner was not included, please fix");
} }
this.headers = this.localuser.headers; this.headers = this.localuser.headers;
this.channels = []; this.channels = [];
this.channelids = {}; this.channelids = {};
// @ts-ignore // @ts-ignore
this.properties = {}; this.properties = {};
this.roles = []; this.roles = [];
this.roleids = new Map(); this.roleids = new Map();
this.prevchannel = undefined; this.prevchannel = undefined;
this.properties.name = "Direct Messages"; this.properties.name = "Direct Messages";
for (const thing of json) { for (const thing of json) {
const temp = new Group(thing, this); const temp = new Group(thing, this);
this.channels.push(temp); this.channels.push(temp);
this.channelids[temp.id] = temp; this.channelids[temp.id] = temp;
} }
this.headchannels = this.channels; this.headchannels = this.channels;
} }
createChannelpac(json: any) { createChannelpac(json: any) {
const thischannel = new Group(json, this); const thischannel = new Group(json, this);
this.channelids[thischannel.id] = thischannel; this.channelids[thischannel.id] = thischannel;
this.channels.push(thischannel); this.channels.push(thischannel);
this.sortchannels(); this.sortchannels();
this.printServers(); this.printServers();
return thischannel; return thischannel;
} }
delChannel(json: channeljson) { delChannel(json: channeljson) {
const channel = this.channelids[json.id]; const channel = this.channelids[json.id];
super.delChannel(json); super.delChannel(json);
if (channel) { if (channel) {
channel.del(); channel.del();
} }
} }
giveMember(_member: memberjson) { giveMember(_member: memberjson) {
console.error("not a real guild, can't give member object"); console.error("not a real guild, can't give member object");
} }
getRole(/* ID: string */) { getRole(/* ID: string */) {
return null; return null;
} }
hasRole(/* r: string */) { hasRole(/* r: string */) {
return false; return false;
} }
isAdmin() { isAdmin() {
return false; return false;
} }
unreaddms() { unreaddms() {
for (const thing of this.channels) { for (const thing of this.channels) {
(thing as Group).unreads(); (thing as Group).unreads();
} }
} }
} }
const dmPermissions = new Permissions("0"); const dmPermissions = new Permissions("0");
@ -100,8 +100,8 @@ dmPermissions.setPermission("USE_VAD", 1);
// @ts-ignore // @ts-ignore
class Group extends Channel { class Group extends Channel {
user: User; user: User;
static contextmenu = new Contextmenu<Group, undefined>("channel menu"); static contextmenu = new Contextmenu<Group, undefined>("channel menu");
static setupcontextmenu() { static setupcontextmenu() {
this.contextmenu.addbutton("Copy DM id", function (this: Group) { this.contextmenu.addbutton("Copy DM id", function (this: Group) {
navigator.clipboard.writeText(this.id); navigator.clipboard.writeText(this.id);
@ -301,6 +301,6 @@ class Group extends Channel {
hasPermission(name: string): boolean { hasPermission(name: string): boolean {
return dmPermissions.hasPermission(name); return dmPermissions.hasPermission(name);
} }
} }
export { Direct, Group }; export { Direct, Group };
Group.setupcontextmenu(); Group.setupcontextmenu();

View file

@ -6,406 +6,406 @@ import { getapiurls, getInstances } from "./login.js";
import { Guild } from "./guild.js"; import { Guild } from "./guild.js";
class Embed { class Embed {
type: string; type: string;
owner: Message; owner: Message;
json: embedjson; json: embedjson;
constructor(json: embedjson, owner: Message) { constructor(json: embedjson, owner: Message) {
this.type = this.getType(json); this.type = this.getType(json);
this.owner = owner; this.owner = owner;
this.json = json; this.json = json;
} }
getType(json: embedjson) { getType(json: embedjson) {
const instances = getInstances(); const instances = getInstances();
if ( if (
instances && instances &&
json.type === "link" && json.type === "link" &&
json.url && json.url &&
URL.canParse(json.url) URL.canParse(json.url)
) { ) {
const Url = new URL(json.url); const Url = new URL(json.url);
for (const instance of instances) { for (const instance of instances) {
if (instance.url && URL.canParse(instance.url)) { if (instance.url && URL.canParse(instance.url)) {
const IUrl = new URL(instance.url); const IUrl = new URL(instance.url);
const params = new URLSearchParams(Url.search); const params = new URLSearchParams(Url.search);
let host: string; let host: string;
if (params.has("instance")) { if (params.has("instance")) {
const url = params.get("instance") as string; const url = params.get("instance") as string;
if (URL.canParse(url)) { if (URL.canParse(url)) {
host = new URL(url).host; host = new URL(url).host;
} else { } else {
host = Url.host; host = Url.host;
} }
} else { } else {
host = Url.host; host = Url.host;
} }
if (IUrl.host === host) { if (IUrl.host === host) {
const code = const code =
Url.pathname.split("/")[Url.pathname.split("/").length - 1]; Url.pathname.split("/")[Url.pathname.split("/").length - 1];
json.invite = { json.invite = {
url: instance.url, url: instance.url,
code, code,
}; };
return "invite"; return "invite";
} }
} }
} }
} }
return json.type || "rich"; return json.type || "rich";
} }
generateHTML() { generateHTML() {
switch (this.type) { switch (this.type) {
case "rich": case "rich":
return this.generateRich(); return this.generateRich();
case "image": case "image":
return this.generateImage(); return this.generateImage();
case "invite": case "invite":
return this.generateInvite(); return this.generateInvite();
case "link": case "link":
return this.generateLink(); return this.generateLink();
case "video": case "video":
case "article": case "article":
return this.generateArticle(); return this.generateArticle();
default: default:
console.warn( console.warn(
`unsupported embed type ${this.type}, please add support dev :3`, `unsupported embed type ${this.type}, please add support dev :3`,
this.json this.json
); );
return document.createElement("div"); //prevent errors by giving blank div return document.createElement("div"); //prevent errors by giving blank div
} }
} }
get message() { get message() {
return this.owner; return this.owner;
} }
get channel() { get channel() {
return this.message.channel; return this.message.channel;
} }
get guild() { get guild() {
return this.channel.guild; return this.channel.guild;
} }
get localuser() { get localuser() {
return this.guild.localuser; return this.guild.localuser;
} }
generateRich() { generateRich() {
const div = document.createElement("div"); const div = document.createElement("div");
if (this.json.color) { if (this.json.color) {
div.style.backgroundColor = "#" + this.json.color.toString(16); div.style.backgroundColor = "#" + this.json.color.toString(16);
} }
div.classList.add("embed-color"); div.classList.add("embed-color");
const embed = document.createElement("div"); const embed = document.createElement("div");
embed.classList.add("embed"); embed.classList.add("embed");
div.append(embed); div.append(embed);
if (this.json.author) { if (this.json.author) {
const authorline = document.createElement("div"); const authorline = document.createElement("div");
if (this.json.author.icon_url) { if (this.json.author.icon_url) {
const img = document.createElement("img"); const img = document.createElement("img");
img.classList.add("embedimg"); img.classList.add("embedimg");
img.src = this.json.author.icon_url; img.src = this.json.author.icon_url;
authorline.append(img); authorline.append(img);
} }
const a = document.createElement("a"); const a = document.createElement("a");
a.textContent = this.json.author.name as string; a.textContent = this.json.author.name as string;
if (this.json.author.url) { if (this.json.author.url) {
MarkDown.safeLink(a, this.json.author.url); MarkDown.safeLink(a, this.json.author.url);
} }
a.classList.add("username"); a.classList.add("username");
authorline.append(a); authorline.append(a);
embed.append(authorline); embed.append(authorline);
} }
if (this.json.title) { if (this.json.title) {
const title = document.createElement("a"); const title = document.createElement("a");
title.append(new MarkDown(this.json.title, this.channel).makeHTML()); title.append(new MarkDown(this.json.title, this.channel).makeHTML());
if (this.json.url) { if (this.json.url) {
MarkDown.safeLink(title, this.json.url); MarkDown.safeLink(title, this.json.url);
} }
title.classList.add("embedtitle"); title.classList.add("embedtitle");
embed.append(title); embed.append(title);
} }
if (this.json.description) { if (this.json.description) {
const p = document.createElement("p"); const p = document.createElement("p");
p.append(new MarkDown(this.json.description, this.channel).makeHTML()); p.append(new MarkDown(this.json.description, this.channel).makeHTML());
embed.append(p); embed.append(p);
} }
embed.append(document.createElement("br")); embed.append(document.createElement("br"));
if (this.json.fields) { if (this.json.fields) {
for (const thing of this.json.fields) { for (const thing of this.json.fields) {
const div = document.createElement("div"); const div = document.createElement("div");
const b = document.createElement("b"); const b = document.createElement("b");
b.textContent = thing.name; b.textContent = thing.name;
div.append(b); div.append(b);
const p = document.createElement("p"); const p = document.createElement("p");
p.append(new MarkDown(thing.value, this.channel).makeHTML()); p.append(new MarkDown(thing.value, this.channel).makeHTML());
p.classList.add("embedp"); p.classList.add("embedp");
div.append(p); div.append(p);
if (thing.inline) { if (thing.inline) {
div.classList.add("inline"); div.classList.add("inline");
} }
embed.append(div); embed.append(div);
} }
} }
if (this.json.footer || this.json.timestamp) { if (this.json.footer || this.json.timestamp) {
const footer = document.createElement("div"); const footer = document.createElement("div");
if (this.json?.footer?.icon_url) { if (this.json?.footer?.icon_url) {
const img = document.createElement("img"); const img = document.createElement("img");
img.src = this.json.footer.icon_url; img.src = this.json.footer.icon_url;
img.classList.add("embedicon"); img.classList.add("embedicon");
footer.append(img); footer.append(img);
} }
if (this.json?.footer?.text) { if (this.json?.footer?.text) {
const span = document.createElement("span"); const span = document.createElement("span");
span.textContent = this.json.footer.text; span.textContent = this.json.footer.text;
span.classList.add("spaceright"); span.classList.add("spaceright");
footer.append(span); footer.append(span);
} }
if (this.json?.footer && this.json?.timestamp) { if (this.json?.footer && this.json?.timestamp) {
const span = document.createElement("span"); const span = document.createElement("span");
span.textContent = "•"; span.textContent = "•";
span.classList.add("spaceright"); span.classList.add("spaceright");
footer.append(span); footer.append(span);
} }
if (this.json?.timestamp) { if (this.json?.timestamp) {
const span = document.createElement("span"); const span = document.createElement("span");
span.textContent = new Date(this.json.timestamp).toLocaleString(); span.textContent = new Date(this.json.timestamp).toLocaleString();
footer.append(span); footer.append(span);
} }
embed.append(footer); embed.append(footer);
} }
return div; return div;
} }
generateImage() { generateImage() {
const img = document.createElement("img"); const img = document.createElement("img");
img.classList.add("messageimg"); img.classList.add("messageimg");
img.onclick = function () { img.onclick = function () {
const full = new Dialog(["img", img.src, ["fit"]]); const full = new Dialog(["img", img.src, ["fit"]]);
full.show(); full.show();
}; };
img.src = this.json.thumbnail.proxy_url; img.src = this.json.thumbnail.proxy_url;
if (this.json.thumbnail.width) { if (this.json.thumbnail.width) {
let scale = 1; let scale = 1;
const max = 96 * 3; const max = 96 * 3;
scale = Math.max(scale, this.json.thumbnail.width / max); scale = Math.max(scale, this.json.thumbnail.width / max);
scale = Math.max(scale, this.json.thumbnail.height / max); scale = Math.max(scale, this.json.thumbnail.height / max);
this.json.thumbnail.width /= scale; this.json.thumbnail.width /= scale;
this.json.thumbnail.height /= scale; this.json.thumbnail.height /= scale;
} }
img.style.width = this.json.thumbnail.width + "px"; img.style.width = this.json.thumbnail.width + "px";
img.style.height = this.json.thumbnail.height + "px"; img.style.height = this.json.thumbnail.height + "px";
console.log(this.json, "Image fix"); console.log(this.json, "Image fix");
return img; return img;
} }
generateLink() { generateLink() {
const table = document.createElement("table"); const table = document.createElement("table");
table.classList.add("embed", "linkembed"); table.classList.add("embed", "linkembed");
const trtop = document.createElement("tr"); const trtop = document.createElement("tr");
table.append(trtop); table.append(trtop);
if (this.json.url && this.json.title) { if (this.json.url && this.json.title) {
const td = document.createElement("td"); const td = document.createElement("td");
const a = document.createElement("a"); const a = document.createElement("a");
MarkDown.safeLink(a, this.json.url); MarkDown.safeLink(a, this.json.url);
a.textContent = this.json.title; a.textContent = this.json.title;
td.append(a); td.append(a);
trtop.append(td); trtop.append(td);
} }
{ {
const td = document.createElement("td"); const td = document.createElement("td");
const img = document.createElement("img"); const img = document.createElement("img");
if (this.json.thumbnail) { if (this.json.thumbnail) {
img.classList.add("embedimg"); img.classList.add("embedimg");
img.onclick = function () { img.onclick = function () {
const full = new Dialog(["img", img.src, ["fit"]]); const full = new Dialog(["img", img.src, ["fit"]]);
full.show(); full.show();
}; };
img.src = this.json.thumbnail.proxy_url; img.src = this.json.thumbnail.proxy_url;
td.append(img); td.append(img);
} }
trtop.append(td); trtop.append(td);
} }
const bottomtr = document.createElement("tr"); const bottomtr = document.createElement("tr");
const td = document.createElement("td"); const td = document.createElement("td");
if (this.json.description) { if (this.json.description) {
const span = document.createElement("span"); const span = document.createElement("span");
span.textContent = this.json.description; span.textContent = this.json.description;
td.append(span); td.append(span);
} }
bottomtr.append(td); bottomtr.append(td);
table.append(bottomtr); table.append(bottomtr);
return table; return table;
} }
invcache: [invitejson, { cdn: string; api: string }] | undefined; invcache: [invitejson, { cdn: string; api: string }] | undefined;
generateInvite() { generateInvite() {
if (this.invcache && (!this.json.invite || !this.localuser)) { if (this.invcache && (!this.json.invite || !this.localuser)) {
return this.generateLink(); return this.generateLink();
} }
const div = document.createElement("div"); const div = document.createElement("div");
div.classList.add("embed", "inviteEmbed", "flexttb"); div.classList.add("embed", "inviteEmbed", "flexttb");
const json1 = this.json.invite; const json1 = this.json.invite;
(async () => { (async () => {
let json: invitejson; let json: invitejson;
let info: { cdn: string; api: string }; let info: { cdn: string; api: string };
if (!this.invcache) { if (!this.invcache) {
if (!json1) { if (!json1) {
div.append(this.generateLink()); div.append(this.generateLink());
return; return;
} }
const tempinfo = await getapiurls(json1.url); const tempinfo = await getapiurls(json1.url);
if (!tempinfo) { if (!tempinfo) {
div.append(this.generateLink()); div.append(this.generateLink());
return; return;
} }
info = tempinfo; info = tempinfo;
const res = await fetch(info.api + "/invites/" + json1.code); const res = await fetch(info.api + "/invites/" + json1.code);
if (!res.ok) { if (!res.ok) {
div.append(this.generateLink()); div.append(this.generateLink());
} }
json = (await res.json()) as invitejson; json = (await res.json()) as invitejson;
this.invcache = [json, info]; this.invcache = [json, info];
} else { } else {
[json, info] = this.invcache; [json, info] = this.invcache;
} }
if (!json) { if (!json) {
div.append(this.generateLink()); div.append(this.generateLink());
return; return;
} }
if (json.guild.banner) { if (json.guild.banner) {
const banner = document.createElement("img"); const banner = document.createElement("img");
banner.src = banner.src =
this.localuser.info.cdn + this.localuser.info.cdn +
"/icons/" + "/icons/" +
json.guild.id + json.guild.id +
"/" + "/" +
json.guild.banner + json.guild.banner +
".png?size=256"; ".png?size=256";
banner.classList.add("banner"); banner.classList.add("banner");
div.append(banner); div.append(banner);
} }
const guild: invitejson["guild"] & { info?: { cdn: string } } = const guild: invitejson["guild"] & { info?: { cdn: string } } =
json.guild; json.guild;
guild.info = info; guild.info = info;
const icon = Guild.generateGuildIcon( const icon = Guild.generateGuildIcon(
guild as invitejson["guild"] & { info: { cdn: string } } guild as invitejson["guild"] & { info: { cdn: string } }
); );
const iconrow = document.createElement("div"); const iconrow = document.createElement("div");
iconrow.classList.add("flexltr", "flexstart"); iconrow.classList.add("flexltr", "flexstart");
iconrow.append(icon); iconrow.append(icon);
{ {
const guildinfo = document.createElement("div"); const guildinfo = document.createElement("div");
guildinfo.classList.add("flexttb", "invguildinfo"); guildinfo.classList.add("flexttb", "invguildinfo");
const name = document.createElement("b"); const name = document.createElement("b");
name.textContent = guild.name; name.textContent = guild.name;
guildinfo.append(name); guildinfo.append(name);
const members = document.createElement("span"); const members = document.createElement("span");
members.innerText = members.innerText =
"#" + json.channel.name + " • Members: " + guild.member_count; "#" + json.channel.name + " • Members: " + guild.member_count;
guildinfo.append(members); guildinfo.append(members);
members.classList.add("subtext"); members.classList.add("subtext");
iconrow.append(guildinfo); iconrow.append(guildinfo);
} }
div.append(iconrow); div.append(iconrow);
const h2 = document.createElement("h2"); const h2 = document.createElement("h2");
h2.textContent = `You've been invited by ${json.inviter.username}`; h2.textContent = `You've been invited by ${json.inviter.username}`;
div.append(h2); div.append(h2);
const button = document.createElement("button"); const button = document.createElement("button");
button.textContent = "Accept"; button.textContent = "Accept";
if (this.localuser.info.api.startsWith(info.api)) { if (this.localuser.info.api.startsWith(info.api)) {
if (this.localuser.guildids.has(guild.id)) { if (this.localuser.guildids.has(guild.id)) {
button.textContent = "Already joined"; button.textContent = "Already joined";
button.disabled = true; button.disabled = true;
} }
} }
button.classList.add("acceptinvbutton"); button.classList.add("acceptinvbutton");
div.append(button); div.append(button);
button.onclick = (_) => { button.onclick = (_) => {
if (this.localuser.info.api.startsWith(info.api)) { if (this.localuser.info.api.startsWith(info.api)) {
fetch(this.localuser.info.api + "/invites/" + json.code, { fetch(this.localuser.info.api + "/invites/" + json.code, {
method: "POST", method: "POST",
headers: this.localuser.headers, headers: this.localuser.headers,
}) })
.then((r) => r.json()) .then((r) => r.json())
.then((_) => { .then((_) => {
if (_.message) { if (_.message) {
alert(_.message); alert(_.message);
} }
}); });
} else { } else {
if (this.json.invite) { if (this.json.invite) {
const params = new URLSearchParams(""); const params = new URLSearchParams("");
params.set("instance", this.json.invite.url); params.set("instance", this.json.invite.url);
const encoded = params.toString(); const encoded = params.toString();
const url = `${location.origin}/invite/${this.json.invite.code}?${encoded}`; const url = `${location.origin}/invite/${this.json.invite.code}?${encoded}`;
window.open(url, "_blank"); window.open(url, "_blank");
} }
} }
}; };
})(); })();
return div; return div;
} }
generateArticle() { generateArticle() {
const colordiv = document.createElement("div"); const colordiv = document.createElement("div");
colordiv.style.backgroundColor = "#000000"; colordiv.style.backgroundColor = "#000000";
colordiv.classList.add("embed-color"); colordiv.classList.add("embed-color");
const div = document.createElement("div"); const div = document.createElement("div");
div.classList.add("embed"); div.classList.add("embed");
if (this.json.provider) { if (this.json.provider) {
const provider = document.createElement("p"); const provider = document.createElement("p");
provider.classList.add("provider"); provider.classList.add("provider");
provider.textContent = this.json.provider.name; provider.textContent = this.json.provider.name;
div.append(provider); div.append(provider);
} }
const a = document.createElement("a"); const a = document.createElement("a");
if (this.json.url && this.json.url) { if (this.json.url && this.json.url) {
MarkDown.safeLink(a, this.json.url); MarkDown.safeLink(a, this.json.url);
a.textContent = this.json.url; a.textContent = this.json.url;
div.append(a); div.append(a);
} }
if (this.json.description) { if (this.json.description) {
const description = document.createElement("p"); const description = document.createElement("p");
description.textContent = this.json.description; description.textContent = this.json.description;
div.append(description); div.append(description);
} }
if (this.json.thumbnail) { if (this.json.thumbnail) {
const img = document.createElement("img"); const img = document.createElement("img");
if (this.json.thumbnail.width && this.json.thumbnail.width) { if (this.json.thumbnail.width && this.json.thumbnail.width) {
let scale = 1; let scale = 1;
const inch = 96; const inch = 96;
scale = Math.max(scale, this.json.thumbnail.width / inch / 4); scale = Math.max(scale, this.json.thumbnail.width / inch / 4);
scale = Math.max(scale, this.json.thumbnail.height / inch / 3); scale = Math.max(scale, this.json.thumbnail.height / inch / 3);
this.json.thumbnail.width /= scale; this.json.thumbnail.width /= scale;
this.json.thumbnail.height /= scale; this.json.thumbnail.height /= scale;
img.style.width = this.json.thumbnail.width + "px"; img.style.width = this.json.thumbnail.width + "px";
img.style.height = this.json.thumbnail.height + "px"; img.style.height = this.json.thumbnail.height + "px";
} }
img.classList.add("bigembedimg"); img.classList.add("bigembedimg");
if (this.json.video) { if (this.json.video) {
img.onclick = async () => { img.onclick = async () => {
if (this.json.video) { if (this.json.video) {
img.remove(); img.remove();
const iframe = document.createElement("iframe"); const iframe = document.createElement("iframe");
iframe.src = this.json.video.url + "?autoplay=1"; iframe.src = this.json.video.url + "?autoplay=1";
if (this.json.thumbnail.width && this.json.thumbnail.width) { if (this.json.thumbnail.width && this.json.thumbnail.width) {
iframe.style.width = this.json.thumbnail.width + "px"; iframe.style.width = this.json.thumbnail.width + "px";
iframe.style.height = this.json.thumbnail.height + "px"; iframe.style.height = this.json.thumbnail.height + "px";
} }
div.append(iframe); div.append(iframe);
} }
}; };
} else { } else {
img.onclick = async () => { img.onclick = async () => {
const full = new Dialog(["img", img.src, ["fit"]]); const full = new Dialog(["img", img.src, ["fit"]]);
full.show(); full.show();
}; };
} }
img.src = this.json.thumbnail.proxy_url || this.json.thumbnail.url; img.src = this.json.thumbnail.proxy_url || this.json.thumbnail.url;
div.append(img); div.append(img);
} }
colordiv.append(div); colordiv.append(div);
return colordiv; return colordiv;
} }
} }
export { Embed }; export { Embed };

View file

@ -3,133 +3,133 @@ import { Guild } from "./guild.js";
import { Localuser } from "./localuser.js"; import { Localuser } from "./localuser.js";
class Emoji { class Emoji {
static emojis: { static emojis: {
name: string; name: string;
emojis: { emojis: {
name: string; name: string;
emoji: string; emoji: string;
}[]; }[];
}[]; }[];
name: string; name: string;
id: string; id: string;
animated: boolean; animated: boolean;
owner: Guild | Localuser; owner: Guild | Localuser;
get guild() { get guild() {
if (this.owner instanceof Guild) { if (this.owner instanceof Guild) {
return this.owner; return this.owner;
} }
return; return;
} }
get localuser() { get localuser() {
if (this.owner instanceof Guild) { if (this.owner instanceof Guild) {
return this.owner.localuser; return this.owner.localuser;
} else { } else {
return this.owner; return this.owner;
} }
} }
get info() { get info() {
return this.owner.info; return this.owner.info;
} }
constructor( constructor(
json: { name: string; id: string; animated: boolean }, json: { name: string; id: string; animated: boolean },
owner: Guild | Localuser owner: Guild | Localuser
) { ) {
this.name = json.name; this.name = json.name;
this.id = json.id; this.id = json.id;
this.animated = json.animated; this.animated = json.animated;
this.owner = owner; this.owner = owner;
} }
getHTML(bigemoji: boolean = false) { getHTML(bigemoji: boolean = false) {
const emojiElem = document.createElement("img"); const emojiElem = document.createElement("img");
emojiElem.classList.add("md-emoji"); emojiElem.classList.add("md-emoji");
emojiElem.classList.add(bigemoji ? "bigemoji" : "smallemoji"); emojiElem.classList.add(bigemoji ? "bigemoji" : "smallemoji");
emojiElem.crossOrigin = "anonymous"; emojiElem.crossOrigin = "anonymous";
emojiElem.src = emojiElem.src =
this.info.cdn + this.info.cdn +
"/emojis/" + "/emojis/" +
this.id + this.id +
"." + "." +
(this.animated ? "gif" : "png") + (this.animated ? "gif" : "png") +
"?size=32"; "?size=32";
emojiElem.alt = this.name; emojiElem.alt = this.name;
emojiElem.loading = "lazy"; emojiElem.loading = "lazy";
return emojiElem; return emojiElem;
} }
static decodeEmojiList(buffer: ArrayBuffer) { static decodeEmojiList(buffer: ArrayBuffer) {
const view = new DataView(buffer, 0); const view = new DataView(buffer, 0);
let i = 0; let i = 0;
function read16() { function read16() {
const int = view.getUint16(i); const int = view.getUint16(i);
i += 2; i += 2;
return int; return int;
} }
function read8() { function read8() {
const int = view.getUint8(i); const int = view.getUint8(i);
i += 1; i += 1;
return int; return int;
} }
function readString8() { function readString8() {
return readStringNo(read8()); return readStringNo(read8());
} }
function readString16() { function readString16() {
return readStringNo(read16()); return readStringNo(read16());
} }
function readStringNo(length: number) { function readStringNo(length: number) {
const array = new Uint8Array(length); const array = new Uint8Array(length);
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
array[i] = read8(); array[i] = read8();
} }
//console.log(array); //console.log(array);
return new TextDecoder("utf-8").decode(array.buffer); return new TextDecoder("utf-8").decode(array.buffer);
} }
const build: { name: string; emojis: { name: string; emoji: string }[] }[] = const build: { name: string; emojis: { name: string; emoji: string }[] }[] =
[]; [];
let cats = read16(); let cats = read16();
for (; cats !== 0; cats--) { for (; cats !== 0; cats--) {
const name = readString16(); const name = readString16();
const emojis: { const emojis: {
name: string; name: string;
skin_tone_support: boolean; skin_tone_support: boolean;
emoji: string; emoji: string;
}[] = []; }[] = [];
let emojinumber = read16(); let emojinumber = read16();
for (; emojinumber !== 0; emojinumber--) { for (; emojinumber !== 0; emojinumber--) {
//console.log(emojis); //console.log(emojis);
const name = readString8(); const name = readString8();
const len = read8(); const len = read8();
const skin_tone_support = len > 127; const skin_tone_support = len > 127;
const emoji = readStringNo(len - Number(skin_tone_support) * 128); const emoji = readStringNo(len - Number(skin_tone_support) * 128);
emojis.push({ emojis.push({
name, name,
skin_tone_support, skin_tone_support,
emoji, emoji,
}); });
} }
build.push({ build.push({
name, name,
emojis, emojis,
}); });
} }
this.emojis = build; this.emojis = build;
console.log(build); console.log(build);
} }
static grabEmoji() { static grabEmoji() {
fetch("/emoji.bin") fetch("/emoji.bin")
.then((e) => { .then((e) => {
return e.arrayBuffer(); return e.arrayBuffer();
}) })
.then((e) => { .then((e) => {
Emoji.decodeEmojiList(e); Emoji.decodeEmojiList(e);
}); });
} }
static async emojiPicker( static async emojiPicker(
x: number, x: number,
y: number, y: number,
localuser: Localuser localuser: Localuser
): Promise<Emoji | string> { ): Promise<Emoji | string> {
let res: (r: Emoji | string) => void; let res: (r: Emoji | string) => void;
const promise: Promise<Emoji | string> = new Promise((r) => { const promise: Promise<Emoji | string> = new Promise((r) => {
res = r; res = r;
@ -254,6 +254,6 @@ class Emoji {
menu.append(body); menu.append(body);
return promise; return promise;
} }
} }
Emoji.grabEmoji(); Emoji.grabEmoji();
export { Emoji }; export { Emoji };

View file

@ -3,150 +3,150 @@ import { Dialog } from "./dialog.js";
import { filejson } from "./jsontypes.js"; import { filejson } from "./jsontypes.js";
class File { class File {
owner: Message | null; owner: Message | null;
id: string; id: string;
filename: string; filename: string;
content_type: string; content_type: string;
width: number | undefined; width: number | undefined;
height: number | undefined; height: number | undefined;
proxy_url: string | undefined; proxy_url: string | undefined;
url: string; url: string;
size: number; size: number;
constructor(fileJSON: filejson, owner: Message | null) { constructor(fileJSON: filejson, owner: Message | null) {
this.owner = owner; this.owner = owner;
this.id = fileJSON.id; this.id = fileJSON.id;
this.filename = fileJSON.filename; this.filename = fileJSON.filename;
this.content_type = fileJSON.content_type; this.content_type = fileJSON.content_type;
this.width = fileJSON.width; this.width = fileJSON.width;
this.height = fileJSON.height; this.height = fileJSON.height;
this.url = fileJSON.url; this.url = fileJSON.url;
this.proxy_url = fileJSON.proxy_url; this.proxy_url = fileJSON.proxy_url;
this.content_type = fileJSON.content_type; this.content_type = fileJSON.content_type;
this.size = fileJSON.size; this.size = fileJSON.size;
} }
getHTML(temp: boolean = false): HTMLElement { getHTML(temp: boolean = false): HTMLElement {
const src = this.proxy_url || this.url; const src = this.proxy_url || this.url;
if (this.width && this.height) { if (this.width && this.height) {
let scale = 1; let scale = 1;
const max = 96 * 3; const max = 96 * 3;
scale = Math.max(scale, this.width / max); scale = Math.max(scale, this.width / max);
scale = Math.max(scale, this.height / max); scale = Math.max(scale, this.height / max);
this.width /= scale; this.width /= scale;
this.height /= scale; this.height /= scale;
} }
if (this.content_type.startsWith("image/")) { if (this.content_type.startsWith("image/")) {
const div = document.createElement("div"); const div = document.createElement("div");
const img = document.createElement("img"); const img = document.createElement("img");
img.classList.add("messageimg"); img.classList.add("messageimg");
div.classList.add("messageimgdiv"); div.classList.add("messageimgdiv");
img.onclick = function () { img.onclick = function () {
const full = new Dialog(["img", img.src, ["fit"]]); const full = new Dialog(["img", img.src, ["fit"]]);
full.show(); full.show();
}; };
img.src = src; img.src = src;
div.append(img); div.append(img);
if (this.width) { if (this.width) {
div.style.width = this.width + "px"; div.style.width = this.width + "px";
div.style.height = this.height + "px"; div.style.height = this.height + "px";
} }
console.log(img); console.log(img);
console.log(this.width, this.height); console.log(this.width, this.height);
return div; return div;
} else if (this.content_type.startsWith("video/")) { } else if (this.content_type.startsWith("video/")) {
const video = document.createElement("video"); const video = document.createElement("video");
const source = document.createElement("source"); const source = document.createElement("source");
source.src = src; source.src = src;
video.append(source); video.append(source);
source.type = this.content_type; source.type = this.content_type;
video.controls = !temp; video.controls = !temp;
if (this.width && this.height) { if (this.width && this.height) {
video.width = this.width; video.width = this.width;
video.height = this.height; video.height = this.height;
} }
return video; return video;
} else if (this.content_type.startsWith("audio/")) { } else if (this.content_type.startsWith("audio/")) {
const audio = document.createElement("audio"); const audio = document.createElement("audio");
const source = document.createElement("source"); const source = document.createElement("source");
source.src = src; source.src = src;
audio.append(source); audio.append(source);
source.type = this.content_type; source.type = this.content_type;
audio.controls = !temp; audio.controls = !temp;
return audio; return audio;
} else { } else {
return this.createunknown(); return this.createunknown();
} }
} }
upHTML(files: Blob[], file: globalThis.File): HTMLElement { upHTML(files: Blob[], file: globalThis.File): HTMLElement {
const div = document.createElement("div"); const div = document.createElement("div");
const contained = this.getHTML(true); const contained = this.getHTML(true);
div.classList.add("containedFile"); div.classList.add("containedFile");
div.append(contained); div.append(contained);
const controls = document.createElement("div"); const controls = document.createElement("div");
const garbage = document.createElement("button"); const garbage = document.createElement("button");
garbage.textContent = "🗑"; garbage.textContent = "🗑";
garbage.onclick = (_) => { garbage.onclick = (_) => {
div.remove(); div.remove();
files.splice(files.indexOf(file), 1); files.splice(files.indexOf(file), 1);
}; };
controls.classList.add("controls"); controls.classList.add("controls");
div.append(controls); div.append(controls);
controls.append(garbage); controls.append(garbage);
return div; return div;
} }
static initFromBlob(file: globalThis.File) { static initFromBlob(file: globalThis.File) {
return new File( return new File(
{ {
filename: file.name, filename: file.name,
size: file.size, size: file.size,
id: "null", id: "null",
content_type: file.type, content_type: file.type,
width: undefined, width: undefined,
height: undefined, height: undefined,
url: URL.createObjectURL(file), url: URL.createObjectURL(file),
proxy_url: undefined, proxy_url: undefined,
}, },
null null
); );
} }
createunknown(): HTMLElement { createunknown(): HTMLElement {
console.log("🗎"); console.log("🗎");
const src = this.proxy_url || this.url; const src = this.proxy_url || this.url;
const div = document.createElement("table"); const div = document.createElement("table");
div.classList.add("unknownfile"); div.classList.add("unknownfile");
const nametr = document.createElement("tr"); const nametr = document.createElement("tr");
div.append(nametr); div.append(nametr);
const fileicon = document.createElement("td"); const fileicon = document.createElement("td");
nametr.append(fileicon); nametr.append(fileicon);
fileicon.append("🗎"); fileicon.append("🗎");
fileicon.classList.add("fileicon"); fileicon.classList.add("fileicon");
fileicon.rowSpan = 2; fileicon.rowSpan = 2;
const nametd = document.createElement("td"); const nametd = document.createElement("td");
if (src) { if (src) {
const a = document.createElement("a"); const a = document.createElement("a");
a.href = src; a.href = src;
a.textContent = this.filename; a.textContent = this.filename;
nametd.append(a); nametd.append(a);
} else { } else {
nametd.textContent = this.filename; nametd.textContent = this.filename;
} }
nametd.classList.add("filename"); nametd.classList.add("filename");
nametr.append(nametd); nametr.append(nametd);
const sizetr = document.createElement("tr"); const sizetr = document.createElement("tr");
const size = document.createElement("td"); const size = document.createElement("td");
sizetr.append(size); sizetr.append(size);
size.textContent = "Size:" + File.filesizehuman(this.size); size.textContent = "Size:" + File.filesizehuman(this.size);
size.classList.add("filesize"); size.classList.add("filesize");
div.appendChild(sizetr); div.appendChild(sizetr);
return div; return div;
} }
static filesizehuman(fsize: number) { static filesizehuman(fsize: number) {
const i = fsize == 0 ? 0 : Math.floor(Math.log(fsize) / Math.log(1024)); const i = fsize == 0 ? 0 : Math.floor(Math.log(fsize) / Math.log(1024));
return ( return (
Number((fsize / Math.pow(1024, i)).toFixed(2)) * 1 + Number((fsize / Math.pow(1024, i)).toFixed(2)) * 1 +
" " + " " +
["Bytes", "Kilobytes", "Megabytes", "Gigabytes", "Terabytes"][i] ["Bytes", "Kilobytes", "Megabytes", "Gigabytes", "Terabytes"][i]
); );
} }
} }
export { File }; export { File };

View file

@ -8,22 +8,22 @@ import { Settings } from "./settings.js";
import { Permissions } from "./permissions.js"; import { Permissions } from "./permissions.js";
import { SnowFlake } from "./snowflake.js"; import { SnowFlake } from "./snowflake.js";
import { import {
channeljson, channeljson,
guildjson, guildjson,
emojijson, emojijson,
memberjson, memberjson,
invitejson, invitejson,
} from "./jsontypes.js"; } from "./jsontypes.js";
import { User } from "./user.js"; import { User } from "./user.js";
class Guild extends SnowFlake { class Guild extends SnowFlake {
owner!: Localuser; owner!: Localuser;
headers!: Localuser["headers"]; headers!: Localuser["headers"];
channels!: Channel[]; channels!: Channel[];
properties!: guildjson["properties"]; properties!: guildjson["properties"];
member_count!: number; member_count!: number;
roles!: Role[]; roles!: Role[];
roleids!: Map<string, Role>; roleids!: Map<string, Role>;
prevchannel: Channel | undefined; prevchannel: Channel | undefined;
banner!: string; banner!: string;
message_notifications!: number; message_notifications!: number;
@ -719,6 +719,6 @@ class Guild extends SnowFlake {
}), }),
}); });
} }
} }
Guild.setupcontextmenu(); Guild.setupcontextmenu();
export { Guild }; export { Guild };

View file

@ -3,87 +3,87 @@ console.log(mobile);
const serverbox = document.getElementById("instancebox") as HTMLDivElement; const serverbox = document.getElementById("instancebox") as HTMLDivElement;
fetch("/instances.json") fetch("/instances.json")
.then((_) => _.json()) .then((_) => _.json())
.then( .then(
( (
json: { json: {
name: string; name: string;
description?: string; description?: string;
descriptionLong?: string; descriptionLong?: string;
image?: string; image?: string;
url?: string; url?: string;
display?: boolean; display?: boolean;
online?: boolean; online?: boolean;
uptime: { alltime: number; daytime: number; weektime: number }; uptime: { alltime: number; daytime: number; weektime: number };
urls: { urls: {
wellknown: string; wellknown: string;
api: string; api: string;
cdn: string; cdn: string;
gateway: string; gateway: string;
login?: string; login?: string;
}; };
}[] }[]
) => { ) => {
console.warn(json); console.warn(json);
for (const instance of json) { for (const instance of json) {
if (instance.display === false) { if (instance.display === false) {
continue; continue;
} }
const div = document.createElement("div"); const div = document.createElement("div");
div.classList.add("flexltr", "instance"); div.classList.add("flexltr", "instance");
if (instance.image) { if (instance.image) {
const img = document.createElement("img"); const img = document.createElement("img");
img.src = instance.image; img.src = instance.image;
div.append(img); div.append(img);
} }
const statbox = document.createElement("div"); const statbox = document.createElement("div");
statbox.classList.add("flexttb"); statbox.classList.add("flexttb");
{ {
const textbox = document.createElement("div"); const textbox = document.createElement("div");
textbox.classList.add("flexttb", "instatancetextbox"); textbox.classList.add("flexttb", "instatancetextbox");
const title = document.createElement("h2"); const title = document.createElement("h2");
title.innerText = instance.name; title.innerText = instance.name;
if (instance.online !== undefined) { if (instance.online !== undefined) {
const status = document.createElement("span"); const status = document.createElement("span");
status.innerText = instance.online ? "Online" : "Offline"; status.innerText = instance.online ? "Online" : "Offline";
status.classList.add("instanceStatus"); status.classList.add("instanceStatus");
title.append(status); title.append(status);
} }
textbox.append(title); textbox.append(title);
if (instance.description || instance.descriptionLong) { if (instance.description || instance.descriptionLong) {
const p = document.createElement("p"); const p = document.createElement("p");
if (instance.descriptionLong) { if (instance.descriptionLong) {
p.innerText = instance.descriptionLong; p.innerText = instance.descriptionLong;
} else if (instance.description) { } else if (instance.description) {
p.innerText = instance.description; p.innerText = instance.description;
} }
textbox.append(p); textbox.append(p);
} }
statbox.append(textbox); statbox.append(textbox);
} }
if (instance.uptime) { if (instance.uptime) {
const stats = document.createElement("div"); const stats = document.createElement("div");
stats.classList.add("flexltr"); stats.classList.add("flexltr");
const span = document.createElement("span"); const span = document.createElement("span");
span.innerText = `Uptime: All time: ${Math.round( span.innerText = `Uptime: All time: ${Math.round(
instance.uptime.alltime * 100 instance.uptime.alltime * 100
)}% This week: ${Math.round( )}% This week: ${Math.round(
instance.uptime.weektime * 100 instance.uptime.weektime * 100
)}% Today: ${Math.round(instance.uptime.daytime * 100)}%`; )}% Today: ${Math.round(instance.uptime.daytime * 100)}%`;
stats.append(span); stats.append(span);
statbox.append(stats); statbox.append(stats);
} }
div.append(statbox); div.append(statbox);
div.onclick = (_) => { div.onclick = (_) => {
if (instance.online) { if (instance.online) {
window.location.href = window.location.href =
"/register.html?instance=" + encodeURI(instance.name); "/register.html?instance=" + encodeURI(instance.name);
} else { } else {
alert("Instance is offline, can't connect"); alert("Instance is offline, can't connect");
} }
}; };
serverbox.append(div); serverbox.append(div);
} }
} }
); );

View file

@ -6,7 +6,7 @@ import { Message } from "./message.js";
import { File } from "./file.js"; import { File } from "./file.js";
(async () => { (async () => {
async function waitForLoad(): Promise<void> { async function waitForLoad(): Promise<void> {
return new Promise((resolve) => { return new Promise((resolve) => {
document.addEventListener("DOMContentLoaded", (_) => resolve()); document.addEventListener("DOMContentLoaded", (_) => resolve());
}); });
@ -256,4 +256,4 @@ import { File } from "./file.js";
document.getElementById("servers")!.classList.remove("collapse"); document.getElementById("servers")!.classList.remove("collapse");
}; };
} }
})(); })();

View file

@ -1,8 +1,8 @@
class InfiniteScroller { class InfiniteScroller {
readonly getIDFromOffset: ( readonly getIDFromOffset: (
ID: string, ID: string,
offset: number offset: number
) => Promise<string | undefined>; ) => Promise<string | undefined>;
readonly getHTMLFromID: (ID: string) => Promise<HTMLElement>; readonly getHTMLFromID: (ID: string) => Promise<HTMLElement>;
readonly destroyFromID: (ID: string) => Promise<boolean>; readonly destroyFromID: (ID: string) => Promise<boolean>;
readonly reachesBottom: () => void; readonly reachesBottom: () => void;
@ -318,6 +318,6 @@ class InfiniteScroller {
clearTimeout(this.timeout); clearTimeout(this.timeout);
} }
} }
} }
export { InfiniteScroller }; export { InfiniteScroller };

View file

@ -1,147 +1,147 @@
import { getBulkUsers, Specialuser, getapiurls } from "./login.js"; import { getBulkUsers, Specialuser, getapiurls } from "./login.js";
(async () => { (async () => {
const users = getBulkUsers(); const users = getBulkUsers();
const well = new URLSearchParams(window.location.search).get("instance"); const well = new URLSearchParams(window.location.search).get("instance");
const joinable: Specialuser[] = []; const joinable: Specialuser[] = [];
for (const key in users.users) { for (const key in users.users) {
if (Object.prototype.hasOwnProperty.call(users.users, key)) { if (Object.prototype.hasOwnProperty.call(users.users, key)) {
const user: Specialuser = users.users[key]; const user: Specialuser = users.users[key];
if (well && user.serverurls.wellknown.includes(well)) { if (well && user.serverurls.wellknown.includes(well)) {
joinable.push(user); joinable.push(user);
} }
console.log(user); console.log(user);
} }
} }
let urls: { api: string; cdn: string } | undefined; let urls: { api: string; cdn: string } | undefined;
if (!joinable.length && well) { if (!joinable.length && well) {
const out = await getapiurls(well); const out = await getapiurls(well);
if (out) { if (out) {
urls = out; urls = out;
for (const key in users.users) { for (const key in users.users) {
if (Object.prototype.hasOwnProperty.call(users.users, key)) { if (Object.prototype.hasOwnProperty.call(users.users, key)) {
const user: Specialuser = users.users[key]; const user: Specialuser = users.users[key];
if (user.serverurls.api.includes(out.api)) { if (user.serverurls.api.includes(out.api)) {
joinable.push(user); joinable.push(user);
} }
console.log(user); console.log(user);
} }
} }
} else { } else {
throw new Error( throw new Error(
"Someone needs to handle the case where the servers don't exist" "Someone needs to handle the case where the servers don't exist"
); );
} }
} else { } else {
urls = joinable[0].serverurls; urls = joinable[0].serverurls;
} }
if (!joinable.length) { if (!joinable.length) {
document.getElementById("AcceptInvite")!.textContent = document.getElementById("AcceptInvite")!.textContent =
"Create an account to accept the invite"; "Create an account to accept the invite";
} }
const code = window.location.pathname.split("/")[2]; const code = window.location.pathname.split("/")[2];
let guildinfo: any; let guildinfo: any;
fetch(`${urls!.api}/invites/${code}`, { fetch(`${urls!.api}/invites/${code}`, {
method: "GET", method: "GET",
}) })
.then((response) => response.json()) .then((response) => response.json())
.then((json) => { .then((json) => {
const guildjson = json.guild; const guildjson = json.guild;
guildinfo = guildjson; guildinfo = guildjson;
document.getElementById("invitename")!.textContent = guildjson.name; document.getElementById("invitename")!.textContent = guildjson.name;
document.getElementById( document.getElementById(
"invitedescription" "invitedescription"
)!.textContent = `${json.inviter.username} invited you to join ${guildjson.name}`; )!.textContent = `${json.inviter.username} invited you to join ${guildjson.name}`;
if (guildjson.icon) { if (guildjson.icon) {
const img = document.createElement("img"); const img = document.createElement("img");
img.src = `${urls!.cdn}/icons/${guildjson.id}/${guildjson.icon}.png`; img.src = `${urls!.cdn}/icons/${guildjson.id}/${guildjson.icon}.png`;
img.classList.add("inviteGuild"); img.classList.add("inviteGuild");
document.getElementById("inviteimg")!.append(img); document.getElementById("inviteimg")!.append(img);
} else { } else {
const txt = guildjson.name const txt = guildjson.name
.replace(/'s /g, " ") .replace(/'s /g, " ")
.replace(/\w+/g, (word: any[]) => word[0]) .replace(/\w+/g, (word: any[]) => word[0])
.replace(/\s/g, ""); .replace(/\s/g, "");
const div = document.createElement("div"); const div = document.createElement("div");
div.textContent = txt; div.textContent = txt;
div.classList.add("inviteGuild"); div.classList.add("inviteGuild");
document.getElementById("inviteimg")!.append(div); document.getElementById("inviteimg")!.append(div);
} }
}); });
function showAccounts(): void { function showAccounts(): void {
const table = document.createElement("dialog"); const table = document.createElement("dialog");
for (const user of joinable) { for (const user of joinable) {
console.log(user.pfpsrc); console.log(user.pfpsrc);
const userinfo = document.createElement("div"); const userinfo = document.createElement("div");
userinfo.classList.add("flexltr", "switchtable"); userinfo.classList.add("flexltr", "switchtable");
const pfp = document.createElement("img"); const pfp = document.createElement("img");
pfp.src = user.pfpsrc; pfp.src = user.pfpsrc;
pfp.classList.add("pfp"); pfp.classList.add("pfp");
userinfo.append(pfp); userinfo.append(pfp);
const userDiv = document.createElement("div"); const userDiv = document.createElement("div");
userDiv.classList.add("userinfo"); userDiv.classList.add("userinfo");
userDiv.textContent = user.username; userDiv.textContent = user.username;
userDiv.append(document.createElement("br")); userDiv.append(document.createElement("br"));
const span = document.createElement("span"); const span = document.createElement("span");
span.textContent = user.serverurls.wellknown span.textContent = user.serverurls.wellknown
.replace("https://", "") .replace("https://", "")
.replace("http://", ""); .replace("http://", "");
span.classList.add("serverURL"); span.classList.add("serverURL");
userDiv.append(span); userDiv.append(span);
userinfo.append(userDiv); userinfo.append(userDiv);
table.append(userinfo); table.append(userinfo);
userinfo.addEventListener("click", () => { userinfo.addEventListener("click", () => {
console.log(user); console.log(user);
fetch(`${urls!.api}/invites/${code}`, { fetch(`${urls!.api}/invites/${code}`, {
method: "POST", method: "POST",
headers: { headers: {
Authorization: user.token, Authorization: user.token,
}, },
}).then(() => { }).then(() => {
users.currentuser = user.uid; users.currentuser = user.uid;
localStorage.setItem("userinfos", JSON.stringify(users)); localStorage.setItem("userinfos", JSON.stringify(users));
window.location.href = "/channels/" + guildinfo.id; window.location.href = "/channels/" + guildinfo.id;
}); });
}); });
} }
const td = document.createElement("div"); const td = document.createElement("div");
td.classList.add("switchtable"); td.classList.add("switchtable");
td.textContent = "Login or create an account ⇌"; td.textContent = "Login or create an account ⇌";
td.addEventListener("click", () => { td.addEventListener("click", () => {
const l = new URLSearchParams("?"); const l = new URLSearchParams("?");
l.set("goback", window.location.href); l.set("goback", window.location.href);
l.set("instance", well!); l.set("instance", well!);
window.location.href = "/login?" + l.toString(); window.location.href = "/login?" + l.toString();
}); });
if (!joinable.length) { if (!joinable.length) {
const l = new URLSearchParams("?"); const l = new URLSearchParams("?");
l.set("goback", window.location.href); l.set("goback", window.location.href);
l.set("instance", well!); l.set("instance", well!);
window.location.href = "/login?" + l.toString(); window.location.href = "/login?" + l.toString();
} }
table.append(td); table.append(td);
table.classList.add("accountSwitcher"); table.classList.add("accountSwitcher");
console.log(table); console.log(table);
document.body.append(table); document.body.append(table);
} }
document document
.getElementById("AcceptInvite")! .getElementById("AcceptInvite")!
.addEventListener("click", showAccounts); .addEventListener("click", showAccounts);
})(); })();

View file

@ -1,501 +1,501 @@
type readyjson = { type readyjson = {
op: 0; op: 0;
t: "READY"; t: "READY";
s: number; s: number;
d: { d: {
v: number; v: number;
user: mainuserjson; user: mainuserjson;
user_settings: { user_settings: {
index: number; index: number;
afk_timeout: number; afk_timeout: number;
allow_accessibility_detection: boolean; allow_accessibility_detection: boolean;
animate_emoji: boolean; animate_emoji: boolean;
animate_stickers: number; animate_stickers: number;
contact_sync_enabled: boolean; contact_sync_enabled: boolean;
convert_emoticons: boolean; convert_emoticons: boolean;
custom_status: string; custom_status: string;
default_guilds_restricted: boolean; default_guilds_restricted: boolean;
detect_platform_accounts: boolean; detect_platform_accounts: boolean;
developer_mode: boolean; developer_mode: boolean;
disable_games_tab: boolean; disable_games_tab: boolean;
enable_tts_command: boolean; enable_tts_command: boolean;
explicit_content_filter: 0; explicit_content_filter: 0;
friend_discovery_flags: 0; friend_discovery_flags: 0;
friend_source_flags: { friend_source_flags: {
all: boolean; all: boolean;
}; //might be missing things here }; //might be missing things here
gateway_connected: boolean; gateway_connected: boolean;
gif_auto_play: boolean; gif_auto_play: boolean;
guild_folders: []; //need an example of this not empty guild_folders: []; //need an example of this not empty
guild_positions: []; //need an example of this not empty guild_positions: []; //need an example of this not empty
inline_attachment_media: boolean; inline_attachment_media: boolean;
inline_embed_media: boolean; inline_embed_media: boolean;
locale: string; locale: string;
message_display_compact: boolean; message_display_compact: boolean;
native_phone_integration_enabled: boolean; native_phone_integration_enabled: boolean;
render_embeds: boolean; render_embeds: boolean;
render_reactions: boolean; render_reactions: boolean;
restricted_guilds: []; //need an example of this not empty restricted_guilds: []; //need an example of this not empty
show_current_game: boolean; show_current_game: boolean;
status: string; status: string;
stream_notifications_enabled: boolean; stream_notifications_enabled: boolean;
theme: string; theme: string;
timezone_offset: number; timezone_offset: number;
view_nsfw_guilds: boolean; view_nsfw_guilds: boolean;
}; };
guilds: guildjson[]; guilds: guildjson[];
relationships: { relationships: {
id: string; id: string;
type: 0 | 1 | 2 | 3 | 4; type: 0 | 1 | 2 | 3 | 4;
nickname: string | null; nickname: string | null;
user: userjson; user: userjson;
}[]; }[];
read_state: { read_state: {
entries: { entries: {
id: string; id: string;
channel_id: string; channel_id: string;
last_message_id: string; last_message_id: string;
last_pin_timestamp: string; last_pin_timestamp: string;
mention_count: number; //in theory, the server doesn't actually send this as far as I'm aware mention_count: number; //in theory, the server doesn't actually send this as far as I'm aware
}[]; }[];
partial: boolean; partial: boolean;
version: number; version: number;
}; };
user_guild_settings: { user_guild_settings: {
entries: { entries: {
channel_overrides: unknown[]; //will have to find example channel_overrides: unknown[]; //will have to find example
message_notifications: number; message_notifications: number;
flags: number; flags: number;
hide_muted_channels: boolean; hide_muted_channels: boolean;
mobile_push: boolean; mobile_push: boolean;
mute_config: null; mute_config: null;
mute_scheduled_events: boolean; mute_scheduled_events: boolean;
muted: boolean; muted: boolean;
notify_highlights: number; notify_highlights: number;
suppress_everyone: boolean; suppress_everyone: boolean;
suppress_roles: boolean; suppress_roles: boolean;
version: number; version: number;
guild_id: string; guild_id: string;
}[]; }[];
partial: boolean; partial: boolean;
version: number; version: number;
}; };
private_channels: dirrectjson[]; private_channels: dirrectjson[];
session_id: string; session_id: string;
country_code: string; country_code: string;
users: userjson[]; users: userjson[];
merged_members: [memberjson][]; merged_members: [memberjson][];
sessions: { sessions: {
active: boolean; active: boolean;
activities: []; //will need to find example of this activities: []; //will need to find example of this
client_info: { client_info: {
version: number; version: number;
}; };
session_id: string; session_id: string;
status: string; status: string;
}[]; }[];
resume_gateway_url: string; resume_gateway_url: string;
consents: { consents: {
personalization: { personalization: {
consented: boolean; consented: boolean;
}; };
}; };
experiments: []; //not sure if I need to do this :P experiments: []; //not sure if I need to do this :P
guild_join_requests: []; //need to get examples guild_join_requests: []; //need to get examples
connected_accounts: []; //need to get examples connected_accounts: []; //need to get examples
guild_experiments: []; //need to get examples guild_experiments: []; //need to get examples
geo_ordered_rtc_regions: []; //need to get examples geo_ordered_rtc_regions: []; //need to get examples
api_code_version: number; api_code_version: number;
friend_suggestion_count: number; friend_suggestion_count: number;
analytics_token: string; analytics_token: string;
tutorial: boolean; tutorial: boolean;
session_type: string; session_type: string;
auth_session_id_hash: string; auth_session_id_hash: string;
notification_settings: { notification_settings: {
flags: number; flags: number;
}; };
}; };
}; };
type mainuserjson = userjson & { type mainuserjson = userjson & {
flags: number; flags: number;
mfa_enabled?: boolean; mfa_enabled?: boolean;
email?: string; email?: string;
phone?: string; phone?: string;
verified: boolean; verified: boolean;
nsfw_allowed: boolean; nsfw_allowed: boolean;
premium: boolean; premium: boolean;
purchased_flags: number; purchased_flags: number;
premium_usage_flags: number; premium_usage_flags: number;
disabled: boolean; disabled: boolean;
}; };
type userjson = { type userjson = {
username: string; username: string;
discriminator: string; discriminator: string;
id: string; id: string;
public_flags: number; public_flags: number;
avatar: string | null; avatar: string | null;
accent_color: number; accent_color: number;
banner?: string; banner?: string;
bio: string; bio: string;
bot: boolean; bot: boolean;
premium_since: string; premium_since: string;
premium_type: number; premium_type: number;
theme_colors: string; theme_colors: string;
pronouns: string; pronouns: string;
badge_ids: string[]; badge_ids: string[];
}; };
type memberjson = { type memberjson = {
index?: number; index?: number;
id: string; id: string;
user: userjson | null; user: userjson | null;
guild_id: string; guild_id: string;
guild: { guild: {
id: string; id: string;
} | null; } | null;
nick?: string; nick?: string;
roles: string[]; roles: string[];
joined_at: string; joined_at: string;
premium_since: string; premium_since: string;
deaf: boolean; deaf: boolean;
mute: boolean; mute: boolean;
pending: boolean; pending: boolean;
last_message_id?: boolean; //What??? last_message_id?: boolean; //What???
}; };
type emojijson = { type emojijson = {
name: string; name: string;
id?: string; id?: string;
animated?: boolean; animated?: boolean;
}; };
type guildjson = { type guildjson = {
application_command_counts: { [key: string]: number }; application_command_counts: { [key: string]: number };
channels: channeljson[]; channels: channeljson[];
data_mode: string; data_mode: string;
emojis: emojijson[]; emojis: emojijson[];
guild_scheduled_events: []; guild_scheduled_events: [];
id: string; id: string;
large: boolean; large: boolean;
lazy: boolean; lazy: boolean;
member_count: number; member_count: number;
premium_subscription_count: number; premium_subscription_count: number;
properties: { properties: {
region: string | null; region: string | null;
name: string; name: string;
description: string; description: string;
icon: string; icon: string;
splash: string; splash: string;
banner: string; banner: string;
features: string[]; features: string[];
preferred_locale: string; preferred_locale: string;
owner_id: string; owner_id: string;
application_id: string; application_id: string;
afk_channel_id: string; afk_channel_id: string;
afk_timeout: number; afk_timeout: number;
member_count: number; member_count: number;
system_channel_id: string; system_channel_id: string;
verification_level: number; verification_level: number;
explicit_content_filter: number; explicit_content_filter: number;
default_message_notifications: number; default_message_notifications: number;
mfa_level: number; mfa_level: number;
vanity_url_code: number; vanity_url_code: number;
premium_tier: number; premium_tier: number;
premium_progress_bar_enabled: boolean; premium_progress_bar_enabled: boolean;
system_channel_flags: number; system_channel_flags: number;
discovery_splash: string; discovery_splash: string;
rules_channel_id: string; rules_channel_id: string;
public_updates_channel_id: string; public_updates_channel_id: string;
max_video_channel_users: number; max_video_channel_users: number;
max_members: number; max_members: number;
nsfw_level: number; nsfw_level: number;
hub_type: null; hub_type: null;
home_header: null; home_header: null;
id: string; id: string;
latest_onboarding_question_id: string; latest_onboarding_question_id: string;
max_stage_video_channel_users: number; max_stage_video_channel_users: number;
nsfw: boolean; nsfw: boolean;
safety_alerts_channel_id: string; safety_alerts_channel_id: string;
}; };
roles: rolesjson[]; roles: rolesjson[];
stage_instances: []; stage_instances: [];
stickers: []; stickers: [];
threads: []; threads: [];
version: string; version: string;
guild_hashes: {}; guild_hashes: {};
joined_at: string; joined_at: string;
}; };
type startTypingjson = { type startTypingjson = {
d: { d: {
channel_id: string; channel_id: string;
guild_id?: string; guild_id?: string;
user_id: string; user_id: string;
timestamp: number; timestamp: number;
member?: memberjson; member?: memberjson;
}; };
}; };
type channeljson = { type channeljson = {
id: string; id: string;
created_at: string; created_at: string;
name: string; name: string;
icon: string; icon: string;
type: number; type: number;
last_message_id: string; last_message_id: string;
guild_id: string; guild_id: string;
parent_id: string; parent_id: string;
last_pin_timestamp: string; last_pin_timestamp: string;
default_auto_archive_duration: number; default_auto_archive_duration: number;
permission_overwrites: { permission_overwrites: {
id: string; id: string;
allow: string; allow: string;
deny: string; deny: string;
}[]; }[];
video_quality_mode: null; video_quality_mode: null;
nsfw: boolean; nsfw: boolean;
topic: string; topic: string;
retention_policy_id: string; retention_policy_id: string;
flags: number; flags: number;
default_thread_rate_limit_per_user: number; default_thread_rate_limit_per_user: number;
position: number; position: number;
}; };
type rolesjson = { type rolesjson = {
id: string; id: string;
guild_id: string; guild_id: string;
color: number; color: number;
hoist: boolean; hoist: boolean;
managed: boolean; managed: boolean;
mentionable: boolean; mentionable: boolean;
name: string; name: string;
permissions: string; permissions: string;
position: number; position: number;
icon: string; icon: string;
unicode_emoji: string; unicode_emoji: string;
flags: number; flags: number;
}; };
type dirrectjson = { type dirrectjson = {
id: string; id: string;
flags: number; flags: number;
last_message_id: string; last_message_id: string;
type: number; type: number;
recipients: userjson[]; recipients: userjson[];
is_spam: boolean; is_spam: boolean;
}; };
type messagejson = { type messagejson = {
id: string; id: string;
channel_id: string; channel_id: string;
guild_id: string; guild_id: string;
author: userjson; author: userjson;
member?: memberjson; member?: memberjson;
content: string; content: string;
timestamp: string; timestamp: string;
edited_timestamp: string; edited_timestamp: string;
tts: boolean; tts: boolean;
mention_everyone: boolean; mention_everyone: boolean;
mentions: []; //need examples to fix mentions: []; //need examples to fix
mention_roles: []; //need examples to fix mention_roles: []; //need examples to fix
attachments: filejson[]; attachments: filejson[];
embeds: embedjson[]; embeds: embedjson[];
reactions: { reactions: {
count: number; count: number;
emoji: emojijson; //very likely needs expanding emoji: emojijson; //very likely needs expanding
me: boolean; me: boolean;
}[]; }[];
nonce: string; nonce: string;
pinned: boolean; pinned: boolean;
type: number; type: number;
}; };
type filejson = { type filejson = {
id: string; id: string;
filename: string; filename: string;
content_type: string; content_type: string;
width?: number; width?: number;
height?: number; height?: number;
proxy_url: string | undefined; proxy_url: string | undefined;
url: string; url: string;
size: number; size: number;
}; };
type embedjson = { type embedjson = {
type: string | null; type: string | null;
color?: number; color?: number;
author: { author: {
icon_url?: string; icon_url?: string;
name?: string; name?: string;
url?: string; url?: string;
title?: string; title?: string;
}; };
title?: string; title?: string;
url?: string; url?: string;
description?: string; description?: string;
fields?: { fields?: {
name: string; name: string;
value: string; value: string;
inline: boolean; inline: boolean;
}[]; }[];
footer?: { footer?: {
icon_url?: string; icon_url?: string;
text?: string; text?: string;
thumbnail?: string; thumbnail?: string;
}; };
timestamp?: string; timestamp?: string;
thumbnail: { thumbnail: {
proxy_url: string; proxy_url: string;
url: string; url: string;
width: number; width: number;
height: number; height: number;
}; };
provider: { provider: {
name: string; name: string;
}; };
video?: { video?: {
url: string; url: string;
width?: number | null; width?: number | null;
height?: number | null; height?: number | null;
proxy_url?: string; proxy_url?: string;
}; };
invite?: { invite?: {
url: string; url: string;
code: string; code: string;
}; };
}; };
type invitejson = { type invitejson = {
code: string; code: string;
temporary: boolean; temporary: boolean;
uses: number; uses: number;
max_use: number; max_use: number;
max_age: number; max_age: number;
created_at: string; created_at: string;
expires_at: string; expires_at: string;
guild_id: string; guild_id: string;
channel_id: string; channel_id: string;
inviter_id: string; inviter_id: string;
target_user_id: string | null; target_user_id: string | null;
target_user_type: string | null; target_user_type: string | null;
vanity_url: string | null; vanity_url: string | null;
flags: number; flags: number;
guild: guildjson["properties"]; guild: guildjson["properties"];
channel: channeljson; channel: channeljson;
inviter: userjson; inviter: userjson;
}; };
type presencejson = { type presencejson = {
status: string; status: string;
since: number | null; since: number | null;
activities: any[]; //bit more complicated but not now activities: any[]; //bit more complicated but not now
afk: boolean; afk: boolean;
user?: userjson; user?: userjson;
}; };
type messageCreateJson = { type messageCreateJson = {
op: 0; op: 0;
d: { d: {
guild_id?: string; guild_id?: string;
channel_id?: string; channel_id?: string;
} & messagejson; } & messagejson;
s: number; s: number;
t: "MESSAGE_CREATE"; t: "MESSAGE_CREATE";
}; };
type wsjson = type wsjson =
| { | {
op: 0; op: 0;
d: any; d: any;
s: number; s: number;
t: t:
| "TYPING_START" | "TYPING_START"
| "USER_UPDATE" | "USER_UPDATE"
| "CHANNEL_UPDATE" | "CHANNEL_UPDATE"
| "CHANNEL_CREATE" | "CHANNEL_CREATE"
| "CHANNEL_DELETE" | "CHANNEL_DELETE"
| "GUILD_DELETE" | "GUILD_DELETE"
| "GUILD_CREATE" | "GUILD_CREATE"
| "MESSAGE_REACTION_REMOVE_ALL" | "MESSAGE_REACTION_REMOVE_ALL"
| "MESSAGE_REACTION_REMOVE_EMOJI"; | "MESSAGE_REACTION_REMOVE_EMOJI";
} }
| { | {
op: 0; op: 0;
t: "GUILD_MEMBERS_CHUNK"; t: "GUILD_MEMBERS_CHUNK";
d: memberChunk; d: memberChunk;
s: number; s: number;
} }
| { | {
op: 0; op: 0;
d: { d: {
id: string; id: string;
guild_id?: string; guild_id?: string;
channel_id: string; channel_id: string;
}; };
s: number; s: number;
t: "MESSAGE_DELETE"; t: "MESSAGE_DELETE";
} }
| { | {
op: 0; op: 0;
d: { d: {
guild_id?: string; guild_id?: string;
channel_id: string; channel_id: string;
} & messagejson; } & messagejson;
s: number; s: number;
t: "MESSAGE_UPDATE"; t: "MESSAGE_UPDATE";
} }
| messageCreateJson | messageCreateJson
| readyjson | readyjson
| { | {
op: 11; op: 11;
s: undefined; s: undefined;
d: {}; d: {};
} }
| { | {
op: 10; op: 10;
s: undefined; s: undefined;
d: { d: {
heartbeat_interval: number; heartbeat_interval: number;
}; };
} }
| { | {
op: 0; op: 0;
t: "MESSAGE_REACTION_ADD"; t: "MESSAGE_REACTION_ADD";
d: { d: {
user_id: string; user_id: string;
channel_id: string; channel_id: string;
message_id: string; message_id: string;
guild_id?: string; guild_id?: string;
emoji: emojijson; emoji: emojijson;
member?: memberjson; member?: memberjson;
}; };
s: number; s: number;
} }
| { | {
op: 0; op: 0;
t: "MESSAGE_REACTION_REMOVE"; t: "MESSAGE_REACTION_REMOVE";
d: { d: {
user_id: string; user_id: string;
channel_id: string; channel_id: string;
message_id: string; message_id: string;
guild_id: string; guild_id: string;
emoji: emojijson; emoji: emojijson;
}; };
s: 3; s: 3;
}; };
type memberChunk = { type memberChunk = {
guild_id: string; guild_id: string;
nonce: string; nonce: string;
members: memberjson[]; members: memberjson[];
presences: presencejson[]; presences: presencejson[];
chunk_index: number; chunk_index: number;
chunk_count: number; chunk_count: number;
not_found: string[]; not_found: string[];
}; };
export { export {
readyjson, readyjson,
dirrectjson, dirrectjson,
startTypingjson, startTypingjson,
channeljson, channeljson,
guildjson, guildjson,
rolesjson, rolesjson,
userjson, userjson,
memberjson, memberjson,
mainuserjson, mainuserjson,
messagejson, messagejson,
filejson, filejson,
embedjson, embedjson,
emojijson, emojijson,
presencejson, presencejson,
wsjson, wsjson,
messageCreateJson, messageCreateJson,
memberChunk, memberChunk,
invitejson, invitejson,
}; };

View file

@ -6,14 +6,14 @@ import { User } from "./user.js";
import { Dialog } from "./dialog.js"; import { Dialog } from "./dialog.js";
import { getapiurls, getBulkInfo, setTheme, Specialuser } from "./login.js"; import { getapiurls, getBulkInfo, setTheme, Specialuser } from "./login.js";
import { import {
channeljson, channeljson,
guildjson, guildjson,
memberjson, memberjson,
messageCreateJson, messageCreateJson,
presencejson, presencejson,
readyjson, readyjson,
startTypingjson, startTypingjson,
wsjson, wsjson,
} from "./jsontypes.js"; } from "./jsontypes.js";
import { Member } from "./member.js"; import { Member } from "./member.js";
import { FormError, Settings } from "./settings.js"; import { FormError, Settings } from "./settings.js";
@ -22,22 +22,22 @@ import { MarkDown } from "./markdown.js";
const wsCodesRetry = new Set([4000, 4003, 4005, 4007, 4008, 4009]); const wsCodesRetry = new Set([4000, 4003, 4005, 4007, 4008, 4009]);
class Localuser { class Localuser {
badges: Map< badges: Map<
string, string,
{ id: string; description: string; icon: string; link: string } { id: string; description: string; icon: string; link: string }
> = new Map(); > = new Map();
lastSequence: number | null = null; lastSequence: number | null = null;
token!: string; token!: string;
userinfo!: Specialuser; userinfo!: Specialuser;
serverurls!: Specialuser["serverurls"]; serverurls!: Specialuser["serverurls"];
initialized!: boolean; initialized!: boolean;
info!: Specialuser["serverurls"]; info!: Specialuser["serverurls"];
headers!: { "Content-type": string; Authorization: string }; headers!: { "Content-type": string; Authorization: string };
userConnections!: Dialog; userConnections!: Dialog;
devPortal!: Dialog; devPortal!: Dialog;
ready!: readyjson; ready!: readyjson;
guilds!: Guild[]; guilds!: Guild[];
guildids: Map<string, Guild> = new Map(); guildids: Map<string, Guild> = new Map();
user!: User; user!: User;
status!: string; status!: string;
channelfocus: Channel | undefined; channelfocus: Channel | undefined;
@ -1634,7 +1634,7 @@ class Localuser {
//---------- resolving members code ----------- //---------- resolving members code -----------
readonly waitingmembers: Map< readonly waitingmembers: Map<
string, string,
Map<string, (returns: memberjson | undefined) => void> Map<string, (returns: memberjson | undefined)> void>
> = new Map(); > = new Map();
readonly presences: Map<string, presencejson> = new Map(); readonly presences: Map<string, presencejson> = new Map();
async resolvemember( async resolvemember(
@ -1675,7 +1675,7 @@ class Localuser {
return await promise; return await promise;
} }
fetchingmembers: Map<string, boolean> = new Map(); fetchingmembers: Map<string, boolean> = new Map();
noncemap: Map<string, (r: [memberjson[], string[]]) => void> = new Map(); noncemap: Map<string, (r: [memberjson[], string[]])> void> = new Map();
noncebuild: Map<string, [memberjson[], string[], number[]]> = new Map(); noncebuild: Map<string, [memberjson[], string[], number[]]> = new Map();
async gotChunk(chunk: { async gotChunk(chunk: {
chunk_index: number; chunk_index: number;
@ -1820,5 +1820,5 @@ class Localuser {
]); ]);
dialog.show(); dialog.show();
} }
} }
export { Localuser }; export { Localuser };

View file

@ -3,207 +3,207 @@ import { Dialog } from "./dialog.js";
const mobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent); const mobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
function setTheme() { function setTheme() {
let name = localStorage.getItem("theme"); let name = localStorage.getItem("theme");
if (!name) { if (!name) {
localStorage.setItem("theme", "Dark"); localStorage.setItem("theme", "Dark");
name = "Dark"; name = "Dark";
} }
document.body.className = name + "-theme"; document.body.className = name + "-theme";
} }
let instances: let instances:
| { | {
name: string; name: string;
description?: string; description?: string;
descriptionLong?: string; descriptionLong?: string;
image?: string; image?: string;
url?: string; url?: string;
display?: boolean; display?: boolean;
online?: boolean; online?: boolean;
uptime: { alltime: number; daytime: number; weektime: number }; uptime: { alltime: number; daytime: number; weektime: number };
urls: { urls: {
wellknown: string; wellknown: string;
api: string; api: string;
cdn: string; cdn: string;
gateway: string; gateway: string;
login?: string; login?: string;
}; };
}[] }[]
| null; | null;
setTheme(); setTheme();
function getBulkUsers() { function getBulkUsers() {
const json = getBulkInfo(); const json = getBulkInfo();
for (const thing in json.users) { for (const thing in json.users) {
json.users[thing] = new Specialuser(json.users[thing]); json.users[thing] = new Specialuser(json.users[thing]);
} }
return json; return json;
} }
function trimswitcher() { function trimswitcher() {
const json = getBulkInfo(); const json = getBulkInfo();
const map = new Map(); const map = new Map();
for (const thing in json.users) { for (const thing in json.users) {
const user = json.users[thing]; const user = json.users[thing];
let wellknown = user.serverurls.wellknown; let wellknown = user.serverurls.wellknown;
if (wellknown.at(-1) !== "/") { if (wellknown.at(-1) !== "/") {
wellknown += "/"; wellknown += "/";
} }
wellknown += user.username; wellknown += user.username;
if (map.has(wellknown)) { if (map.has(wellknown)) {
const otheruser = map.get(wellknown); const otheruser = map.get(wellknown);
if (otheruser[1].serverurls.wellknown.at(-1) === "/") { if (otheruser[1].serverurls.wellknown.at(-1) === "/") {
delete json.users[otheruser[0]]; delete json.users[otheruser[0]];
map.set(wellknown, [thing, user]); map.set(wellknown, [thing, user]);
} else { } else {
delete json.users[thing]; delete json.users[thing];
} }
} else { } else {
map.set(wellknown, [thing, user]); map.set(wellknown, [thing, user]);
} }
} }
for (const thing in json.users) { for (const thing in json.users) {
if (thing.at(-1) === "/") { if (thing.at(-1) === "/") {
const user = json.users[thing]; const user = json.users[thing];
delete json.users[thing]; delete json.users[thing];
json.users[thing.slice(0, -1)] = user; json.users[thing.slice(0, -1)] = user;
} }
} }
localStorage.setItem("userinfos", JSON.stringify(json)); localStorage.setItem("userinfos", JSON.stringify(json));
console.log(json); console.log(json);
} }
function getBulkInfo() { function getBulkInfo() {
return JSON.parse(localStorage.getItem("userinfos")!); return JSON.parse(localStorage.getItem("userinfos")!);
} }
function setDefaults() { function setDefaults() {
let userinfos = getBulkInfo(); let userinfos = getBulkInfo();
if (!userinfos) { if (!userinfos) {
localStorage.setItem( localStorage.setItem(
"userinfos", "userinfos",
JSON.stringify({ JSON.stringify({
currentuser: null, currentuser: null,
users: {}, users: {},
preferences: { preferences: {
theme: "Dark", theme: "Dark",
notifications: false, notifications: false,
notisound: "three", notisound: "three",
}, },
}) })
); );
userinfos = getBulkInfo(); userinfos = getBulkInfo();
} }
if (userinfos.users === undefined) { if (userinfos.users === undefined) {
userinfos.users = {}; userinfos.users = {};
} }
if (userinfos.accent_color === undefined) { if (userinfos.accent_color === undefined) {
userinfos.accent_color = "#242443"; userinfos.accent_color = "#242443";
} }
document.documentElement.style.setProperty( document.documentElement.style.setProperty(
"--accent-color", "--accent-color",
userinfos.accent_color userinfos.accent_color
); );
if (userinfos.preferences === undefined) { if (userinfos.preferences === undefined) {
userinfos.preferences = { userinfos.preferences = {
theme: "Dark", theme: "Dark",
notifications: false, notifications: false,
notisound: "three", notisound: "three",
}; };
} }
if (userinfos.preferences && userinfos.preferences.notisound === undefined) { if (userinfos.preferences && userinfos.preferences.notisound === undefined) {
userinfos.preferences.notisound = "three"; userinfos.preferences.notisound = "three";
} }
localStorage.setItem("userinfos", JSON.stringify(userinfos)); localStorage.setItem("userinfos", JSON.stringify(userinfos));
} }
setDefaults(); setDefaults();
class Specialuser { class Specialuser {
serverurls: { serverurls: {
api: string; api: string;
cdn: string; cdn: string;
gateway: string; gateway: string;
wellknown: string; wellknown: string;
login: string; login: string;
}; };
email: string; email: string;
token: string; token: string;
loggedin; loggedin;
json; json;
constructor(json: any) { constructor(json: any) {
if (json instanceof Specialuser) { if (json instanceof Specialuser) {
console.error("specialuser can't construct from another specialuser"); console.error("specialuser can't construct from another specialuser");
} }
this.serverurls = json.serverurls; this.serverurls = json.serverurls;
let apistring = new URL(json.serverurls.api).toString(); let apistring = new URL(json.serverurls.api).toString();
apistring = apistring.replace(/\/(v\d+\/?)?$/, "") + "/v9"; apistring = apistring.replace(/\/(v\d+\/?)?$/, "") + "/v9";
this.serverurls.api = apistring; this.serverurls.api = apistring;
this.serverurls.cdn = new URL(json.serverurls.cdn) this.serverurls.cdn = new URL(json.serverurls.cdn)
.toString() .toString()
.replace(/\/$/, ""); .replace(/\/$/, "");
this.serverurls.gateway = new URL(json.serverurls.gateway) this.serverurls.gateway = new URL(json.serverurls.gateway)
.toString() .toString()
.replace(/\/$/, ""); .replace(/\/$/, "");
this.serverurls.wellknown = new URL(json.serverurls.wellknown) this.serverurls.wellknown = new URL(json.serverurls.wellknown)
.toString() .toString()
.replace(/\/$/, ""); .replace(/\/$/, "");
this.serverurls.login = new URL(json.serverurls.login) this.serverurls.login = new URL(json.serverurls.login)
.toString() .toString()
.replace(/\/$/, ""); .replace(/\/$/, "");
this.email = json.email; this.email = json.email;
this.token = json.token; this.token = json.token;
this.loggedin = json.loggedin; this.loggedin = json.loggedin;
this.json = json; this.json = json;
this.json.localuserStore ??= {}; this.json.localuserStore ??= {};
if (!this.serverurls || !this.email || !this.token) { if (!this.serverurls || !this.email || !this.token) {
console.error( console.error(
"There are fundamentally missing pieces of info missing from this user" "There are fundamentally missing pieces of info missing from this user"
); );
} }
} }
set pfpsrc(e) { set pfpsrc(e) {
this.json.pfpsrc = e; this.json.pfpsrc = e;
this.updateLocal(); this.updateLocal();
} }
get pfpsrc() { get pfpsrc() {
return this.json.pfpsrc; return this.json.pfpsrc;
} }
set username(e) { set username(e) {
this.json.username = e; this.json.username = e;
this.updateLocal(); this.updateLocal();
} }
get username() { get username() {
return this.json.username; return this.json.username;
} }
set localuserStore(e) { set localuserStore(e) {
this.json.localuserStore = e; this.json.localuserStore = e;
this.updateLocal(); this.updateLocal();
} }
get localuserStore() { get localuserStore() {
return this.json.localuserStore; return this.json.localuserStore;
} }
get uid() { get uid() {
return this.email + this.serverurls.wellknown; return this.email + this.serverurls.wellknown;
} }
toJSON() { toJSON() {
return this.json; return this.json;
} }
updateLocal() { updateLocal() {
const info = getBulkInfo(); const info = getBulkInfo();
info.users[this.uid] = this.toJSON(); info.users[this.uid] = this.toJSON();
localStorage.setItem("userinfos", JSON.stringify(info)); localStorage.setItem("userinfos", JSON.stringify(info));
} }
} }
function adduser(user: typeof Specialuser.prototype.json) { function adduser(user: typeof Specialuser.prototype.json) {
user = new Specialuser(user); user = new Specialuser(user);
const info = getBulkInfo(); const info = getBulkInfo();
info.users[user.uid] = user; info.users[user.uid] = user;
info.currentuser = user.uid; info.currentuser = user.uid;
localStorage.setItem("userinfos", JSON.stringify(info)); localStorage.setItem("userinfos", JSON.stringify(info));
return user; return user;
} }
const instancein = document.getElementById("instancein") as HTMLInputElement; const instancein = document.getElementById("instancein") as HTMLInputElement;
let timeout: string | number | NodeJS.Timeout | undefined; let timeout: string | number | NodeJS.Timeout | undefined;
// let instanceinfo; // let instanceinfo;
const stringURLMap = new Map<string, string>(); const stringURLMap = new Map<string, string>();
const stringURLsMap = new Map< const stringURLsMap = new Map<
string, string,
{ {
wellknown: string; wellknown: string;
@ -212,8 +212,8 @@ const stringURLsMap = new Map<
gateway: string; gateway: string;
login?: string; login?: string;
} }
>(); >();
async function getapiurls(str: string): Promise< async function getapiurls(str: string): Promise<
| { | {
api: string; api: string;
cdn: string; cdn: string;
@ -222,7 +222,7 @@ async function getapiurls(str: string): Promise<
login: string; login: string;
} }
| false | false
> { > {
if (!URL.canParse(str)) { if (!URL.canParse(str)) {
const val = stringURLMap.get(str); const val = stringURLMap.get(str);
if (val) { if (val) {
@ -311,8 +311,8 @@ async function getapiurls(str: string): Promise<
} }
return false; return false;
} }
} }
async function checkInstance(instance?: string) { async function checkInstance(instance?: string) {
const verify = document.getElementById("verify"); const verify = document.getElementById("verify");
try { try {
verify!.textContent = "Checking Instance"; verify!.textContent = "Checking Instance";
@ -345,9 +345,9 @@ async function checkInstance(instance?: string) {
console.log("catch"); console.log("catch");
verify!.textContent = "Invalid Instance, try again"; verify!.textContent = "Invalid Instance, try again";
} }
} }
if (instancein) { if (instancein) {
console.log(instancein); console.log(instancein);
instancein.addEventListener("keydown", (_) => { instancein.addEventListener("keydown", (_) => {
const verify = document.getElementById("verify"); const verify = document.getElementById("verify");
@ -365,9 +365,9 @@ if (instancein) {
} else { } else {
checkInstance("https://spacebar.chat/"); checkInstance("https://spacebar.chat/");
} }
} }
async function login(username: string, password: string, captcha: string) { async function login(username: string, password: string, captcha: string) {
if (captcha === "") { if (captcha === "") {
captcha = ""; captcha = "";
} }
@ -491,9 +491,9 @@ async function login(username: string, password: string, captcha: string) {
} catch (error) { } catch (error) {
console.error("Error:", error); console.error("Error:", error);
} }
} }
async function check(e: SubmitEvent) { async function check(e: SubmitEvent) {
e.preventDefault(); e.preventDefault();
const target = e.target as HTMLFormElement; const target = e.target as HTMLFormElement;
const h = await login( const h = await login(
@ -506,16 +506,16 @@ async function check(e: SubmitEvent) {
wrongElement.textContent = h; wrongElement.textContent = h;
} }
console.log(h); console.log(h);
} }
if (document.getElementById("form")) { if (document.getElementById("form")) {
const form = document.getElementById("form"); const form = document.getElementById("form");
if (form) { if (form) {
form.addEventListener("submit", (e: SubmitEvent) => check(e)); form.addEventListener("submit", (e: SubmitEvent) => check(e));
} }
} }
//this currently does not work, and need to be implemented better at some time. //this currently does not work, and need to be implemented better at some time.
/* /*
if ("serviceWorker" in navigator){ if ("serviceWorker" in navigator){
navigator.serviceWorker.register("/service.js", { navigator.serviceWorker.register("/service.js", {
scope: "/", scope: "/",
}).then((registration) => { }).then((registration) => {
@ -537,10 +537,10 @@ if ("serviceWorker" in navigator){
}); });
} }
}) })
} }
*/ */
const switchurl = document.getElementById("switch") as HTMLAreaElement; const switchurl = document.getElementById("switch") as HTMLAreaElement;
if (switchurl) { if (switchurl) {
switchurl.href += window.location.search; switchurl.href += window.location.search;
const instance = new URLSearchParams(window.location.search).get("instance"); const instance = new URLSearchParams(window.location.search).get("instance");
console.log(instance); console.log(instance);
@ -548,10 +548,10 @@ if (switchurl) {
instancein.value = instance; instancein.value = instance;
checkInstance(""); checkInstance("");
} }
} }
export { checkInstance }; export { checkInstance };
trimswitcher(); trimswitcher();
export { export {
mobile, mobile,
getBulkUsers, getBulkUsers,
getBulkInfo, getBulkInfo,
@ -559,15 +559,15 @@ export {
Specialuser, Specialuser,
getapiurls, getapiurls,
adduser, adduser,
}; };
const datalist = document.getElementById("instances"); const datalist = document.getElementById("instances");
console.warn(datalist); console.warn(datalist);
export function getInstances() { export function getInstances() {
return instances; return instances;
} }
fetch("/instances.json") fetch("/instances.json")
.then((_) => _.json()) .then((_) => _.json())
.then( .then(
( (

File diff suppressed because it is too large Load diff

View file

@ -6,59 +6,59 @@ import { memberjson, presencejson } from "./jsontypes.js";
import { Dialog } from "./dialog.js"; import { Dialog } from "./dialog.js";
class Member extends SnowFlake { class Member extends SnowFlake {
static already = {}; static already = {};
owner: Guild; owner: Guild;
user: User; user: User;
roles: Role[] = []; roles: Role[] = [];
nick!: string; nick!: string;
[key: string]: any; [key: string]: any;
private constructor(memberjson: memberjson, owner: Guild) { private constructor(memberjson: memberjson, owner: Guild) {
super(memberjson.id); super(memberjson.id);
this.owner = owner; this.owner = owner;
if (this.localuser.userMap.has(memberjson.id)) { if (this.localuser.userMap.has(memberjson.id)) {
this.user = this.localuser.userMap.get(memberjson.id) as User; this.user = this.localuser.userMap.get(memberjson.id) as User;
} else if (memberjson.user) { } else if (memberjson.user) {
this.user = new User(memberjson.user, owner.localuser); this.user = new User(memberjson.user, owner.localuser);
} else { } else {
throw new Error("Missing user object of this member"); throw new Error("Missing user object of this member");
} }
for (const key of Object.keys(memberjson)) { for (const key of Object.keys(memberjson)) {
if (key === "guild" || key === "owner") { if (key === "guild" || key === "owner") {
continue; continue;
} }
if (key === "roles") { if (key === "roles") {
for (const strrole of memberjson.roles) { for (const strrole of memberjson.roles) {
const role = this.guild.roleids.get(strrole); const role = this.guild.roleids.get(strrole);
if (!role) continue; if (!role) continue;
this.roles.push(role); this.roles.push(role);
} }
continue; continue;
} }
(this as any)[key] = (memberjson as any)[key]; (this as any)[key] = (memberjson as any)[key];
} }
if (this.localuser.userMap.has(this?.id)) { if (this.localuser.userMap.has(this?.id)) {
this.user = this.localuser.userMap.get(this?.id) as User; this.user = this.localuser.userMap.get(this?.id) as User;
} }
this.roles.sort((a, b) => { this.roles.sort((a, b) => {
return this.guild.roles.indexOf(a) - this.guild.roles.indexOf(b); return this.guild.roles.indexOf(a) - this.guild.roles.indexOf(b);
}); });
} }
get guild() { get guild() {
return this.owner; return this.owner;
} }
get localuser() { get localuser() {
return this.guild.localuser; return this.guild.localuser;
} }
get info() { get info() {
return this.owner.info; return this.owner.info;
} }
static async new( static async new(
memberjson: memberjson, memberjson: memberjson,
owner: Guild owner: Guild
): Promise<Member | undefined> { ): Promise<Member | undefined> {
let user: User; let user: User;
if (owner.localuser.userMap.has(memberjson.id)) { if (owner.localuser.userMap.has(memberjson.id)) {
user = owner.localuser.userMap.get(memberjson.id) as User; user = owner.localuser.userMap.get(memberjson.id) as User;
@ -252,5 +252,5 @@ class Member extends SnowFlake {
} }
return false; return false;
} }
} }
export { Member }; export { Member };

View file

@ -13,7 +13,7 @@ import { Emoji } from "./emoji.js";
import { Dialog } from "./dialog.js"; import { Dialog } from "./dialog.js";
class Message extends SnowFlake { class Message extends SnowFlake {
static contextmenu = new Contextmenu<Message, undefined>("message menu"); static contextmenu = new Contextmenu<Message, undefined>("message menu");
owner: Channel; owner: Channel;
headers: Localuser["headers"]; headers: Localuser["headers"];
embeds!: Embed[]; embeds!: Embed[];
@ -735,11 +735,11 @@ class Message extends SnowFlake {
} }
return this.div as HTMLElement; return this.div as HTMLElement;
} }
} }
let now: string; let now: string;
let yesterdayStr: string; let yesterdayStr: string;
function formatTime(date: Date) { function formatTime(date: Date) {
updateTimes(); updateTimes();
const datestring = date.toLocaleDateString(); const datestring = date.toLocaleDateString();
const formatTime = (date: Date) => const formatTime = (date: Date) =>
@ -752,10 +752,10 @@ function formatTime(date: Date) {
} else { } else {
return `${date.toLocaleDateString()} at ${formatTime(date)}`; return `${date.toLocaleDateString()} at ${formatTime(date)}`;
} }
} }
let tomorrow = 0; let tomorrow = 0;
updateTimes(); updateTimes();
function updateTimes() { function updateTimes() {
if (tomorrow < Date.now()) { if (tomorrow < Date.now()) {
const d = new Date(); const d = new Date();
tomorrow = d.setHours(24, 0, 0, 0); tomorrow = d.setHours(24, 0, 0, 0);
@ -764,6 +764,6 @@ function updateTimes() {
yesterday.setDate(new Date().getDate() - 1); yesterday.setDate(new Date().getDate() - 1);
yesterdayStr = yesterday.toLocaleDateString(); yesterdayStr = yesterday.toLocaleDateString();
} }
} }
Message.setup(); Message.setup();
export { Message }; export { Message };

View file

@ -1,347 +1,347 @@
class Permissions { class Permissions {
allow: bigint; allow: bigint;
deny: bigint; deny: bigint;
readonly hasDeny: boolean; readonly hasDeny: boolean;
constructor(allow: string, deny: string = "") { constructor(allow: string, deny: string = "") {
this.hasDeny = Boolean(deny); this.hasDeny = Boolean(deny);
try { try {
this.allow = BigInt(allow); this.allow = BigInt(allow);
this.deny = BigInt(deny); this.deny = BigInt(deny);
} catch { } catch {
this.allow = 0n; this.allow = 0n;
this.deny = 0n; this.deny = 0n;
console.error( console.error(
`Something really stupid happened with a permission with allow being ${allow} and deny being, ${deny}, execution will still happen, but something really stupid happened, please report if you know what caused this.` `Something really stupid happened with a permission with allow being ${allow} and deny being, ${deny}, execution will still happen, but something really stupid happened, please report if you know what caused this.`
); );
} }
} }
getPermissionbit(b: number, big: bigint): boolean { getPermissionbit(b: number, big: bigint): boolean {
return Boolean((big >> BigInt(b)) & 1n); return Boolean((big >> BigInt(b)) & 1n);
} }
setPermissionbit(b: number, state: boolean, big: bigint): bigint { setPermissionbit(b: number, state: boolean, big: bigint): bigint {
const bit = 1n << BigInt(b); const bit = 1n << BigInt(b);
return (big & ~bit) | (BigInt(state) << BigInt(b)); //thanks to geotale for this code :3 return (big & ~bit) | (BigInt(state) << BigInt(b)); //thanks to geotale for this code :3
} }
static map: { static map: {
[key: number | string]: [key: number | string]:
| { name: string; readableName: string; description: string } | { name: string; readableName: string; description: string }
| number; | number;
}; };
static info: { name: string; readableName: string; description: string }[]; static info: { name: string; readableName: string; description: string }[];
static makeMap() { static makeMap() {
Permissions.info = [ Permissions.info = [
//for people in the future, do not reorder these, the creation of the map realize on the order //for people in the future, do not reorder these, the creation of the map realize on the order
{ {
name: "CREATE_INSTANT_INVITE", name: "CREATE_INSTANT_INVITE",
readableName: "Create invite", readableName: "Create invite",
description: "Allows the user to create invites for the guild", description: "Allows the user to create invites for the guild",
}, },
{ {
name: "KICK_MEMBERS", name: "KICK_MEMBERS",
readableName: "Kick members", readableName: "Kick members",
description: "Allows the user to kick members from the guild", description: "Allows the user to kick members from the guild",
}, },
{ {
name: "BAN_MEMBERS", name: "BAN_MEMBERS",
readableName: "Ban members", readableName: "Ban members",
description: "Allows the user to ban members from the guild", description: "Allows the user to ban members from the guild",
}, },
{ {
name: "ADMINISTRATOR", name: "ADMINISTRATOR",
readableName: "Administrator", readableName: "Administrator",
description: description:
"Allows all permissions and bypasses channel permission overwrites. This is a dangerous permission!", "Allows all permissions and bypasses channel permission overwrites. This is a dangerous permission!",
}, },
{ {
name: "MANAGE_CHANNELS", name: "MANAGE_CHANNELS",
readableName: "Manage channels", readableName: "Manage channels",
description: "Allows the user to manage and edit channels", description: "Allows the user to manage and edit channels",
}, },
{ {
name: "MANAGE_GUILD", name: "MANAGE_GUILD",
readableName: "Manage guild", readableName: "Manage guild",
description: "Allows management and editing of the guild", description: "Allows management and editing of the guild",
}, },
{ {
name: "ADD_REACTIONS", name: "ADD_REACTIONS",
readableName: "Add reactions", readableName: "Add reactions",
description: "Allows user to add reactions to messages", description: "Allows user to add reactions to messages",
}, },
{ {
name: "VIEW_AUDIT_LOG", name: "VIEW_AUDIT_LOG",
readableName: "View audit log", readableName: "View audit log",
description: "Allows the user to view the audit log", description: "Allows the user to view the audit log",
}, },
{ {
name: "PRIORITY_SPEAKER", name: "PRIORITY_SPEAKER",
readableName: "Priority speaker", readableName: "Priority speaker",
description: "Allows for using priority speaker in a voice channel", description: "Allows for using priority speaker in a voice channel",
}, },
{ {
name: "STREAM", name: "STREAM",
readableName: "Video", readableName: "Video",
description: "Allows the user to stream", description: "Allows the user to stream",
}, },
{ {
name: "VIEW_CHANNEL", name: "VIEW_CHANNEL",
readableName: "View channels", readableName: "View channels",
description: "Allows the user to view the channel", description: "Allows the user to view the channel",
}, },
{ {
name: "SEND_MESSAGES", name: "SEND_MESSAGES",
readableName: "Send messages", readableName: "Send messages",
description: "Allows user to send messages", description: "Allows user to send messages",
}, },
{ {
name: "SEND_TTS_MESSAGES", name: "SEND_TTS_MESSAGES",
readableName: "Send text-to-speech messages", readableName: "Send text-to-speech messages",
description: "Allows the user to send text-to-speech messages", description: "Allows the user to send text-to-speech messages",
}, },
{ {
name: "MANAGE_MESSAGES", name: "MANAGE_MESSAGES",
readableName: "Manage messages", readableName: "Manage messages",
description: "Allows the user to delete messages that aren't their own", description: "Allows the user to delete messages that aren't their own",
}, },
{ {
name: "EMBED_LINKS", name: "EMBED_LINKS",
readableName: "Embed links", readableName: "Embed links",
description: "Allow links sent by this user to auto-embed", description: "Allow links sent by this user to auto-embed",
}, },
{ {
name: "ATTACH_FILES", name: "ATTACH_FILES",
readableName: "Attach files", readableName: "Attach files",
description: "Allows the user to attach files", description: "Allows the user to attach files",
}, },
{ {
name: "READ_MESSAGE_HISTORY", name: "READ_MESSAGE_HISTORY",
readableName: "Read message history", readableName: "Read message history",
description: "Allows user to read the message history", description: "Allows user to read the message history",
}, },
{ {
name: "MENTION_EVERYONE", name: "MENTION_EVERYONE",
readableName: "Mention @everyone, @here and all roles", readableName: "Mention @everyone, @here and all roles",
description: "Allows the user to mention everyone", description: "Allows the user to mention everyone",
}, },
{ {
name: "USE_EXTERNAL_EMOJIS", name: "USE_EXTERNAL_EMOJIS",
readableName: "Use external emojis", readableName: "Use external emojis",
description: "Allows the user to use external emojis", description: "Allows the user to use external emojis",
}, },
{ {
name: "VIEW_GUILD_INSIGHTS", name: "VIEW_GUILD_INSIGHTS",
readableName: "View guild insights", readableName: "View guild insights",
description: "Allows the user to see guild insights", description: "Allows the user to see guild insights",
}, },
{ {
name: "CONNECT", name: "CONNECT",
readableName: "Connect", readableName: "Connect",
description: "Allows the user to connect to a voice channel", description: "Allows the user to connect to a voice channel",
}, },
{ {
name: "SPEAK", name: "SPEAK",
readableName: "Speak", readableName: "Speak",
description: "Allows the user to speak in a voice channel", description: "Allows the user to speak in a voice channel",
}, },
{ {
name: "MUTE_MEMBERS", name: "MUTE_MEMBERS",
readableName: "Mute members", readableName: "Mute members",
description: "Allows user to mute other members", description: "Allows user to mute other members",
}, },
{ {
name: "DEAFEN_MEMBERS", name: "DEAFEN_MEMBERS",
readableName: "Deafen members", readableName: "Deafen members",
description: "Allows user to deafen other members", description: "Allows user to deafen other members",
}, },
{ {
name: "MOVE_MEMBERS", name: "MOVE_MEMBERS",
readableName: "Move members", readableName: "Move members",
description: "Allows the user to move members between voice channels", description: "Allows the user to move members between voice channels",
}, },
{ {
name: "USE_VAD", name: "USE_VAD",
readableName: "Use voice activity detection", readableName: "Use voice activity detection",
description: description:
"Allows users to speak in a voice channel by simply talking", "Allows users to speak in a voice channel by simply talking",
}, },
{ {
name: "CHANGE_NICKNAME", name: "CHANGE_NICKNAME",
readableName: "Change nickname", readableName: "Change nickname",
description: "Allows the user to change their own nickname", description: "Allows the user to change their own nickname",
}, },
{ {
name: "MANAGE_NICKNAMES", name: "MANAGE_NICKNAMES",
readableName: "Manage nicknames", readableName: "Manage nicknames",
description: "Allows user to change nicknames of other members", description: "Allows user to change nicknames of other members",
}, },
{ {
name: "MANAGE_ROLES", name: "MANAGE_ROLES",
readableName: "Manage roles", readableName: "Manage roles",
description: "Allows user to edit and manage roles", description: "Allows user to edit and manage roles",
}, },
{ {
name: "MANAGE_WEBHOOKS", name: "MANAGE_WEBHOOKS",
readableName: "Manage webhooks", readableName: "Manage webhooks",
description: "Allows management and editing of webhooks", description: "Allows management and editing of webhooks",
}, },
{ {
name: "MANAGE_GUILD_EXPRESSIONS", name: "MANAGE_GUILD_EXPRESSIONS",
readableName: "Manage expressions", readableName: "Manage expressions",
description: "Allows for managing emoji, stickers, and soundboards", description: "Allows for managing emoji, stickers, and soundboards",
}, },
{ {
name: "USE_APPLICATION_COMMANDS", name: "USE_APPLICATION_COMMANDS",
readableName: "Use application commands", readableName: "Use application commands",
description: "Allows the user to use application commands", description: "Allows the user to use application commands",
}, },
{ {
name: "REQUEST_TO_SPEAK", name: "REQUEST_TO_SPEAK",
readableName: "Request to speak", readableName: "Request to speak",
description: "Allows user to request to speak in stage channel", description: "Allows user to request to speak in stage channel",
}, },
{ {
name: "MANAGE_EVENTS", name: "MANAGE_EVENTS",
readableName: "Manage events", readableName: "Manage events",
description: "Allows user to edit and manage events", description: "Allows user to edit and manage events",
}, },
{ {
name: "MANAGE_THREADS", name: "MANAGE_THREADS",
readableName: "Manage threads", readableName: "Manage threads",
description: description:
"Allows the user to delete and archive threads and view all private threads", "Allows the user to delete and archive threads and view all private threads",
}, },
{ {
name: "CREATE_PUBLIC_THREADS", name: "CREATE_PUBLIC_THREADS",
readableName: "Create public threads", readableName: "Create public threads",
description: "Allows the user to create public threads", description: "Allows the user to create public threads",
}, },
{ {
name: "CREATE_PRIVATE_THREADS", name: "CREATE_PRIVATE_THREADS",
readableName: "Create private threads", readableName: "Create private threads",
description: "Allows the user to create private threads", description: "Allows the user to create private threads",
}, },
{ {
name: "USE_EXTERNAL_STICKERS", name: "USE_EXTERNAL_STICKERS",
readableName: "Use external stickers", readableName: "Use external stickers",
description: "Allows user to use external stickers", description: "Allows user to use external stickers",
}, },
{ {
name: "SEND_MESSAGES_IN_THREADS", name: "SEND_MESSAGES_IN_THREADS",
readableName: "Send messages in threads", readableName: "Send messages in threads",
description: "Allows the user to send messages in threads", description: "Allows the user to send messages in threads",
}, },
{ {
name: "USE_EMBEDDED_ACTIVITIES", name: "USE_EMBEDDED_ACTIVITIES",
readableName: "Use activities", readableName: "Use activities",
description: "Allows the user to use embedded activities", description: "Allows the user to use embedded activities",
}, },
{ {
name: "MODERATE_MEMBERS", name: "MODERATE_MEMBERS",
readableName: "Timeout members", readableName: "Timeout members",
description: description:
"Allows the user to time out other users to prevent them from sending or reacting to messages in chat and threads, and from speaking in voice and stage channels", "Allows the user to time out other users to prevent them from sending or reacting to messages in chat and threads, and from speaking in voice and stage channels",
}, },
{ {
name: "VIEW_CREATOR_MONETIZATION_ANALYTICS", name: "VIEW_CREATOR_MONETIZATION_ANALYTICS",
readableName: "View creator monetization analytics", readableName: "View creator monetization analytics",
description: "Allows for viewing role subscription insights", description: "Allows for viewing role subscription insights",
}, },
{ {
name: "USE_SOUNDBOARD", name: "USE_SOUNDBOARD",
readableName: "Use soundboard", readableName: "Use soundboard",
description: "Allows for using soundboard in a voice channel", description: "Allows for using soundboard in a voice channel",
}, },
{ {
name: "CREATE_GUILD_EXPRESSIONS", name: "CREATE_GUILD_EXPRESSIONS",
readableName: "Create expressions", readableName: "Create expressions",
description: description:
"Allows for creating emojis, stickers, and soundboard sounds, and editing and deleting those created by the current user.", "Allows for creating emojis, stickers, and soundboard sounds, and editing and deleting those created by the current user.",
}, },
{ {
name: "CREATE_EVENTS", name: "CREATE_EVENTS",
readableName: "Create events", readableName: "Create events",
description: description:
"Allows for creating scheduled events, and editing and deleting those created by the current user.", "Allows for creating scheduled events, and editing and deleting those created by the current user.",
}, },
{ {
name: "USE_EXTERNAL_SOUNDS", name: "USE_EXTERNAL_SOUNDS",
readableName: "Use external sounds", readableName: "Use external sounds",
description: description:
"Allows the usage of custom soundboard sounds from other servers", "Allows the usage of custom soundboard sounds from other servers",
}, },
{ {
name: "SEND_VOICE_MESSAGES", name: "SEND_VOICE_MESSAGES",
readableName: "Send voice messages", readableName: "Send voice messages",
description: "Allows sending voice messages", description: "Allows sending voice messages",
}, },
{ {
name: "SEND_POLLS", name: "SEND_POLLS",
readableName: "Create polls", readableName: "Create polls",
description: "Allows sending polls", description: "Allows sending polls",
}, },
{ {
name: "USE_EXTERNAL_APPS", name: "USE_EXTERNAL_APPS",
readableName: "Use external apps", readableName: "Use external apps",
description: description:
"Allows user-installed apps to send public responses. " + "Allows user-installed apps to send public responses. " +
"When disabled, users will still be allowed to use their apps but the responses will be ephemeral. " + "When disabled, users will still be allowed to use their apps but the responses will be ephemeral. " +
"This only applies to apps not also installed to the server.", "This only applies to apps not also installed to the server.",
}, },
]; ];
Permissions.map = {}; Permissions.map = {};
let i = 0; let i = 0;
for (const thing of Permissions.info) { for (const thing of Permissions.info) {
Permissions.map[i] = thing; Permissions.map[i] = thing;
Permissions.map[thing.name] = i; Permissions.map[thing.name] = i;
i++; i++;
} }
} }
getPermission(name: string): number { getPermission(name: string): number {
if (this.getPermissionbit(Permissions.map[name] as number, this.allow)) { if (this.getPermissionbit(Permissions.map[name] as number, this.allow)) {
return 1; return 1;
} else if ( } else if (
this.getPermissionbit(Permissions.map[name] as number, this.deny) this.getPermissionbit(Permissions.map[name] as number, this.deny)
) { ) {
return -1; return -1;
} else { } else {
return 0; return 0;
} }
} }
hasPermission(name: string): boolean { hasPermission(name: string): boolean {
if (this.deny) { if (this.deny) {
console.warn( console.warn(
"This function may of been used in error, think about using getPermision instead" "This function may of been used in error, think about using getPermision instead"
); );
} }
if (this.getPermissionbit(Permissions.map[name] as number, this.allow)) if (this.getPermissionbit(Permissions.map[name] as number, this.allow))
return true; return true;
if (name != "ADMINISTRATOR") return this.hasPermission("ADMINISTRATOR"); if (name != "ADMINISTRATOR") return this.hasPermission("ADMINISTRATOR");
return false; return false;
} }
setPermission(name: string, setto: number): void { setPermission(name: string, setto: number): void {
const bit = Permissions.map[name] as number; const bit = Permissions.map[name] as number;
if (!bit) { if (!bit) {
return console.error( return console.error(
"Tried to set permission to " + "Tried to set permission to " +
setto + setto +
" for " + " for " +
name + name +
" but it doesn't exist" " but it doesn't exist"
); );
} }
if (setto === 0) { if (setto === 0) {
this.deny = this.setPermissionbit(bit, false, this.deny); this.deny = this.setPermissionbit(bit, false, this.deny);
this.allow = this.setPermissionbit(bit, false, this.allow); this.allow = this.setPermissionbit(bit, false, this.allow);
} else if (setto === 1) { } else if (setto === 1) {
this.deny = this.setPermissionbit(bit, false, this.deny); this.deny = this.setPermissionbit(bit, false, this.deny);
this.allow = this.setPermissionbit(bit, true, this.allow); this.allow = this.setPermissionbit(bit, true, this.allow);
} else if (setto === -1) { } else if (setto === -1) {
this.deny = this.setPermissionbit(bit, true, this.deny); this.deny = this.setPermissionbit(bit, true, this.deny);
this.allow = this.setPermissionbit(bit, false, this.allow); this.allow = this.setPermissionbit(bit, false, this.allow);
} else { } else {
console.error("invalid number entered:" + setto); console.error("invalid number entered:" + setto);
} }
} }
} }
Permissions.makeMap(); Permissions.makeMap();
export { Permissions }; export { Permissions };

View file

@ -2,149 +2,149 @@ import { checkInstance, adduser } from "./login.js";
const registerElement = document.getElementById("register"); const registerElement = document.getElementById("register");
if (registerElement) { if (registerElement) {
registerElement.addEventListener("submit", registertry); registerElement.addEventListener("submit", registertry);
} }
async function registertry(e: Event) { async function registertry(e: Event) {
e.preventDefault(); e.preventDefault();
const elements = (e.target as HTMLFormElement) const elements = (e.target as HTMLFormElement)
.elements as HTMLFormControlsCollection; .elements as HTMLFormControlsCollection;
const email = (elements[1] as HTMLInputElement).value; const email = (elements[1] as HTMLInputElement).value;
const username = (elements[2] as HTMLInputElement).value; const username = (elements[2] as HTMLInputElement).value;
const password = (elements[3] as HTMLInputElement).value; const password = (elements[3] as HTMLInputElement).value;
const confirmPassword = (elements[4] as HTMLInputElement).value; const confirmPassword = (elements[4] as HTMLInputElement).value;
const dateofbirth = (elements[5] as HTMLInputElement).value; const dateofbirth = (elements[5] as HTMLInputElement).value;
const consent = (elements[6] as HTMLInputElement).checked; const consent = (elements[6] as HTMLInputElement).checked;
const captchaKey = (elements[7] as HTMLInputElement)?.value; const captchaKey = (elements[7] as HTMLInputElement)?.value;
if (password !== confirmPassword) { if (password !== confirmPassword) {
(document.getElementById("wrong") as HTMLElement).textContent = (document.getElementById("wrong") as HTMLElement).textContent =
"Passwords don't match"; "Passwords don't match";
return; return;
} }
const instanceInfo = JSON.parse(localStorage.getItem("instanceinfo") ?? "{}"); const instanceInfo = JSON.parse(localStorage.getItem("instanceinfo") ?? "{}");
const apiurl = new URL(instanceInfo.api); const apiurl = new URL(instanceInfo.api);
try { try {
const response = await fetch(apiurl + "/auth/register", { const response = await fetch(apiurl + "/auth/register", {
body: JSON.stringify({ body: JSON.stringify({
date_of_birth: dateofbirth, date_of_birth: dateofbirth,
email, email,
username, username,
password, password,
consent, consent,
captcha_key: captchaKey, captcha_key: captchaKey,
}), }),
headers: { headers: {
"content-type": "application/json", "content-type": "application/json",
}, },
method: "POST", method: "POST",
}); });
const data = await response.json(); const data = await response.json();
if (data.captcha_sitekey) { if (data.captcha_sitekey) {
const capt = document.getElementById("h-captcha"); const capt = document.getElementById("h-captcha");
if (capt && !capt.children.length) { if (capt && !capt.children.length) {
const capty = document.createElement("div"); const capty = document.createElement("div");
capty.classList.add("h-captcha"); capty.classList.add("h-captcha");
capty.setAttribute("data-sitekey", data.captcha_sitekey); capty.setAttribute("data-sitekey", data.captcha_sitekey);
const script = document.createElement("script"); const script = document.createElement("script");
script.src = "https://js.hcaptcha.com/1/api.js"; script.src = "https://js.hcaptcha.com/1/api.js";
capt.append(script); capt.append(script);
capt.append(capty); capt.append(capty);
} else { } else {
eval("hcaptcha.reset()"); eval("hcaptcha.reset()");
} }
return; return;
} }
if (!data.token) { if (!data.token) {
handleErrors(data.errors, elements); handleErrors(data.errors, elements);
} else { } else {
adduser({ adduser({
serverurls: instanceInfo, serverurls: instanceInfo,
email, email,
token: data.token, token: data.token,
}).username = username; }).username = username;
localStorage.setItem("token", data.token); localStorage.setItem("token", data.token);
const redir = new URLSearchParams(window.location.search).get("goback"); const redir = new URLSearchParams(window.location.search).get("goback");
window.location.href = redir ? redir : "/channels/@me"; window.location.href = redir ? redir : "/channels/@me";
} }
} catch (error) { } catch (error) {
console.error("Registration failed:", error); console.error("Registration failed:", error);
} }
} }
function handleErrors(errors: any, elements: HTMLFormControlsCollection) { function handleErrors(errors: any, elements: HTMLFormControlsCollection) {
if (errors.consent) { if (errors.consent) {
showError(elements[6] as HTMLElement, errors.consent._errors[0].message); showError(elements[6] as HTMLElement, errors.consent._errors[0].message);
} else if (errors.password) { } else if (errors.password) {
showError( showError(
elements[3] as HTMLElement, elements[3] as HTMLElement,
"Password: " + errors.password._errors[0].message "Password: " + errors.password._errors[0].message
); );
} else if (errors.username) { } else if (errors.username) {
showError( showError(
elements[2] as HTMLElement, elements[2] as HTMLElement,
"Username: " + errors.username._errors[0].message "Username: " + errors.username._errors[0].message
); );
} else if (errors.email) { } else if (errors.email) {
showError( showError(
elements[1] as HTMLElement, elements[1] as HTMLElement,
"Email: " + errors.email._errors[0].message "Email: " + errors.email._errors[0].message
); );
} else if (errors.date_of_birth) { } else if (errors.date_of_birth) {
showError( showError(
elements[5] as HTMLElement, elements[5] as HTMLElement,
"Date of Birth: " + errors.date_of_birth._errors[0].message "Date of Birth: " + errors.date_of_birth._errors[0].message
); );
} else { } else {
(document.getElementById("wrong") as HTMLElement).textContent = (document.getElementById("wrong") as HTMLElement).textContent =
errors[Object.keys(errors)[0]]._errors[0].message; errors[Object.keys(errors)[0]]._errors[0].message;
} }
} }
function showError(element: HTMLElement, message: string) { function showError(element: HTMLElement, message: string) {
const parent = element.parentElement!; const parent = element.parentElement!;
let errorElement = parent.getElementsByClassName( let errorElement = parent.getElementsByClassName(
"suberror" "suberror"
)[0] as HTMLElement; )[0] as HTMLElement;
if (!errorElement) { if (!errorElement) {
const div = document.createElement("div"); const div = document.createElement("div");
div.classList.add("suberror", "suberrora"); div.classList.add("suberror", "suberrora");
parent.append(div); parent.append(div);
errorElement = div; errorElement = div;
} else { } else {
errorElement.classList.remove("suberror"); errorElement.classList.remove("suberror");
setTimeout(() => { setTimeout(() => {
errorElement.classList.add("suberror"); errorElement.classList.add("suberror");
}, 100); }, 100);
} }
errorElement.textContent = message; errorElement.textContent = message;
} }
let TOSa = document.getElementById("TOSa") as HTMLAnchorElement | null; let TOSa = document.getElementById("TOSa") as HTMLAnchorElement | null;
async function tosLogic() { async function tosLogic() {
const instanceInfo = JSON.parse(localStorage.getItem("instanceinfo") ?? "{}"); const instanceInfo = JSON.parse(localStorage.getItem("instanceinfo") ?? "{}");
const apiurl = new URL(instanceInfo.api); const apiurl = new URL(instanceInfo.api);
const response = await fetch(apiurl.toString() + "/ping"); const response = await fetch(apiurl.toString() + "/ping");
const data = await response.json(); const data = await response.json();
const tosPage = data.instance.tosPage; const tosPage = data.instance.tosPage;
if (tosPage) { if (tosPage) {
document.getElementById("TOSbox")!.innerHTML = document.getElementById("TOSbox")!.innerHTML =
'I agree to the <a href="" id="TOSa">Terms of Service</a>:'; 'I agree to the <a href="" id="TOSa">Terms of Service</a>:';
TOSa = document.getElementById("TOSa") as HTMLAnchorElement; TOSa = document.getElementById("TOSa") as HTMLAnchorElement;
TOSa.href = tosPage; TOSa.href = tosPage;
} else { } else {
document.getElementById("TOSbox")!.textContent = document.getElementById("TOSbox")!.textContent =
"This instance has no Terms of Service, accept ToS anyways:"; "This instance has no Terms of Service, accept ToS anyways:";
TOSa = null; TOSa = null;
} }
console.log(tosPage); console.log(tosPage);
} }
tosLogic(); tosLogic();

View file

@ -4,41 +4,41 @@ import { Guild } from "./guild.js";
import { SnowFlake } from "./snowflake.js"; import { SnowFlake } from "./snowflake.js";
import { rolesjson } from "./jsontypes.js"; import { rolesjson } from "./jsontypes.js";
class Role extends SnowFlake { class Role extends SnowFlake {
permissions: Permissions; permissions: Permissions;
owner: Guild; owner: Guild;
color!: number; color!: number;
name!: string; name!: string;
info: Guild["info"]; info: Guild["info"];
hoist!: boolean; hoist!: boolean;
icon!: string; icon!: string;
mentionable!: boolean; mentionable!: boolean;
unicode_emoji!: string; unicode_emoji!: string;
headers: Guild["headers"]; headers: Guild["headers"];
constructor(json: rolesjson, owner: Guild) { constructor(json: rolesjson, owner: Guild) {
super(json.id); super(json.id);
this.headers = owner.headers; this.headers = owner.headers;
this.info = owner.info; this.info = owner.info;
for (const thing of Object.keys(json)) { for (const thing of Object.keys(json)) {
if (thing === "id") { if (thing === "id") {
continue; continue;
} }
(this as any)[thing] = (json as any)[thing]; (this as any)[thing] = (json as any)[thing];
} }
this.permissions = new Permissions(json.permissions); this.permissions = new Permissions(json.permissions);
this.owner = owner; this.owner = owner;
} }
get guild(): Guild { get guild(): Guild {
return this.owner; return this.owner;
} }
get localuser(): Localuser { get localuser(): Localuser {
return this.guild.localuser; return this.guild.localuser;
} }
getColor(): string | null { getColor(): string | null {
if (this.color === 0) { if (this.color === 0) {
return null; return null;
} }
return `#${this.color.toString(16)}`; return `#${this.color.toString(16)}`;
} }
} }
export { Role }; export { Role };
import { Options } from "./settings.js"; import { Options } from "./settings.js";
@ -119,9 +119,9 @@ class PermissionToggle implements OptionsElement<number> {
return div; return div;
} }
submit() {} submit() {}
} }
import { OptionsElement, Buttons } from "./settings.js"; import { OptionsElement, Buttons } from "./settings.js";
class RoleList extends Buttons { class RoleList extends Buttons {
readonly permissions: [Role, Permissions][]; readonly permissions: [Role, Permissions][];
permission: Permissions; permission: Permissions;
readonly guild: Guild; readonly guild: Guild;
@ -176,5 +176,5 @@ class RoleList extends Buttons {
save() { save() {
this.onchange(this.curid, this.permission); this.onchange(this.curid, this.permission);
} }
} }
export { RoleList }; export { RoleList };

View file

@ -1,96 +1,96 @@
function deleteoldcache() { function deleteoldcache() {
caches.delete("cache"); caches.delete("cache");
console.log("this ran :P"); console.log("this ran :P");
} }
async function putInCache(request: URL | RequestInfo, response: Response) { async function putInCache(request: URL | RequestInfo, response: Response) {
console.log(request, response); console.log(request, response);
const cache = await caches.open("cache"); const cache = await caches.open("cache");
console.log("Grabbed"); console.log("Grabbed");
try { try {
console.log(await cache.put(request, response)); console.log(await cache.put(request, response));
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
} }
console.log("test"); console.log("test");
let lastcache: string; let lastcache: string;
self.addEventListener("activate", async () => { self.addEventListener("activate", async () => {
console.log("test2"); console.log("test2");
checkCache(); checkCache();
}); });
async function checkCache() { async function checkCache() {
if (checkedrecently) { if (checkedrecently) {
return; return;
} }
const promise = await caches.match("/getupdates"); const promise = await caches.match("/getupdates");
if (promise) { if (promise) {
lastcache = await promise.text(); lastcache = await promise.text();
} }
console.log(lastcache); console.log(lastcache);
fetch("/getupdates").then(async (data) => { fetch("/getupdates").then(async (data) => {
const text = await data.clone().text(); const text = await data.clone().text();
console.log(text, lastcache); console.log(text, lastcache);
if (lastcache !== text) { if (lastcache !== text) {
deleteoldcache(); deleteoldcache();
putInCache("/getupdates", data.clone()); putInCache("/getupdates", data.clone());
} }
checkedrecently = true; checkedrecently = true;
setTimeout((_: any) => { setTimeout((_: any) => {
checkedrecently = false; checkedrecently = false;
}, 1000 * 60 * 30); }, 1000 * 60 * 30);
}); });
} }
var checkedrecently = false; var checkedrecently = false;
function samedomain(url: string | URL) { function samedomain(url: string | URL) {
return new URL(url).origin === self.origin; return new URL(url).origin === self.origin;
} }
function isindexhtml(url: string | URL) { function isindexhtml(url: string | URL) {
console.log(url); console.log(url);
if (new URL(url).pathname.startsWith("/channels")) { if (new URL(url).pathname.startsWith("/channels")) {
return true; return true;
} }
return false; return false;
} }
async function getfile(event: { async function getfile(event: {
request: { url: URL | RequestInfo; clone: () => string | URL | Request }; request: { url: URL | RequestInfo; clone: () => string | URL | Request };
}) { }) {
checkCache(); checkCache();
if (!samedomain(event.request.url.toString())) { if (!samedomain(event.request.url.toString())) {
return await fetch(event.request.clone()); return await fetch(event.request.clone());
} }
const responseFromCache = await caches.match(event.request.url); const responseFromCache = await caches.match(event.request.url);
console.log(responseFromCache, caches); console.log(responseFromCache, caches);
if (responseFromCache) { if (responseFromCache) {
console.log("cache hit"); console.log("cache hit");
return responseFromCache; return responseFromCache;
} }
if (isindexhtml(event.request.url.toString())) { if (isindexhtml(event.request.url.toString())) {
console.log("is index.html"); console.log("is index.html");
const responseFromCache = await caches.match("/index.html"); const responseFromCache = await caches.match("/index.html");
if (responseFromCache) { if (responseFromCache) {
console.log("cache hit"); console.log("cache hit");
return responseFromCache; return responseFromCache;
} }
const responseFromNetwork = await fetch("/index.html"); const responseFromNetwork = await fetch("/index.html");
await putInCache("/index.html", responseFromNetwork.clone()); await putInCache("/index.html", responseFromNetwork.clone());
return responseFromNetwork; return responseFromNetwork;
} }
const responseFromNetwork = await fetch(event.request.clone()); const responseFromNetwork = await fetch(event.request.clone());
console.log(event.request.clone()); console.log(event.request.clone());
await putInCache(event.request.clone(), responseFromNetwork.clone()); await putInCache(event.request.clone(), responseFromNetwork.clone());
try { try {
return responseFromNetwork; return responseFromNetwork;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
return e; return e;
} }
} }
self.addEventListener("fetch", (event: any) => { self.addEventListener("fetch", (event: any) => {
try { try {
event.respondWith(getfile(event)); event.respondWith(getfile(event));
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }
}); });

View file

@ -4,9 +4,9 @@ interface OptionsElement<x> {
submit: () => void; submit: () => void;
readonly watchForChange: (func: (arg1: x) => void) => void; readonly watchForChange: (func: (arg1: x) => void) => void;
value: x; value: x;
} }
//future me stuff //future me stuff
class Buttons implements OptionsElement<unknown> { class Buttons implements OptionsElement<unknown> {
readonly name: string; readonly name: string;
readonly buttons: [string, Options | string][]; readonly buttons: [string, Options | string][];
buttonList!: HTMLDivElement; buttonList!: HTMLDivElement;
@ -75,9 +75,9 @@ class Buttons implements OptionsElement<unknown> {
watchForChange() {} watchForChange() {}
save() {} save() {}
submit() {} submit() {}
} }
class TextInput implements OptionsElement<string> { class TextInput implements OptionsElement<string> {
readonly label: string; readonly label: string;
readonly owner: Options; readonly owner: Options;
readonly onSubmit: (str: string) => void; readonly onSubmit: (str: string) => void;
@ -125,9 +125,9 @@ class TextInput implements OptionsElement<string> {
submit() { submit() {
this.onSubmit(this.value); this.onSubmit(this.value);
} }
} }
class SettingsText implements OptionsElement<void> { class SettingsText implements OptionsElement<void> {
readonly onSubmit!: (str: string) => void; readonly onSubmit!: (str: string) => void;
value!: void; value!: void;
readonly text: string; readonly text: string;
@ -141,8 +141,8 @@ class SettingsText implements OptionsElement<void> {
} }
watchForChange() {} watchForChange() {}
submit() {} submit() {}
} }
class SettingsTitle implements OptionsElement<void> { class SettingsTitle implements OptionsElement<void> {
readonly onSubmit!: (str: string) => void; readonly onSubmit!: (str: string) => void;
value!: void; value!: void;
readonly text: string; readonly text: string;
@ -156,8 +156,8 @@ class SettingsTitle implements OptionsElement<void> {
} }
watchForChange() {} watchForChange() {}
submit() {} submit() {}
} }
class CheckboxInput implements OptionsElement<boolean> { class CheckboxInput implements OptionsElement<boolean> {
readonly label: string; readonly label: string;
readonly owner: Options; readonly owner: Options;
readonly onSubmit: (str: boolean) => void; readonly onSubmit: (str: boolean) => void;
@ -203,9 +203,9 @@ class CheckboxInput implements OptionsElement<boolean> {
submit() { submit() {
this.onSubmit(this.value); this.onSubmit(this.value);
} }
} }
class ButtonInput implements OptionsElement<void> { class ButtonInput implements OptionsElement<void> {
readonly label: string; readonly label: string;
readonly owner: Options; readonly owner: Options;
readonly onClick: () => void; readonly onClick: () => void;
@ -239,9 +239,9 @@ class ButtonInput implements OptionsElement<void> {
} }
watchForChange() {} watchForChange() {}
submit() {} submit() {}
} }
class ColorInput implements OptionsElement<string> { class ColorInput implements OptionsElement<string> {
readonly label: string; readonly label: string;
readonly owner: Options; readonly owner: Options;
readonly onSubmit: (str: string) => void; readonly onSubmit: (str: string) => void;
@ -289,9 +289,9 @@ class ColorInput implements OptionsElement<string> {
submit() { submit() {
this.onSubmit(this.colorContent); this.onSubmit(this.colorContent);
} }
} }
class SelectInput implements OptionsElement<number> { class SelectInput implements OptionsElement<number> {
readonly label: string; readonly label: string;
readonly owner: Options; readonly owner: Options;
readonly onSubmit: (str: number) => void; readonly onSubmit: (str: number) => void;
@ -348,8 +348,8 @@ class SelectInput implements OptionsElement<number> {
submit() { submit() {
this.onSubmit(this.index); this.onSubmit(this.index);
} }
} }
class MDInput implements OptionsElement<string> { class MDInput implements OptionsElement<string> {
readonly label: string; readonly label: string;
readonly owner: Options; readonly owner: Options;
readonly onSubmit: (str: string) => void; readonly onSubmit: (str: string) => void;
@ -395,8 +395,8 @@ class MDInput implements OptionsElement<string> {
submit() { submit() {
this.onSubmit(this.value); this.onSubmit(this.value);
} }
} }
class FileInput implements OptionsElement<FileList | null> { class FileInput implements OptionsElement<FileList | null> {
readonly label: string; readonly label: string;
readonly owner: Options; readonly owner: Options;
readonly onSubmit: (str: FileList | null) => void; readonly onSubmit: (str: FileList | null) => void;
@ -458,9 +458,9 @@ class FileInput implements OptionsElement<FileList | null> {
this.onSubmit(input.files); this.onSubmit(input.files);
} }
} }
} }
class HtmlArea implements OptionsElement<void> { class HtmlArea implements OptionsElement<void> {
submit: () => void; submit: () => void;
html: (() => HTMLElement) | HTMLElement; html: (() => HTMLElement) | HTMLElement;
value!: void; value!: void;
@ -476,8 +476,8 @@ class HtmlArea implements OptionsElement<void> {
} }
} }
watchForChange() {} watchForChange() {}
} }
class Options implements OptionsElement<void> { class Options implements OptionsElement<void> {
name: string; name: string;
haschanged = false; haschanged = false;
readonly options: OptionsElement<any>[]; readonly options: OptionsElement<any>[];
@ -776,8 +776,8 @@ class Options implements OptionsElement<void> {
thing.submit(); thing.submit();
} }
} }
} }
class FormError extends Error { class FormError extends Error {
elem: OptionsElement<any>; elem: OptionsElement<any>;
message: string; message: string;
constructor(elem: OptionsElement<any>, message: string) { constructor(elem: OptionsElement<any>, message: string) {
@ -785,9 +785,9 @@ class FormError extends Error {
this.message = message; this.message = message;
this.elem = elem; this.elem = elem;
} }
} }
export { FormError }; export { FormError };
class Form implements OptionsElement<object> { class Form implements OptionsElement<object> {
name: string; name: string;
readonly options: Options; readonly options: Options;
readonly owner: Options; readonly owner: Options;
@ -1068,8 +1068,8 @@ class Form implements OptionsElement<object> {
} }
element.textContent = message; element.textContent = message;
} }
} }
class Settings extends Buttons { class Settings extends Buttons {
static readonly Buttons = Buttons; static readonly Buttons = Buttons;
static readonly Options = Options; static readonly Options = Options;
html!: HTMLElement | null; html!: HTMLElement | null;
@ -1108,6 +1108,6 @@ class Settings extends Buttons {
this.html = null; this.html = null;
} }
} }
} }
export { Settings, OptionsElement, Buttons, Options }; export { Settings, OptionsElement, Buttons, Options };

View file

@ -1,20 +1,20 @@
abstract class SnowFlake { abstract class SnowFlake {
public readonly id: string; public readonly id: string;
constructor(id: string) { constructor(id: string) {
this.id = id; this.id = id;
} }
getUnixTime(): number { getUnixTime(): number {
return SnowFlake.stringToUnixTime(this.id); return SnowFlake.stringToUnixTime(this.id);
} }
static stringToUnixTime(str: string) { static stringToUnixTime(str: string) {
try { try {
return Number((BigInt(str) >> 22n) + 1420070400000n); return Number((BigInt(str) >> 22n) + 1420070400000n);
} catch { } catch {
console.error( console.error(
`The ID is corrupted, it's ${str} when it should be some number.` `The ID is corrupted, it's ${str} when it should be some number.`
); );
return 0; return 0;
} }
} }
} }
export { SnowFlake }; export { SnowFlake };

View file

@ -7,25 +7,25 @@ import { SnowFlake } from "./snowflake.js";
import { presencejson, userjson } from "./jsontypes.js"; import { presencejson, userjson } from "./jsontypes.js";
class User extends SnowFlake { class User extends SnowFlake {
owner: Localuser; owner: Localuser;
hypotheticalpfp!: boolean; hypotheticalpfp!: boolean;
avatar!: string | null; avatar!: string | null;
username!: string; username!: string;
nickname: string | null = null; nickname: string | null = null;
relationshipType: 0 | 1 | 2 | 3 | 4 = 0; relationshipType: 0 | 1 | 2 | 3 | 4 = 0;
bio!: MarkDown; bio!: MarkDown;
discriminator!: string; discriminator!: string;
pronouns!: string; pronouns!: string;
bot!: boolean; bot!: boolean;
public_flags!: number; public_flags!: number;
accent_color!: number; accent_color!: number;
banner: string | undefined; banner: string | undefined;
hypotheticalbanner!: boolean; hypotheticalbanner!: boolean;
premium_since!: string; premium_since!: string;
premium_type!: number; premium_type!: number;
theme_colors!: string; theme_colors!: string;
badge_ids!: string[]; badge_ids!: string[];
members: WeakMap<Guild, Member | undefined | Promise<Member | undefined>> = members: WeakMap<Guild, Member | undefined | Promise<Member | undefined>> =
new WeakMap(); new WeakMap();
private status!: string; private status!: string;
resolving: false | Promise<any> = false; resolving: false | Promise<any> = false;
@ -483,7 +483,7 @@ class User extends SnowFlake {
e.stopPropagation(); e.stopPropagation();
}; };
} }
} }
User.setUpContextMenu(); User.setUpContextMenu();
export { User }; export { User };