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

View file

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

View file

@ -13,21 +13,21 @@ const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
interface Instance {
name: string;
[key: string]: any;
name: string;
[key: string]: any;
}
const app = express();
import instances from "./webpage/instances.json" with { type: "json" };
const instanceNames = new Map<string, Instance>();
for (const instance of instances) {
for (const instance of instances) {
instanceNames.set(instance.name, instance);
}
}
app.use(compression());
app.use(compression());
async function updateInstances(): Promise<void> {
async function updateInstances(): Promise<void> {
try {
const response = await fetch(
"https://raw.githubusercontent.com/spacebarchat/spacebarchat/master/instances/instances.json"
@ -51,11 +51,11 @@ async function updateInstances(): Promise<void> {
} catch (error) {
console.error("Error updating instances:", error);
}
}
}
updateInstances();
updateInstances();
app.use("/getupdates", (_req: Request, res: Response) => {
app.use("/getupdates", (_req: Request, res: Response) => {
try {
const stats = fs.statSync(path.join(__dirname, "webpage"));
res.send(stats.mtimeMs.toString());
@ -63,18 +63,18 @@ app.use("/getupdates", (_req: Request, res: Response) => {
console.error("Error getting updates:", error);
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);
});
});
app.use("/uptime", (req: Request, res: Response) => {
app.use("/uptime", (req: Request, res: Response) => {
const instanceUptime = uptime[req.query.name as string];
res.send(instanceUptime);
});
});
app.use("/", async (req: Request, res: Response) => {
app.use("/", async (req: Request, res: Response) => {
const scheme = req.secure ? "https" : "http";
const host = `${scheme}://${req.get("Host")}`;
const ref = host + req.originalUrl;
@ -110,11 +110,11 @@ app.use("/", async (req: Request, res: Response) => {
} else {
res.sendFile(path.join(__dirname, "webpage", "index.html"));
}
});
});
const PORT = process.env.PORT || Number(process.argv[2]) || 8080;
app.listen(PORT, () => {
const PORT = process.env.PORT || Number(process.argv[2]) || 8080;
app.listen(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);
interface UptimeEntry {
time: number;
online: boolean;
time: number;
online: boolean;
}
interface UptimeObject {
[key: string]: UptimeEntry[];
[key: string]: UptimeEntry[];
}
interface Instance {
name: string;
urls?: { api: string };
url?: string;
online?: boolean;
uptime?: {
daytime: number;
weektime: number;
alltime: number;
};
name: string;
urls?: { api: string };
url?: string;
online?: boolean;
uptime?: {
daytime: number;
weektime: number;
alltime: number;
};
}
let uptimeObject: UptimeObject = loadUptimeObject();
export { uptimeObject as uptime };
function loadUptimeObject(): UptimeObject {
const filePath = path.join(__dirname, "..", "uptime.json");
if (fs.existsSync(filePath)) {
try {
return JSON.parse(fs.readFileSync(filePath, "utf8"));
} catch (error) {
console.error("Error reading uptime.json:", error);
return {};
}
}
return {};
const filePath = path.join(__dirname, "..", "uptime.json");
if (fs.existsSync(filePath)) {
try {
return JSON.parse(fs.readFileSync(filePath, "utf8"));
} catch (error) {
console.error("Error reading uptime.json:", error);
return {};
}
}
return {};
}
function saveUptimeObject(): void {
fs.writeFile(
`${__dirname}/uptime.json`,
JSON.stringify(uptimeObject),
(error) => {
if (error) {
console.error("Error saving uptime.json:", error);
}
}
);
fs.writeFile(
`${__dirname}/uptime.json`,
JSON.stringify(uptimeObject),
(error) => {
if (error) {
console.error("Error saving uptime.json:", error);
}
}
);
}
function removeUndefinedKey(): void {
if (uptimeObject.undefined) {
delete uptimeObject.undefined;
saveUptimeObject();
}
if (uptimeObject.undefined) {
delete uptimeObject.undefined;
saveUptimeObject();
}
}
removeUndefinedKey();
@ -72,12 +72,12 @@ export async function observe(instances: Instance[]): Promise<void> {
);
await Promise.allSettled(instancePromises);
updateInactiveInstances(activeInstances);
}
}
async function resolveInstance(
async function resolveInstance(
instance: Instance,
activeInstances: Set<string>
): Promise<void> {
): Promise<void> {
try {
calcStats(instance);
const api = await getApiUrl(instance);
@ -90,9 +90,9 @@ async function resolveInstance(
} catch (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) {
return instance.urls.api;
}
@ -101,28 +101,28 @@ async function getApiUrl(instance: Instance): Promise<string | null> {
return urls ? urls.api : null;
}
return null;
}
}
function handleUnresolvedApi(instance: Instance): void {
function handleUnresolvedApi(instance: Instance): void {
setStatus(instance, false);
console.warn(`${instance.name} does not resolve api URL`, instance);
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 initialDelay = Math.random() * 1000 * 60 * 10;
setTimeout(() => {
checkHealth(instance, api);
setInterval(() => checkHealth(instance, api), checkInterval);
}, initialDelay);
}
}
async function checkHealth(
async function checkHealth(
instance: Instance,
api: string,
tries = 0
): Promise<void> {
): Promise<void> {
try {
const response = await fetch(`${api}ping`, { method: "HEAD" });
if (response.ok || tries > 3) {
@ -138,25 +138,25 @@ async function checkHealth(
retryHealthCheck(instance, api, tries);
}
}
}
}
function retryHealthCheck(
function retryHealthCheck(
instance: Instance,
api: string,
tries: number
): void {
): void {
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)) {
if (!activeInstances.has(key)) {
setStatus(key, false);
}
}
}
}
function calcStats(instance: Instance): void {
function calcStats(instance: Instance): void {
const obj = uptimeObject[instance.name];
if (!obj) return;
@ -199,15 +199,15 @@ function calcStats(instance: Instance): void {
weektime,
online
);
}
}
function calculateUptimeStats(
function calculateUptimeStats(
totalTimePassed: number,
alltime: number,
daytime: number,
weektime: number,
online: boolean
): { daytime: number; weektime: number; alltime: number } {
): { daytime: number; weektime: number; alltime: number } {
const dayInMs = 1000 * 60 * 60 * 24;
const weekInMs = dayInMs * 7;
@ -229,9 +229,9 @@ function calculateUptimeStats(
}
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;
let obj = uptimeObject[name];
@ -248,4 +248,4 @@ function setStatus(instance: string | Instance, status: boolean): void {
if (typeof instance !== "string") {
calcStats(instance);
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -6,14 +6,14 @@ import { User } from "./user.js";
import { Dialog } from "./dialog.js";
import { getapiurls, getBulkInfo, setTheme, Specialuser } from "./login.js";
import {
channeljson,
guildjson,
memberjson,
messageCreateJson,
presencejson,
readyjson,
startTypingjson,
wsjson,
channeljson,
guildjson,
memberjson,
messageCreateJson,
presencejson,
readyjson,
startTypingjson,
wsjson,
} from "./jsontypes.js";
import { Member } from "./member.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]);
class Localuser {
badges: Map<
string,
{ id: string; description: string; icon: string; link: string }
> = new Map();
lastSequence: number | null = null;
token!: string;
userinfo!: Specialuser;
serverurls!: Specialuser["serverurls"];
initialized!: boolean;
info!: Specialuser["serverurls"];
headers!: { "Content-type": string; Authorization: string };
userConnections!: Dialog;
devPortal!: Dialog;
ready!: readyjson;
guilds!: Guild[];
guildids: Map<string, Guild> = new Map();
badges: Map<
string,
{ id: string; description: string; icon: string; link: string }
> = new Map();
lastSequence: number | null = null;
token!: string;
userinfo!: Specialuser;
serverurls!: Specialuser["serverurls"];
initialized!: boolean;
info!: Specialuser["serverurls"];
headers!: { "Content-type": string; Authorization: string };
userConnections!: Dialog;
devPortal!: Dialog;
ready!: readyjson;
guilds!: Guild[];
guildids: Map<string, Guild> = new Map();
user!: User;
status!: string;
channelfocus: Channel | undefined;
@ -1634,7 +1634,7 @@ class Localuser {
//---------- resolving members code -----------
readonly waitingmembers: Map<
string,
Map<string, (returns: memberjson | undefined) => void>
Map<string, (returns: memberjson | undefined)> void>
> = new Map();
readonly presences: Map<string, presencejson> = new Map();
async resolvemember(
@ -1675,7 +1675,7 @@ class Localuser {
return await promise;
}
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();
async gotChunk(chunk: {
chunk_index: number;
@ -1820,5 +1820,5 @@ class Localuser {
]);
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);
function setTheme() {
let name = localStorage.getItem("theme");
if (!name) {
localStorage.setItem("theme", "Dark");
name = "Dark";
}
document.body.className = name + "-theme";
let name = localStorage.getItem("theme");
if (!name) {
localStorage.setItem("theme", "Dark");
name = "Dark";
}
document.body.className = name + "-theme";
}
let instances:
| {
name: string;
description?: string;
descriptionLong?: string;
image?: string;
url?: string;
display?: boolean;
online?: boolean;
uptime: { alltime: number; daytime: number; weektime: number };
urls: {
wellknown: string;
api: string;
cdn: string;
gateway: string;
login?: string;
};
}[]
| null;
| {
name: string;
description?: string;
descriptionLong?: string;
image?: string;
url?: string;
display?: boolean;
online?: boolean;
uptime: { alltime: number; daytime: number; weektime: number };
urls: {
wellknown: string;
api: string;
cdn: string;
gateway: string;
login?: string;
};
}[]
| null;
setTheme();
function getBulkUsers() {
const json = getBulkInfo();
for (const thing in json.users) {
json.users[thing] = new Specialuser(json.users[thing]);
}
return json;
const json = getBulkInfo();
for (const thing in json.users) {
json.users[thing] = new Specialuser(json.users[thing]);
}
return json;
}
function trimswitcher() {
const json = getBulkInfo();
const map = new Map();
for (const thing in json.users) {
const user = json.users[thing];
let wellknown = user.serverurls.wellknown;
if (wellknown.at(-1) !== "/") {
wellknown += "/";
}
wellknown += user.username;
if (map.has(wellknown)) {
const otheruser = map.get(wellknown);
if (otheruser[1].serverurls.wellknown.at(-1) === "/") {
delete json.users[otheruser[0]];
map.set(wellknown, [thing, user]);
} else {
delete json.users[thing];
}
} else {
map.set(wellknown, [thing, user]);
}
}
for (const thing in json.users) {
if (thing.at(-1) === "/") {
const user = json.users[thing];
delete json.users[thing];
json.users[thing.slice(0, -1)] = user;
}
}
localStorage.setItem("userinfos", JSON.stringify(json));
console.log(json);
const json = getBulkInfo();
const map = new Map();
for (const thing in json.users) {
const user = json.users[thing];
let wellknown = user.serverurls.wellknown;
if (wellknown.at(-1) !== "/") {
wellknown += "/";
}
wellknown += user.username;
if (map.has(wellknown)) {
const otheruser = map.get(wellknown);
if (otheruser[1].serverurls.wellknown.at(-1) === "/") {
delete json.users[otheruser[0]];
map.set(wellknown, [thing, user]);
} else {
delete json.users[thing];
}
} else {
map.set(wellknown, [thing, user]);
}
}
for (const thing in json.users) {
if (thing.at(-1) === "/") {
const user = json.users[thing];
delete json.users[thing];
json.users[thing.slice(0, -1)] = user;
}
}
localStorage.setItem("userinfos", JSON.stringify(json));
console.log(json);
}
function getBulkInfo() {
return JSON.parse(localStorage.getItem("userinfos")!);
return JSON.parse(localStorage.getItem("userinfos")!);
}
function setDefaults() {
let userinfos = getBulkInfo();
if (!userinfos) {
localStorage.setItem(
"userinfos",
JSON.stringify({
currentuser: null,
users: {},
preferences: {
theme: "Dark",
notifications: false,
notisound: "three",
},
})
);
userinfos = getBulkInfo();
}
if (userinfos.users === undefined) {
userinfos.users = {};
}
if (userinfos.accent_color === undefined) {
userinfos.accent_color = "#242443";
}
document.documentElement.style.setProperty(
"--accent-color",
userinfos.accent_color
);
if (userinfos.preferences === undefined) {
userinfos.preferences = {
theme: "Dark",
notifications: false,
notisound: "three",
};
}
if (userinfos.preferences && userinfos.preferences.notisound === undefined) {
userinfos.preferences.notisound = "three";
}
localStorage.setItem("userinfos", JSON.stringify(userinfos));
let userinfos = getBulkInfo();
if (!userinfos) {
localStorage.setItem(
"userinfos",
JSON.stringify({
currentuser: null,
users: {},
preferences: {
theme: "Dark",
notifications: false,
notisound: "three",
},
})
);
userinfos = getBulkInfo();
}
if (userinfos.users === undefined) {
userinfos.users = {};
}
if (userinfos.accent_color === undefined) {
userinfos.accent_color = "#242443";
}
document.documentElement.style.setProperty(
"--accent-color",
userinfos.accent_color
);
if (userinfos.preferences === undefined) {
userinfos.preferences = {
theme: "Dark",
notifications: false,
notisound: "three",
};
}
if (userinfos.preferences && userinfos.preferences.notisound === undefined) {
userinfos.preferences.notisound = "three";
}
localStorage.setItem("userinfos", JSON.stringify(userinfos));
}
setDefaults();
class Specialuser {
serverurls: {
api: string;
cdn: string;
gateway: string;
wellknown: string;
login: string;
};
email: string;
token: string;
loggedin;
json;
constructor(json: any) {
if (json instanceof Specialuser) {
console.error("specialuser can't construct from another specialuser");
}
this.serverurls = json.serverurls;
let apistring = new URL(json.serverurls.api).toString();
apistring = apistring.replace(/\/(v\d+\/?)?$/, "") + "/v9";
this.serverurls.api = apistring;
this.serverurls.cdn = new URL(json.serverurls.cdn)
.toString()
.replace(/\/$/, "");
this.serverurls.gateway = new URL(json.serverurls.gateway)
.toString()
.replace(/\/$/, "");
this.serverurls.wellknown = new URL(json.serverurls.wellknown)
.toString()
.replace(/\/$/, "");
this.serverurls.login = new URL(json.serverurls.login)
.toString()
.replace(/\/$/, "");
this.email = json.email;
this.token = json.token;
this.loggedin = json.loggedin;
this.json = json;
this.json.localuserStore ??= {};
if (!this.serverurls || !this.email || !this.token) {
console.error(
"There are fundamentally missing pieces of info missing from this user"
);
}
}
set pfpsrc(e) {
this.json.pfpsrc = e;
this.updateLocal();
}
get pfpsrc() {
return this.json.pfpsrc;
}
set username(e) {
this.json.username = e;
this.updateLocal();
}
get username() {
return this.json.username;
}
set localuserStore(e) {
this.json.localuserStore = e;
this.updateLocal();
}
get localuserStore() {
return this.json.localuserStore;
}
get uid() {
return this.email + this.serverurls.wellknown;
}
toJSON() {
return this.json;
}
updateLocal() {
const info = getBulkInfo();
info.users[this.uid] = this.toJSON();
localStorage.setItem("userinfos", JSON.stringify(info));
}
serverurls: {
api: string;
cdn: string;
gateway: string;
wellknown: string;
login: string;
};
email: string;
token: string;
loggedin;
json;
constructor(json: any) {
if (json instanceof Specialuser) {
console.error("specialuser can't construct from another specialuser");
}
this.serverurls = json.serverurls;
let apistring = new URL(json.serverurls.api).toString();
apistring = apistring.replace(/\/(v\d+\/?)?$/, "") + "/v9";
this.serverurls.api = apistring;
this.serverurls.cdn = new URL(json.serverurls.cdn)
.toString()
.replace(/\/$/, "");
this.serverurls.gateway = new URL(json.serverurls.gateway)
.toString()
.replace(/\/$/, "");
this.serverurls.wellknown = new URL(json.serverurls.wellknown)
.toString()
.replace(/\/$/, "");
this.serverurls.login = new URL(json.serverurls.login)
.toString()
.replace(/\/$/, "");
this.email = json.email;
this.token = json.token;
this.loggedin = json.loggedin;
this.json = json;
this.json.localuserStore ??= {};
if (!this.serverurls || !this.email || !this.token) {
console.error(
"There are fundamentally missing pieces of info missing from this user"
);
}
}
set pfpsrc(e) {
this.json.pfpsrc = e;
this.updateLocal();
}
get pfpsrc() {
return this.json.pfpsrc;
}
set username(e) {
this.json.username = e;
this.updateLocal();
}
get username() {
return this.json.username;
}
set localuserStore(e) {
this.json.localuserStore = e;
this.updateLocal();
}
get localuserStore() {
return this.json.localuserStore;
}
get uid() {
return this.email + this.serverurls.wellknown;
}
toJSON() {
return this.json;
}
updateLocal() {
const info = getBulkInfo();
info.users[this.uid] = this.toJSON();
localStorage.setItem("userinfos", JSON.stringify(info));
}
}
function adduser(user: typeof Specialuser.prototype.json) {
user = new Specialuser(user);
const info = getBulkInfo();
info.users[user.uid] = user;
info.currentuser = user.uid;
localStorage.setItem("userinfos", JSON.stringify(info));
return user;
user = new Specialuser(user);
const info = getBulkInfo();
info.users[user.uid] = user;
info.currentuser = user.uid;
localStorage.setItem("userinfos", JSON.stringify(info));
return user;
}
const instancein = document.getElementById("instancein") as HTMLInputElement;
let timeout: string | number | NodeJS.Timeout | undefined;
// let instanceinfo;
const stringURLMap = new Map<string, string>();
const stringURLsMap = new Map<
const stringURLsMap = new Map<
string,
{
wellknown: string;
@ -212,8 +212,8 @@ const stringURLsMap = new Map<
gateway: string;
login?: string;
}
>();
async function getapiurls(str: string): Promise<
>();
async function getapiurls(str: string): Promise<
| {
api: string;
cdn: string;
@ -222,7 +222,7 @@ async function getapiurls(str: string): Promise<
login: string;
}
| false
> {
> {
if (!URL.canParse(str)) {
const val = stringURLMap.get(str);
if (val) {
@ -311,8 +311,8 @@ async function getapiurls(str: string): Promise<
}
return false;
}
}
async function checkInstance(instance?: string) {
}
async function checkInstance(instance?: string) {
const verify = document.getElementById("verify");
try {
verify!.textContent = "Checking Instance";
@ -345,9 +345,9 @@ async function checkInstance(instance?: string) {
console.log("catch");
verify!.textContent = "Invalid Instance, try again";
}
}
}
if (instancein) {
if (instancein) {
console.log(instancein);
instancein.addEventListener("keydown", (_) => {
const verify = document.getElementById("verify");
@ -365,9 +365,9 @@ if (instancein) {
} else {
checkInstance("https://spacebar.chat/");
}
}
}
async function login(username: string, password: string, captcha: string) {
async function login(username: string, password: string, captcha: string) {
if (captcha === "") {
captcha = "";
}
@ -491,9 +491,9 @@ async function login(username: string, password: string, captcha: string) {
} catch (error) {
console.error("Error:", error);
}
}
}
async function check(e: SubmitEvent) {
async function check(e: SubmitEvent) {
e.preventDefault();
const target = e.target as HTMLFormElement;
const h = await login(
@ -506,16 +506,16 @@ async function check(e: SubmitEvent) {
wrongElement.textContent = h;
}
console.log(h);
}
if (document.getElementById("form")) {
}
if (document.getElementById("form")) {
const form = document.getElementById("form");
if (form) {
form.addEventListener("submit", (e: SubmitEvent) => check(e));
}
}
//this currently does not work, and need to be implemented better at some time.
/*
if ("serviceWorker" in navigator){
}
//this currently does not work, and need to be implemented better at some time.
/*
if ("serviceWorker" in navigator){
navigator.serviceWorker.register("/service.js", {
scope: "/",
}).then((registration) => {
@ -537,10 +537,10 @@ if ("serviceWorker" in navigator){
});
}
})
}
*/
const switchurl = document.getElementById("switch") as HTMLAreaElement;
if (switchurl) {
}
*/
const switchurl = document.getElementById("switch") as HTMLAreaElement;
if (switchurl) {
switchurl.href += window.location.search;
const instance = new URLSearchParams(window.location.search).get("instance");
console.log(instance);
@ -548,10 +548,10 @@ if (switchurl) {
instancein.value = instance;
checkInstance("");
}
}
export { checkInstance };
trimswitcher();
export {
}
export { checkInstance };
trimswitcher();
export {
mobile,
getBulkUsers,
getBulkInfo,
@ -559,15 +559,15 @@ export {
Specialuser,
getapiurls,
adduser,
};
};
const datalist = document.getElementById("instances");
console.warn(datalist);
export function getInstances() {
const datalist = document.getElementById("instances");
console.warn(datalist);
export function getInstances() {
return instances;
}
}
fetch("/instances.json")
fetch("/instances.json")
.then((_) => _.json())
.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";
class Member extends SnowFlake {
static already = {};
owner: Guild;
user: User;
roles: Role[] = [];
nick!: string;
[key: string]: any;
static already = {};
owner: Guild;
user: User;
roles: Role[] = [];
nick!: string;
[key: string]: any;
private constructor(memberjson: memberjson, owner: Guild) {
super(memberjson.id);
this.owner = owner;
if (this.localuser.userMap.has(memberjson.id)) {
this.user = this.localuser.userMap.get(memberjson.id) as User;
} else if (memberjson.user) {
this.user = new User(memberjson.user, owner.localuser);
} else {
throw new Error("Missing user object of this member");
}
private constructor(memberjson: memberjson, owner: Guild) {
super(memberjson.id);
this.owner = owner;
if (this.localuser.userMap.has(memberjson.id)) {
this.user = this.localuser.userMap.get(memberjson.id) as User;
} else if (memberjson.user) {
this.user = new User(memberjson.user, owner.localuser);
} else {
throw new Error("Missing user object of this member");
}
for (const key of Object.keys(memberjson)) {
if (key === "guild" || key === "owner") {
continue;
}
for (const key of Object.keys(memberjson)) {
if (key === "guild" || key === "owner") {
continue;
}
if (key === "roles") {
for (const strrole of memberjson.roles) {
const role = this.guild.roleids.get(strrole);
if (!role) continue;
this.roles.push(role);
}
continue;
}
(this as any)[key] = (memberjson as any)[key];
}
if (this.localuser.userMap.has(this?.id)) {
this.user = this.localuser.userMap.get(this?.id) as User;
}
this.roles.sort((a, b) => {
return this.guild.roles.indexOf(a) - this.guild.roles.indexOf(b);
});
}
get guild() {
return this.owner;
}
get localuser() {
return this.guild.localuser;
}
get info() {
return this.owner.info;
}
static async new(
memberjson: memberjson,
owner: Guild
): Promise<Member | undefined> {
if (key === "roles") {
for (const strrole of memberjson.roles) {
const role = this.guild.roleids.get(strrole);
if (!role) continue;
this.roles.push(role);
}
continue;
}
(this as any)[key] = (memberjson as any)[key];
}
if (this.localuser.userMap.has(this?.id)) {
this.user = this.localuser.userMap.get(this?.id) as User;
}
this.roles.sort((a, b) => {
return this.guild.roles.indexOf(a) - this.guild.roles.indexOf(b);
});
}
get guild() {
return this.owner;
}
get localuser() {
return this.guild.localuser;
}
get info() {
return this.owner.info;
}
static async new(
memberjson: memberjson,
owner: Guild
): Promise<Member | undefined> {
let user: User;
if (owner.localuser.userMap.has(memberjson.id)) {
user = owner.localuser.userMap.get(memberjson.id) as User;
@ -252,5 +252,5 @@ class Member extends SnowFlake {
}
return false;
}
}
export { Member };
}
export { Member };

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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