mirror of
https://github.com/tiramisulabs/seyfert.git
synced 2025-07-01 20:46:08 +00:00
feat: slipher
This commit is contained in:
parent
a4574c51ae
commit
07340a98bb
15
biome.json
15
biome.json
@ -4,17 +4,21 @@
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"all": true,
|
||||
"security": {
|
||||
"noGlobalEval": "off"
|
||||
},
|
||||
"suspicious": {
|
||||
"noExplicitAny": "off",
|
||||
"noAssignInExpressions": "off",
|
||||
"noUnsafeDeclarationMerging": "off",
|
||||
"noRedeclare": "off",
|
||||
"noEmptyInterface": "off",
|
||||
"noConfusingVoidType": "off",
|
||||
"noImplicitAnyLet": "off",
|
||||
"noEmptyBlockStatements": "off",
|
||||
"useAwait": "off",
|
||||
"noConsoleLog": "off"
|
||||
"noConsoleLog": "off",
|
||||
"noAsyncPromiseExecutor": "off",
|
||||
"noThenProperty": "off"
|
||||
},
|
||||
"style": {
|
||||
"noNonNullAssertion": "off",
|
||||
@ -25,11 +29,12 @@
|
||||
"useNamingConvention": "off",
|
||||
"noParameterProperties": "off",
|
||||
"useFilenamingConvention": "off",
|
||||
"noDefaultExport": "off",
|
||||
"noNamespaceImport": "off",
|
||||
"useSingleCaseStatement": "off",
|
||||
"useBlockStatements": "off",
|
||||
"useEnumInitializers": "off"
|
||||
"useEnumInitializers": "off",
|
||||
"noArguments": "off",
|
||||
"useForOf": "off"
|
||||
},
|
||||
"correctness": {
|
||||
"noUnusedVariables": "off",
|
||||
@ -43,9 +48,7 @@
|
||||
"noBannedTypes": "off",
|
||||
"noForEach": "off",
|
||||
"noUselessConstructor": "off",
|
||||
"noThisInStatic": "off",
|
||||
"noExcessiveCognitiveComplexity": "off",
|
||||
"noVoid": "off",
|
||||
"noStaticOnlyClass": "off"
|
||||
},
|
||||
"a11y": {
|
||||
|
19
package.json
19
package.json
@ -6,8 +6,7 @@
|
||||
"module": "./lib/index.js",
|
||||
"types": "./lib/index.d.ts",
|
||||
"files": [
|
||||
"lib/**",
|
||||
"deps/**"
|
||||
"lib/**"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc --outDir ./lib",
|
||||
@ -27,18 +26,15 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "1.8.3",
|
||||
"@commitlint/cli": "^19.3.0",
|
||||
"@commitlint/cli": "^19.4.0",
|
||||
"@commitlint/config-conventional": "^19.2.2",
|
||||
"@types/node": "^20.14.11",
|
||||
"husky": "^9.1.1",
|
||||
"lint-staged": "^15.2.7",
|
||||
"typescript": "^5.5.3"
|
||||
"husky": "^9.1.4",
|
||||
"lint-staged": "^15.2.9",
|
||||
"typescript": "^5.5.4"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"chokidar": "^3.6.0",
|
||||
"ioredis": "^5.4.1",
|
||||
"tweetnacl": "^1.0.3",
|
||||
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.42.0"
|
||||
"ioredis": "^5.4.1"
|
||||
},
|
||||
"homepage": "https://seyfert.dev",
|
||||
"repository": {
|
||||
@ -73,5 +69,8 @@
|
||||
"name": "David",
|
||||
"url": "https://github.com/Drylozu"
|
||||
}
|
||||
],
|
||||
"trustedDependencies": [
|
||||
"@biomejs/biome"
|
||||
]
|
||||
}
|
||||
|
219
pnpm-lock.yaml
generated
219
pnpm-lock.yaml
generated
@ -14,34 +14,25 @@ importers:
|
||||
ioredis:
|
||||
specifier: ^5.4.1
|
||||
version: 5.4.1
|
||||
tweetnacl:
|
||||
specifier: ^1.0.3
|
||||
version: 1.0.3
|
||||
uWebSockets.js:
|
||||
specifier: github:uNetworking/uWebSockets.js#v20.42.0
|
||||
version: https://codeload.github.com/uNetworking/uWebSockets.js/tar.gz/f40213ec0a97d0d8721d9d32d92d6eb6ddcd22e7
|
||||
devDependencies:
|
||||
'@biomejs/biome':
|
||||
specifier: 1.8.3
|
||||
version: 1.8.3
|
||||
'@commitlint/cli':
|
||||
specifier: ^19.3.0
|
||||
version: 19.3.0(@types/node@20.14.11)(typescript@5.5.3)
|
||||
specifier: ^19.4.0
|
||||
version: 19.4.0(@types/node@22.4.0)(typescript@5.5.4)
|
||||
'@commitlint/config-conventional':
|
||||
specifier: ^19.2.2
|
||||
version: 19.2.2
|
||||
'@types/node':
|
||||
specifier: ^20.14.11
|
||||
version: 20.14.11
|
||||
husky:
|
||||
specifier: ^9.1.1
|
||||
version: 9.1.1
|
||||
specifier: ^9.1.4
|
||||
version: 9.1.4
|
||||
lint-staged:
|
||||
specifier: ^15.2.7
|
||||
version: 15.2.7
|
||||
specifier: ^15.2.9
|
||||
version: 15.2.9
|
||||
typescript:
|
||||
specifier: ^5.5.3
|
||||
version: 5.5.3
|
||||
specifier: ^5.5.4
|
||||
version: 5.5.4
|
||||
|
||||
packages:
|
||||
|
||||
@ -110,8 +101,8 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@commitlint/cli@19.3.0':
|
||||
resolution: {integrity: sha512-LgYWOwuDR7BSTQ9OLZ12m7F/qhNY+NpAyPBgo4YNMkACE7lGuUnuQq1yi9hz1KA4+3VqpOYl8H1rY/LYK43v7g==}
|
||||
'@commitlint/cli@19.4.0':
|
||||
resolution: {integrity: sha512-sJX4J9UioVwZHq7JWM9tjT5bgWYaIN3rC4FP7YwfEwBYiIO+wMyRttRvQLNkow0vCdM0D67r9NEWU0Ui03I4Eg==}
|
||||
engines: {node: '>=v18'}
|
||||
hasBin: true
|
||||
|
||||
@ -143,8 +134,8 @@ packages:
|
||||
resolution: {integrity: sha512-xrzMmz4JqwGyKQKTpFzlN0dx0TAiT7Ran1fqEBgEmEj+PU98crOFtysJgY+QdeSagx6EDRigQIXJVnfrI0ratA==}
|
||||
engines: {node: '>=v18'}
|
||||
|
||||
'@commitlint/load@19.2.0':
|
||||
resolution: {integrity: sha512-XvxxLJTKqZojCxaBQ7u92qQLFMMZc4+p9qrIq/9kJDy8DOrEa7P1yx7Tjdc2u2JxIalqT4KOGraVgCE7eCYJyQ==}
|
||||
'@commitlint/load@19.4.0':
|
||||
resolution: {integrity: sha512-I4lCWaEZYQJ1y+Y+gdvbGAx9pYPavqZAZ3/7/8BpWh+QjscAn8AjsUpLV2PycBsEx7gupq5gM4BViV9xwTIJuw==}
|
||||
engines: {node: '>=v18'}
|
||||
|
||||
'@commitlint/message@19.0.0':
|
||||
@ -155,8 +146,8 @@ packages:
|
||||
resolution: {integrity: sha512-Il+tNyOb8VDxN3P6XoBBwWJtKKGzHlitEuXA5BP6ir/3loWlsSqDr5aecl6hZcC/spjq4pHqNh0qPlfeWu38QA==}
|
||||
engines: {node: '>=v18'}
|
||||
|
||||
'@commitlint/read@19.2.1':
|
||||
resolution: {integrity: sha512-qETc4+PL0EUv7Q36lJbPG+NJiBOGg7SSC7B5BsPWOmei+Dyif80ErfWQ0qXoW9oCh7GTpTNRoaVhiI8RbhuaNw==}
|
||||
'@commitlint/read@19.4.0':
|
||||
resolution: {integrity: sha512-r95jLOEZzKDakXtnQub+zR3xjdnrl2XzerPwm7ch1/cc5JGq04tyaNpa6ty0CRCWdVrk4CZHhqHozb8yZwy2+g==}
|
||||
engines: {node: '>=v18'}
|
||||
|
||||
'@commitlint/resolve-extends@19.1.0':
|
||||
@ -185,8 +176,8 @@ packages:
|
||||
'@types/conventional-commits-parser@5.0.0':
|
||||
resolution: {integrity: sha512-loB369iXNmAZglwWATL+WRe+CRMmmBPtpolYzIebFaX4YA3x+BEfLqhUAV9WanycKI3TG1IMr5bMJDajDKLlUQ==}
|
||||
|
||||
'@types/node@20.14.11':
|
||||
resolution: {integrity: sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==}
|
||||
'@types/node@22.4.0':
|
||||
resolution: {integrity: sha512-49AbMDwYUz7EXxKU/r7mXOsxwFr4BYbvB7tWYxVuLdb2ibd30ijjXINSMAHiEEZk5PCRBmW1gUeisn2VMKt3cQ==}
|
||||
|
||||
JSONStream@1.3.5:
|
||||
resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==}
|
||||
@ -195,9 +186,9 @@ packages:
|
||||
ajv@8.17.1:
|
||||
resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==}
|
||||
|
||||
ansi-escapes@6.2.1:
|
||||
resolution: {integrity: sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==}
|
||||
engines: {node: '>=14.16'}
|
||||
ansi-escapes@7.0.0:
|
||||
resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
ansi-regex@5.0.1:
|
||||
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||
@ -253,9 +244,9 @@ packages:
|
||||
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
|
||||
engines: {node: '>= 8.10.0'}
|
||||
|
||||
cli-cursor@4.0.0:
|
||||
resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
cli-cursor@5.0.0:
|
||||
resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
cli-truncate@4.0.0:
|
||||
resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==}
|
||||
@ -330,8 +321,8 @@ packages:
|
||||
resolution: {integrity: sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
debug@4.3.5:
|
||||
resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==}
|
||||
debug@4.3.6:
|
||||
resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==}
|
||||
engines: {node: '>=6.0'}
|
||||
peerDependencies:
|
||||
supports-color: '*'
|
||||
@ -357,6 +348,10 @@ packages:
|
||||
resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
environment@1.1.0:
|
||||
resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
error-ex@1.3.2:
|
||||
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
|
||||
|
||||
@ -427,8 +422,8 @@ packages:
|
||||
resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
|
||||
engines: {node: '>=16.17.0'}
|
||||
|
||||
husky@9.1.1:
|
||||
resolution: {integrity: sha512-fCqlqLXcBnXa/TJXmT93/A36tJsjdJkibQ1MuIiFyCCYUlpYpIaj2mv1w+3KR6Rzu1IC3slFTje5f6DUp2A2rg==}
|
||||
husky@9.1.4:
|
||||
resolution: {integrity: sha512-bho94YyReb4JV7LYWRWxZ/xr6TtOTt8cMfmQ39MQYJ7f/YE268s3GdghGwi+y4zAeqewE5zYLvuhV0M0ijsDEA==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
@ -521,13 +516,13 @@ packages:
|
||||
lines-and-columns@1.2.4:
|
||||
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
||||
|
||||
lint-staged@15.2.7:
|
||||
resolution: {integrity: sha512-+FdVbbCZ+yoh7E/RosSdqKJyUM2OEjTciH0TFNkawKgvFp1zbGlEC39RADg+xKBG1R4mhoH2j85myBQZ5wR+lw==}
|
||||
lint-staged@15.2.9:
|
||||
resolution: {integrity: sha512-BZAt8Lk3sEnxw7tfxM7jeZlPRuT4M68O0/CwZhhaw6eeWu0Lz5eERE3m386InivXB64fp/mDID452h48tvKlRQ==}
|
||||
engines: {node: '>=18.12.0'}
|
||||
hasBin: true
|
||||
|
||||
listr2@8.2.3:
|
||||
resolution: {integrity: sha512-Lllokma2mtoniUOS94CcOErHWAug5iu7HOmDrvWgpw8jyQH2fomgB+7lZS4HWZxytUuQwkGOwe49FvwVaA85Xw==}
|
||||
listr2@8.2.4:
|
||||
resolution: {integrity: sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
locate-path@7.2.0:
|
||||
@ -567,8 +562,8 @@ packages:
|
||||
lodash.upperfirst@4.3.1:
|
||||
resolution: {integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==}
|
||||
|
||||
log-update@6.0.0:
|
||||
resolution: {integrity: sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==}
|
||||
log-update@6.1.0:
|
||||
resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
meow@12.1.1:
|
||||
@ -582,14 +577,14 @@ packages:
|
||||
resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==}
|
||||
engines: {node: '>=8.6'}
|
||||
|
||||
mimic-fn@2.1.0:
|
||||
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
mimic-fn@4.0.0:
|
||||
resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
mimic-function@5.0.1:
|
||||
resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
minimist@1.2.8:
|
||||
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
|
||||
|
||||
@ -604,14 +599,14 @@ packages:
|
||||
resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
|
||||
onetime@5.1.2:
|
||||
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
onetime@6.0.0:
|
||||
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
onetime@7.0.0:
|
||||
resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
p-limit@4.0.0:
|
||||
resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
@ -680,9 +675,9 @@ packages:
|
||||
resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
restore-cursor@4.0.0:
|
||||
resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
restore-cursor@5.1.0:
|
||||
resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
rfdc@1.4.1:
|
||||
resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
|
||||
@ -700,9 +695,6 @@ packages:
|
||||
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
signal-exit@3.0.7:
|
||||
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
|
||||
|
||||
signal-exit@4.1.0:
|
||||
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
|
||||
engines: {node: '>=14'}
|
||||
@ -761,20 +753,13 @@ packages:
|
||||
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
|
||||
engines: {node: '>=8.0'}
|
||||
|
||||
tweetnacl@1.0.3:
|
||||
resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==}
|
||||
|
||||
typescript@5.5.3:
|
||||
resolution: {integrity: sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==}
|
||||
typescript@5.5.4:
|
||||
resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==}
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
|
||||
uWebSockets.js@https://codeload.github.com/uNetworking/uWebSockets.js/tar.gz/f40213ec0a97d0d8721d9d32d92d6eb6ddcd22e7:
|
||||
resolution: {tarball: https://codeload.github.com/uNetworking/uWebSockets.js/tar.gz/f40213ec0a97d0d8721d9d32d92d6eb6ddcd22e7}
|
||||
version: 20.42.0
|
||||
|
||||
undici-types@5.26.5:
|
||||
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
|
||||
undici-types@6.19.6:
|
||||
resolution: {integrity: sha512-e/vggGopEfTKSvj4ihnOLTsqhrKRN3LeO6qSN/GxohhuRv8qH9bNQ4B8W7e/vFL+0XTnmHPB4/kegunZGA4Org==}
|
||||
|
||||
unicorn-magic@0.1.0:
|
||||
resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==}
|
||||
@ -797,8 +782,8 @@ packages:
|
||||
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
yaml@2.4.5:
|
||||
resolution: {integrity: sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==}
|
||||
yaml@2.5.0:
|
||||
resolution: {integrity: sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==}
|
||||
engines: {node: '>= 14'}
|
||||
hasBin: true
|
||||
|
||||
@ -865,12 +850,12 @@ snapshots:
|
||||
'@biomejs/cli-win32-x64@1.8.3':
|
||||
optional: true
|
||||
|
||||
'@commitlint/cli@19.3.0(@types/node@20.14.11)(typescript@5.5.3)':
|
||||
'@commitlint/cli@19.4.0(@types/node@22.4.0)(typescript@5.5.4)':
|
||||
dependencies:
|
||||
'@commitlint/format': 19.3.0
|
||||
'@commitlint/lint': 19.2.2
|
||||
'@commitlint/load': 19.2.0(@types/node@20.14.11)(typescript@5.5.3)
|
||||
'@commitlint/read': 19.2.1
|
||||
'@commitlint/load': 19.4.0(@types/node@22.4.0)(typescript@5.5.4)
|
||||
'@commitlint/read': 19.4.0
|
||||
'@commitlint/types': 19.0.3
|
||||
execa: 8.0.1
|
||||
yargs: 17.7.2
|
||||
@ -916,15 +901,15 @@ snapshots:
|
||||
'@commitlint/rules': 19.0.3
|
||||
'@commitlint/types': 19.0.3
|
||||
|
||||
'@commitlint/load@19.2.0(@types/node@20.14.11)(typescript@5.5.3)':
|
||||
'@commitlint/load@19.4.0(@types/node@22.4.0)(typescript@5.5.4)':
|
||||
dependencies:
|
||||
'@commitlint/config-validator': 19.0.3
|
||||
'@commitlint/execute-rule': 19.0.0
|
||||
'@commitlint/resolve-extends': 19.1.0
|
||||
'@commitlint/types': 19.0.3
|
||||
chalk: 5.3.0
|
||||
cosmiconfig: 9.0.0(typescript@5.5.3)
|
||||
cosmiconfig-typescript-loader: 5.0.0(@types/node@20.14.11)(cosmiconfig@9.0.0(typescript@5.5.3))(typescript@5.5.3)
|
||||
cosmiconfig: 9.0.0(typescript@5.5.4)
|
||||
cosmiconfig-typescript-loader: 5.0.0(@types/node@22.4.0)(cosmiconfig@9.0.0(typescript@5.5.4))(typescript@5.5.4)
|
||||
lodash.isplainobject: 4.0.6
|
||||
lodash.merge: 4.6.2
|
||||
lodash.uniq: 4.5.0
|
||||
@ -940,7 +925,7 @@ snapshots:
|
||||
conventional-changelog-angular: 7.0.0
|
||||
conventional-commits-parser: 5.0.0
|
||||
|
||||
'@commitlint/read@19.2.1':
|
||||
'@commitlint/read@19.4.0':
|
||||
dependencies:
|
||||
'@commitlint/top-level': 19.0.0
|
||||
'@commitlint/types': 19.0.3
|
||||
@ -981,11 +966,11 @@ snapshots:
|
||||
|
||||
'@types/conventional-commits-parser@5.0.0':
|
||||
dependencies:
|
||||
'@types/node': 20.14.11
|
||||
'@types/node': 22.4.0
|
||||
|
||||
'@types/node@20.14.11':
|
||||
'@types/node@22.4.0':
|
||||
dependencies:
|
||||
undici-types: 5.26.5
|
||||
undici-types: 6.19.6
|
||||
|
||||
JSONStream@1.3.5:
|
||||
dependencies:
|
||||
@ -999,7 +984,9 @@ snapshots:
|
||||
json-schema-traverse: 1.0.0
|
||||
require-from-string: 2.0.2
|
||||
|
||||
ansi-escapes@6.2.1: {}
|
||||
ansi-escapes@7.0.0:
|
||||
dependencies:
|
||||
environment: 1.1.0
|
||||
|
||||
ansi-regex@5.0.1: {}
|
||||
|
||||
@ -1055,9 +1042,9 @@ snapshots:
|
||||
fsevents: 2.3.3
|
||||
optional: true
|
||||
|
||||
cli-cursor@4.0.0:
|
||||
cli-cursor@5.0.0:
|
||||
dependencies:
|
||||
restore-cursor: 4.0.0
|
||||
restore-cursor: 5.1.0
|
||||
|
||||
cli-truncate@4.0.0:
|
||||
dependencies:
|
||||
@ -1109,21 +1096,21 @@ snapshots:
|
||||
meow: 12.1.1
|
||||
split2: 4.2.0
|
||||
|
||||
cosmiconfig-typescript-loader@5.0.0(@types/node@20.14.11)(cosmiconfig@9.0.0(typescript@5.5.3))(typescript@5.5.3):
|
||||
cosmiconfig-typescript-loader@5.0.0(@types/node@22.4.0)(cosmiconfig@9.0.0(typescript@5.5.4))(typescript@5.5.4):
|
||||
dependencies:
|
||||
'@types/node': 20.14.11
|
||||
cosmiconfig: 9.0.0(typescript@5.5.3)
|
||||
'@types/node': 22.4.0
|
||||
cosmiconfig: 9.0.0(typescript@5.5.4)
|
||||
jiti: 1.21.6
|
||||
typescript: 5.5.3
|
||||
typescript: 5.5.4
|
||||
|
||||
cosmiconfig@9.0.0(typescript@5.5.3):
|
||||
cosmiconfig@9.0.0(typescript@5.5.4):
|
||||
dependencies:
|
||||
env-paths: 2.2.1
|
||||
import-fresh: 3.3.0
|
||||
js-yaml: 4.1.0
|
||||
parse-json: 5.2.0
|
||||
optionalDependencies:
|
||||
typescript: 5.5.3
|
||||
typescript: 5.5.4
|
||||
|
||||
cross-spawn@7.0.3:
|
||||
dependencies:
|
||||
@ -1133,7 +1120,7 @@ snapshots:
|
||||
|
||||
dargs@8.1.0: {}
|
||||
|
||||
debug@4.3.5:
|
||||
debug@4.3.6:
|
||||
dependencies:
|
||||
ms: 2.1.2
|
||||
|
||||
@ -1150,6 +1137,8 @@ snapshots:
|
||||
|
||||
env-paths@2.2.1: {}
|
||||
|
||||
environment@1.1.0: {}
|
||||
|
||||
error-ex@1.3.2:
|
||||
dependencies:
|
||||
is-arrayish: 0.2.1
|
||||
@ -1214,7 +1203,7 @@ snapshots:
|
||||
|
||||
human-signals@5.0.0: {}
|
||||
|
||||
husky@9.1.1: {}
|
||||
husky@9.1.4: {}
|
||||
|
||||
import-fresh@3.3.0:
|
||||
dependencies:
|
||||
@ -1229,7 +1218,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@ioredis/commands': 1.2.0
|
||||
cluster-key-slot: 1.1.2
|
||||
debug: 4.3.5
|
||||
debug: 4.3.6
|
||||
denque: 2.1.0
|
||||
lodash.defaults: 4.2.0
|
||||
lodash.isarguments: 3.1.0
|
||||
@ -1293,27 +1282,27 @@ snapshots:
|
||||
|
||||
lines-and-columns@1.2.4: {}
|
||||
|
||||
lint-staged@15.2.7:
|
||||
lint-staged@15.2.9:
|
||||
dependencies:
|
||||
chalk: 5.3.0
|
||||
commander: 12.1.0
|
||||
debug: 4.3.5
|
||||
debug: 4.3.6
|
||||
execa: 8.0.1
|
||||
lilconfig: 3.1.2
|
||||
listr2: 8.2.3
|
||||
listr2: 8.2.4
|
||||
micromatch: 4.0.7
|
||||
pidtree: 0.6.0
|
||||
string-argv: 0.3.2
|
||||
yaml: 2.4.5
|
||||
yaml: 2.5.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
listr2@8.2.3:
|
||||
listr2@8.2.4:
|
||||
dependencies:
|
||||
cli-truncate: 4.0.0
|
||||
colorette: 2.0.20
|
||||
eventemitter3: 5.0.1
|
||||
log-update: 6.0.0
|
||||
log-update: 6.1.0
|
||||
rfdc: 1.4.1
|
||||
wrap-ansi: 9.0.0
|
||||
|
||||
@ -1345,10 +1334,10 @@ snapshots:
|
||||
|
||||
lodash.upperfirst@4.3.1: {}
|
||||
|
||||
log-update@6.0.0:
|
||||
log-update@6.1.0:
|
||||
dependencies:
|
||||
ansi-escapes: 6.2.1
|
||||
cli-cursor: 4.0.0
|
||||
ansi-escapes: 7.0.0
|
||||
cli-cursor: 5.0.0
|
||||
slice-ansi: 7.1.0
|
||||
strip-ansi: 7.1.0
|
||||
wrap-ansi: 9.0.0
|
||||
@ -1362,10 +1351,10 @@ snapshots:
|
||||
braces: 3.0.3
|
||||
picomatch: 2.3.1
|
||||
|
||||
mimic-fn@2.1.0: {}
|
||||
|
||||
mimic-fn@4.0.0: {}
|
||||
|
||||
mimic-function@5.0.1: {}
|
||||
|
||||
minimist@1.2.8: {}
|
||||
|
||||
ms@2.1.2: {}
|
||||
@ -1377,14 +1366,14 @@ snapshots:
|
||||
dependencies:
|
||||
path-key: 4.0.0
|
||||
|
||||
onetime@5.1.2:
|
||||
dependencies:
|
||||
mimic-fn: 2.1.0
|
||||
|
||||
onetime@6.0.0:
|
||||
dependencies:
|
||||
mimic-fn: 4.0.0
|
||||
|
||||
onetime@7.0.0:
|
||||
dependencies:
|
||||
mimic-function: 5.0.1
|
||||
|
||||
p-limit@4.0.0:
|
||||
dependencies:
|
||||
yocto-queue: 1.1.1
|
||||
@ -1437,10 +1426,10 @@ snapshots:
|
||||
|
||||
resolve-from@5.0.0: {}
|
||||
|
||||
restore-cursor@4.0.0:
|
||||
restore-cursor@5.1.0:
|
||||
dependencies:
|
||||
onetime: 5.1.2
|
||||
signal-exit: 3.0.7
|
||||
onetime: 7.0.0
|
||||
signal-exit: 4.1.0
|
||||
|
||||
rfdc@1.4.1: {}
|
||||
|
||||
@ -1452,8 +1441,6 @@ snapshots:
|
||||
|
||||
shebang-regex@3.0.0: {}
|
||||
|
||||
signal-exit@3.0.7: {}
|
||||
|
||||
signal-exit@4.1.0: {}
|
||||
|
||||
slice-ansi@5.0.0:
|
||||
@ -1507,15 +1494,9 @@ snapshots:
|
||||
dependencies:
|
||||
is-number: 7.0.0
|
||||
|
||||
tweetnacl@1.0.3:
|
||||
optional: true
|
||||
typescript@5.5.4: {}
|
||||
|
||||
typescript@5.5.3: {}
|
||||
|
||||
uWebSockets.js@https://codeload.github.com/uNetworking/uWebSockets.js/tar.gz/f40213ec0a97d0d8721d9d32d92d6eb6ddcd22e7:
|
||||
optional: true
|
||||
|
||||
undici-types@5.26.5: {}
|
||||
undici-types@6.19.6: {}
|
||||
|
||||
unicorn-magic@0.1.0: {}
|
||||
|
||||
@ -1537,7 +1518,7 @@ snapshots:
|
||||
|
||||
y18n@5.0.8: {}
|
||||
|
||||
yaml@2.4.5: {}
|
||||
yaml@2.5.0: {}
|
||||
|
||||
yargs-parser@21.1.1: {}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { RESTGetAPIStickerResult, RESTGetNitroStickerPacksResult } from '../../types';
|
||||
import type { RESTGetAPIStickerResult, RESTGetStickerPacksResult } from '../../types';
|
||||
import type { ProxyRequestMethod } from '../Router';
|
||||
import type { RestArguments } from '../api';
|
||||
|
||||
@ -7,6 +7,6 @@ export interface StickerRoutes {
|
||||
get(args?: RestArguments<ProxyRequestMethod.Get>): Promise<RESTGetAPIStickerResult>;
|
||||
};
|
||||
'sticker-packs': {
|
||||
get(args?: RestArguments<ProxyRequestMethod.Get>): Promise<RESTGetNitroStickerPacksResult>;
|
||||
get(args?: RestArguments<ProxyRequestMethod.Get>): Promise<RESTGetStickerPacksResult>;
|
||||
};
|
||||
}
|
||||
|
@ -348,8 +348,7 @@ export class ApiHandler {
|
||||
const fileKey = file.key ?? `files[${index}]`;
|
||||
|
||||
if (isBufferLike(file.data)) {
|
||||
const contentType = file.contentType;
|
||||
formData.append(fileKey, new Blob([file.data], { type: contentType }), file.name);
|
||||
formData.append(fileKey, new Blob([file.data], { type: file.contentType }), file.name);
|
||||
} else {
|
||||
formData.append(fileKey, new Blob([`${file.data}`], { type: file.contentType }), file.name);
|
||||
}
|
||||
|
1
src/cache/adapters/index.ts
vendored
1
src/cache/adapters/index.ts
vendored
@ -1,5 +1,4 @@
|
||||
export * from './default';
|
||||
export * from './limited';
|
||||
export * from './redis';
|
||||
export * from './types';
|
||||
export * from './workeradapter';
|
||||
|
266
src/cache/adapters/redis.ts
vendored
266
src/cache/adapters/redis.ts
vendored
@ -1,266 +0,0 @@
|
||||
import type { RedisOptions } from 'ioredis';
|
||||
import type { Adapter } from './types';
|
||||
|
||||
let Redis: typeof import('ioredis').Redis | undefined;
|
||||
|
||||
try {
|
||||
Redis = require('ioredis').Redis;
|
||||
} catch {
|
||||
// potocuit > seyfert
|
||||
}
|
||||
|
||||
interface RedisAdapterOptions {
|
||||
namespace?: string;
|
||||
}
|
||||
|
||||
export class RedisAdapter implements Adapter {
|
||||
isAsync = true;
|
||||
|
||||
client: import('ioredis').Redis;
|
||||
namespace: string;
|
||||
|
||||
constructor(data: ({ client: import('ioredis').Redis } | { redisOptions: RedisOptions }) & RedisAdapterOptions) {
|
||||
if (!Redis) {
|
||||
throw new Error('No ioredis installed');
|
||||
}
|
||||
this.client = 'client' in data ? data.client : new Redis(data.redisOptions);
|
||||
this.namespace = data.namespace ?? 'seyfert';
|
||||
}
|
||||
|
||||
private __scanSets(query: string, returnKeys?: false): Promise<any[]>;
|
||||
private __scanSets(query: string, returnKeys: true): Promise<string[]>;
|
||||
private __scanSets(query: string, returnKeys = false) {
|
||||
const match = this.buildKey(query);
|
||||
return new Promise<string[] | any[]>((r, j) => {
|
||||
const stream = this.client.scanStream({
|
||||
match,
|
||||
type: 'set',
|
||||
});
|
||||
const keys: string[] = [];
|
||||
stream
|
||||
.on('data', resultKeys => keys.push(...resultKeys))
|
||||
.on('end', () => (returnKeys ? r(keys.map(x => this.buildKey(x))) : r(this.bulkGet(keys))))
|
||||
.on('error', err => j(err));
|
||||
});
|
||||
}
|
||||
|
||||
scan(query: string, returnKeys?: false): Promise<any[]>;
|
||||
scan(query: string, returnKeys: true): Promise<string[]>;
|
||||
scan(query: string, returnKeys = false) {
|
||||
const match = this.buildKey(query);
|
||||
return new Promise<string[] | any[]>((r, j) => {
|
||||
const stream = this.client.scanStream({
|
||||
match,
|
||||
// omit relationships
|
||||
type: 'hash',
|
||||
});
|
||||
const keys: string[] = [];
|
||||
stream
|
||||
.on('data', resultKeys => keys.push(...resultKeys))
|
||||
.on('end', () => (returnKeys ? r(keys.map(x => this.buildKey(x))) : r(this.bulkGet(keys))))
|
||||
.on('error', err => j(err));
|
||||
});
|
||||
}
|
||||
|
||||
async bulkGet(keys: string[]) {
|
||||
const pipeline = this.client.pipeline();
|
||||
|
||||
for (const key of keys) {
|
||||
pipeline.hgetall(this.buildKey(key));
|
||||
}
|
||||
|
||||
return (await pipeline.exec())?.filter(x => !!x[1]).map(x => toNormal(x[1] as Record<string, any>)) ?? [];
|
||||
}
|
||||
|
||||
async get(keys: string): Promise<any> {
|
||||
const value = await this.client.hgetall(this.buildKey(keys));
|
||||
if (value) {
|
||||
return toNormal(value);
|
||||
}
|
||||
}
|
||||
|
||||
async bulkSet(data: [string, any][]) {
|
||||
const pipeline = this.client.pipeline();
|
||||
|
||||
for (const [k, v] of data) {
|
||||
pipeline.hset(this.buildKey(k), toDb(v));
|
||||
}
|
||||
|
||||
await pipeline.exec();
|
||||
}
|
||||
|
||||
async set(id: string, data: any) {
|
||||
await this.client.hset(this.buildKey(id), toDb(data));
|
||||
}
|
||||
|
||||
async bulkPatch(updateOnly: boolean, data: [string, any][]) {
|
||||
const pipeline = this.client.pipeline();
|
||||
|
||||
for (const [k, v] of data) {
|
||||
if (updateOnly) {
|
||||
pipeline.eval(
|
||||
`if redis.call('exists',KEYS[1]) == 1 then redis.call('hset', KEYS[1], ${Array.from(
|
||||
{ length: Object.keys(v).length * 2 },
|
||||
(_, i) => `ARGV[${i + 1}]`,
|
||||
)}) end`,
|
||||
1,
|
||||
this.buildKey(k),
|
||||
...Object.entries(toDb(v)).flat(),
|
||||
);
|
||||
} else {
|
||||
pipeline.hset(this.buildKey(k), toDb(v));
|
||||
}
|
||||
}
|
||||
|
||||
await pipeline.exec();
|
||||
}
|
||||
|
||||
async patch(updateOnly: boolean, id: string, data: any): Promise<void> {
|
||||
if (updateOnly) {
|
||||
await this.client.eval(
|
||||
`if redis.call('exists',KEYS[1]) == 1 then redis.call('hset', KEYS[1], ${Array.from(
|
||||
{ length: Object.keys(data).length * 2 },
|
||||
(_, i) => `ARGV[${i + 1}]`,
|
||||
)}) end`,
|
||||
1,
|
||||
this.buildKey(id),
|
||||
...Object.entries(toDb(data)).flat(),
|
||||
);
|
||||
} else {
|
||||
await this.client.hset(this.buildKey(id), toDb(data));
|
||||
}
|
||||
}
|
||||
|
||||
async values(to: string): Promise<any[]> {
|
||||
const array: unknown[] = [];
|
||||
const data = await this.keys(to);
|
||||
if (data.length) {
|
||||
const items = await this.bulkGet(data);
|
||||
for (const item of items) {
|
||||
if (item) {
|
||||
array.push(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
async keys(to: string): Promise<string[]> {
|
||||
const data = await this.getToRelationship(to);
|
||||
return data.map(id => this.buildKey(`${to}.${id}`));
|
||||
}
|
||||
|
||||
async count(to: string): Promise<number> {
|
||||
return this.client.scard(`${this.buildKey(to)}:set`);
|
||||
}
|
||||
|
||||
async bulkRemove(keys: string[]) {
|
||||
await this.client.del(...keys.map(x => this.buildKey(x)));
|
||||
}
|
||||
|
||||
async remove(keys: string): Promise<void> {
|
||||
await this.client.del(this.buildKey(keys));
|
||||
}
|
||||
|
||||
async flush(): Promise<void> {
|
||||
const keys = await Promise.all([
|
||||
this.scan(this.buildKey('*'), true),
|
||||
this.__scanSets(this.buildKey('*'), true),
|
||||
]).then(x => x.flat());
|
||||
if (!keys.length) return;
|
||||
await this.bulkRemove(keys);
|
||||
}
|
||||
|
||||
async contains(to: string, keys: string): Promise<boolean> {
|
||||
return (await this.client.sismember(`${this.buildKey(to)}:set`, keys)) === 1;
|
||||
}
|
||||
|
||||
async getToRelationship(to: string): Promise<string[]> {
|
||||
return this.client.smembers(`${this.buildKey(to)}:set`);
|
||||
}
|
||||
|
||||
async bulkAddToRelationShip(data: Record<string, string[]>): Promise<void> {
|
||||
const pipeline = this.client.pipeline();
|
||||
|
||||
for (const [key, value] of Object.entries(data)) {
|
||||
pipeline.sadd(`${this.buildKey(key)}:set`, ...value);
|
||||
}
|
||||
|
||||
await pipeline.exec();
|
||||
}
|
||||
|
||||
async addToRelationship(to: string, keys: string | string[]): Promise<void> {
|
||||
await this.client.sadd(`${this.buildKey(to)}:set`, ...(Array.isArray(keys) ? keys : [keys]));
|
||||
}
|
||||
|
||||
async removeToRelationship(to: string, keys: string | string[]): Promise<void> {
|
||||
await this.client.srem(`${this.buildKey(to)}:set`, ...(Array.isArray(keys) ? keys : [keys]));
|
||||
}
|
||||
|
||||
async removeRelationship(to: string | string[]): Promise<void> {
|
||||
await this.client.del(
|
||||
...(Array.isArray(to) ? to.map(x => `${this.buildKey(x)}:set`) : [`${this.buildKey(to)}:set`]),
|
||||
);
|
||||
}
|
||||
|
||||
protected buildKey(key: string) {
|
||||
return key.startsWith(this.namespace) ? key : `${this.namespace}:${key}`;
|
||||
}
|
||||
}
|
||||
|
||||
const isObject = (o: unknown) => {
|
||||
return !!o && typeof o === 'object' && !Array.isArray(o);
|
||||
};
|
||||
|
||||
function toNormal(target: Record<string, any>): undefined | Record<string, any> | Record<string, any>[] {
|
||||
if (typeof target.ARRAY_OF === 'string') return JSON.parse(target.ARRAY_OF as string).map(toNormal);
|
||||
if (!Object.keys(target).length) return undefined;
|
||||
const result: Record<string, any> = {};
|
||||
for (const [key, value] of Object.entries(target)) {
|
||||
if (key.startsWith('O_')) {
|
||||
result[key.slice(2)] = JSON.parse(value);
|
||||
} else if (key.startsWith('N_')) {
|
||||
result[key.slice(2)] = Number(value);
|
||||
} else if (key.startsWith('B_')) {
|
||||
result[key.slice(2)] = value === 'true';
|
||||
} else {
|
||||
result[key] = value;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function toDb(target: Record<string, any>): Record<string, any> | Record<string, any>[] {
|
||||
if (Array.isArray(target)) return { ARRAY_OF: JSON.stringify(target.map(toDb)) };
|
||||
const result: Record<string, any> = {};
|
||||
for (const [key, value] of Object.entries(target)) {
|
||||
switch (typeof value) {
|
||||
case 'boolean':
|
||||
result[`B_${key}`] = value;
|
||||
break;
|
||||
case 'number':
|
||||
result[`N_${key}`] = `${value}`;
|
||||
break;
|
||||
case 'object':
|
||||
if (Array.isArray(value)) {
|
||||
result[`O_${key}`] = JSON.stringify(value);
|
||||
break;
|
||||
}
|
||||
if (isObject(value)) {
|
||||
result[`O_${key}`] = JSON.stringify(value);
|
||||
break;
|
||||
}
|
||||
if (!Number.isNaN(value)) {
|
||||
result[`O_${key}`] = 'null';
|
||||
break;
|
||||
}
|
||||
result[`O_${key}`] = JSON.stringify(value);
|
||||
break;
|
||||
default:
|
||||
result[key] = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
@ -282,7 +282,7 @@ export class BaseClient {
|
||||
if (!this.handleCommand) this.handleCommand = new HandleCommand(this);
|
||||
}
|
||||
|
||||
protected async onPacket(..._packet: unknown[]) {
|
||||
protected async onPacket(..._packet: unknown[]): Promise<any> {
|
||||
throw new Error('Function not implemented');
|
||||
}
|
||||
|
||||
@ -471,7 +471,6 @@ export interface StartOptions {
|
||||
httpConnection: {
|
||||
publicKey: string;
|
||||
port: number;
|
||||
useUWS: boolean;
|
||||
};
|
||||
token: string;
|
||||
}
|
||||
|
@ -1,213 +1,25 @@
|
||||
import { type APIInteractionResponse, InteractionResponseType, InteractionType, type APIInteraction } from '../types';
|
||||
import type { HttpRequest, HttpResponse } from 'uWebSockets.js';
|
||||
import type { APIInteractionResponse, APIInteraction } from '../types';
|
||||
import { isBufferLike } from '../api/utils/utils';
|
||||
import { MergeOptions, isCloudfareWorker, type DeepPartial } from '../common';
|
||||
import type { BaseClientOptions, InternalRuntimeConfigHTTP, StartOptions } from './base';
|
||||
import type { DeepPartial } from '../common';
|
||||
import type { BaseClientOptions, StartOptions } from './base';
|
||||
import { BaseClient } from './base';
|
||||
|
||||
let UWS: typeof import('uWebSockets.js') | undefined;
|
||||
let nacl: typeof import('tweetnacl') | undefined;
|
||||
|
||||
try {
|
||||
UWS = require('uWebSockets.js');
|
||||
} catch {
|
||||
// easter egg #1
|
||||
}
|
||||
|
||||
try {
|
||||
nacl = require('tweetnacl');
|
||||
} catch {
|
||||
// I always cum
|
||||
}
|
||||
|
||||
export class HttpClient extends BaseClient {
|
||||
app?: ReturnType<typeof import('uWebSockets.js').App>;
|
||||
publicKey!: string;
|
||||
publicKeyHex!: Buffer;
|
||||
|
||||
constructor(options?: BaseClientOptions) {
|
||||
super(options);
|
||||
// if (!UWS) {
|
||||
// throw new Error('No uws installed.');
|
||||
// }
|
||||
if (!nacl) {
|
||||
throw new Error('No tweetnacl installed.');
|
||||
}
|
||||
}
|
||||
|
||||
protected static readJson<T extends Record<string, any>>(res: HttpResponse) {
|
||||
return new Promise<T>((cb, err) => {
|
||||
let buffer: Buffer | undefined;
|
||||
res.onData((ab, isLast) => {
|
||||
const chunk = Buffer.from(ab);
|
||||
if (isLast) {
|
||||
let json;
|
||||
try {
|
||||
json = JSON.parse(buffer ? Buffer.concat([buffer, chunk]).toString() : chunk.toString());
|
||||
} catch (e) {
|
||||
res.close();
|
||||
return;
|
||||
}
|
||||
cb(json);
|
||||
} else {
|
||||
buffer = Buffer.concat(buffer ? [buffer, chunk] : [chunk]);
|
||||
}
|
||||
});
|
||||
|
||||
res.onAborted(err);
|
||||
});
|
||||
}
|
||||
|
||||
protected async execute(options: DeepPartial<StartOptions['httpConnection']>) {
|
||||
await super.execute();
|
||||
const {
|
||||
publicKey: publicKeyRC,
|
||||
port: portRC,
|
||||
applicationId: applicationIdRC,
|
||||
} = await this.getRC<InternalRuntimeConfigHTTP>();
|
||||
|
||||
const publicKey = options.publicKey ?? publicKeyRC;
|
||||
const port = options.port ?? portRC;
|
||||
|
||||
if (!publicKey) {
|
||||
throw new Error('Expected a publicKey, check your config file');
|
||||
}
|
||||
if (!port) {
|
||||
throw new Error('Expected a port, check your config file');
|
||||
}
|
||||
if (applicationIdRC) {
|
||||
this.applicationId = applicationIdRC;
|
||||
}
|
||||
|
||||
this.publicKey = publicKey;
|
||||
this.publicKeyHex = Buffer.from(this.publicKey, 'hex');
|
||||
if (UWS && options.useUWS) {
|
||||
this.app = UWS.App();
|
||||
this.app.post('/interactions', (res, req) => {
|
||||
return this.onPacket(res, req);
|
||||
});
|
||||
this.app.listen(port, () => {
|
||||
this.logger.info(`Listening to <url>:${port}/interactions`);
|
||||
});
|
||||
} else {
|
||||
if (options.useUWS) return this.logger.warn('No uWebSockets installed.');
|
||||
this.logger.info('Use your preferred http server and invoke <HttpClient>.fetch(<Request>) to get started');
|
||||
}
|
||||
}
|
||||
|
||||
async start(options: DeepPartial<Omit<StartOptions, 'connection' | 'eventsDir'>> = {}) {
|
||||
await super.start(options);
|
||||
return this.execute(
|
||||
MergeOptions<DeepPartial<StartOptions['httpConnection']>>({ useUWS: true }, options.httpConnection),
|
||||
);
|
||||
return this.execute(options.httpConnection ?? {});
|
||||
}
|
||||
|
||||
protected async verifySignatureGenericRequest(req: Request) {
|
||||
const timestamp = req.headers.get('x-signature-timestamp');
|
||||
const ed25519 = req.headers.get('x-signature-ed25519') ?? '';
|
||||
const body = (await req.json()) as APIInteraction;
|
||||
if (
|
||||
nacl!.sign.detached.verify(
|
||||
Buffer.from(timestamp + JSON.stringify(body)),
|
||||
Buffer.from(ed25519, 'hex'),
|
||||
this.publicKeyHex,
|
||||
)
|
||||
) {
|
||||
return body;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// https://discord.com/developers/docs/interactions/receiving-and-responding#security-and-authorization
|
||||
protected async verifySignature(res: HttpResponse, req: HttpRequest) {
|
||||
const timestamp = req.getHeader('x-signature-timestamp');
|
||||
const ed25519 = req.getHeader('x-signature-ed25519');
|
||||
const body = await HttpClient.readJson<APIInteraction>(res);
|
||||
if (
|
||||
nacl!.sign.detached.verify(
|
||||
Buffer.from(timestamp + JSON.stringify(body)),
|
||||
Buffer.from(ed25519, 'hex'),
|
||||
this.publicKeyHex,
|
||||
)
|
||||
) {
|
||||
return body;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
async fetch(req: Request): Promise<Response> {
|
||||
const rawBody = await this.verifySignatureGenericRequest(req);
|
||||
if (!rawBody) {
|
||||
this.debugger?.debug('Invalid request/No info, returning 418 status.');
|
||||
// I'm a teapot
|
||||
return new Response('', { status: 418 });
|
||||
}
|
||||
switch (rawBody.type) {
|
||||
case InteractionType.Ping:
|
||||
this.debugger?.debug('Ping interaction received, responding.');
|
||||
return Response.json(
|
||||
{ type: InteractionResponseType.Pong },
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
);
|
||||
default:
|
||||
return new Promise<Response>(r => {
|
||||
if (isCloudfareWorker())
|
||||
return this.handleCommand
|
||||
.interaction(rawBody, -1)
|
||||
.then(() => r(new Response()))
|
||||
.catch(() => r(new Response()));
|
||||
return this.handleCommand.interaction(rawBody, -1, async ({ body, files }) => {
|
||||
let response: FormData | APIInteractionResponse;
|
||||
const headers: { 'Content-Type'?: string } = {};
|
||||
|
||||
if (files) {
|
||||
response = new FormData();
|
||||
for (const [index, file] of files.entries()) {
|
||||
const fileKey = file.key ?? `files[${index}]`;
|
||||
if (isBufferLike(file.data)) {
|
||||
const contentType = file.contentType;
|
||||
response.append(fileKey, new Blob([file.data], { type: contentType }), file.name);
|
||||
} else {
|
||||
response.append(fileKey, new Blob([`${file.data}`], { type: file.contentType }), file.name);
|
||||
}
|
||||
}
|
||||
if (body) {
|
||||
response.append('payload_json', JSON.stringify(body));
|
||||
}
|
||||
} else {
|
||||
response = body ?? {};
|
||||
headers['Content-Type'] = 'application/json';
|
||||
}
|
||||
|
||||
r(
|
||||
response instanceof FormData
|
||||
? new Response(response, { headers })
|
||||
: Response.json(response, {
|
||||
headers,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected async onPacket(res: HttpResponse, req: HttpRequest) {
|
||||
const rawBody = await this.verifySignature(res, req);
|
||||
if (rawBody) {
|
||||
switch (rawBody.type) {
|
||||
case InteractionType.Ping:
|
||||
this.debugger?.debug('Ping interaction received, responding.');
|
||||
res
|
||||
.writeHeader('Content-Type', 'application/json')
|
||||
.end(JSON.stringify({ type: InteractionResponseType.Pong }));
|
||||
break;
|
||||
default:
|
||||
async onPacket(rawBody: APIInteraction): Promise<{
|
||||
headers: { 'Content-Type'?: string };
|
||||
response: APIInteractionResponse | FormData;
|
||||
}> {
|
||||
return new Promise(async r => {
|
||||
await this.handleCommand.interaction(rawBody, -1, async ({ body, files }) => {
|
||||
res.cork(() => {
|
||||
let response: FormData | APIInteractionResponse;
|
||||
const headers: { 'Content-Type'?: string } = {};
|
||||
|
||||
@ -216,8 +28,7 @@ export class HttpClient extends BaseClient {
|
||||
for (const [index, file] of files.entries()) {
|
||||
const fileKey = file.key ?? `files[${index}]`;
|
||||
if (isBufferLike(file.data)) {
|
||||
const contentType = file.contentType;
|
||||
response.append(fileKey, new Blob([file.data], { type: contentType }), file.name);
|
||||
response.append(fileKey, new Blob([file.data], { type: file.contentType }), file.name);
|
||||
} else {
|
||||
response.append(fileKey, new Blob([`${file.data}`], { type: file.contentType }), file.name);
|
||||
}
|
||||
@ -230,19 +41,11 @@ export class HttpClient extends BaseClient {
|
||||
headers['Content-Type'] = 'application/json';
|
||||
}
|
||||
|
||||
for (const i in headers) {
|
||||
res.writeHeader(i, headers[i as keyof typeof headers]!);
|
||||
}
|
||||
|
||||
return res.end(JSON.stringify(response));
|
||||
return r({
|
||||
headers,
|
||||
response,
|
||||
});
|
||||
});
|
||||
});
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
this.debugger?.debug('Invalid request/No info, returning 418 status.');
|
||||
// I'm a teapot
|
||||
res.writeStatus('418').end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
6
src/client/types.ts
Normal file
6
src/client/types.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import type { HttpClient } from './httpclient';
|
||||
|
||||
export interface HttpServerAdapter {
|
||||
client: HttpClient;
|
||||
start?(path: `/${string}`): any;
|
||||
}
|
@ -298,7 +298,6 @@ export class WorkerClient<Ready extends boolean = boolean> extends BaseClient {
|
||||
{
|
||||
let result;
|
||||
try {
|
||||
// biome-ignore lint/security/noGlobalEval: yes
|
||||
result = await eval(`
|
||||
(${data.func})(this)
|
||||
`);
|
||||
|
@ -161,17 +161,14 @@ export class BaseCommand {
|
||||
const option = this.options!.find(x => x.name === i.name) as __CommandOption;
|
||||
const value =
|
||||
resolver.getHoisted(i.name)?.value !== undefined
|
||||
? await new Promise(
|
||||
// biome-ignore lint/suspicious/noAsyncPromiseExecutor: yes
|
||||
async (res, rej) => {
|
||||
? await new Promise(async (res, rej) => {
|
||||
try {
|
||||
(await option.value?.({ context: ctx, value: resolver.getValue(i.name) } as never, res, rej)) ||
|
||||
res(resolver.getValue(i.name));
|
||||
} catch (e) {
|
||||
rej(e);
|
||||
}
|
||||
},
|
||||
)
|
||||
})
|
||||
: undefined;
|
||||
if (value === undefined) {
|
||||
if (option.required) {
|
||||
@ -226,8 +223,6 @@ export class BaseCommand {
|
||||
if (!running) {
|
||||
return;
|
||||
}
|
||||
// biome-ignore lint/style/noArguments: yes
|
||||
// biome-ignore lint/correctness/noUndeclaredVariables: xd
|
||||
if (arguments.length) {
|
||||
// @ts-expect-error
|
||||
context[global ? 'globalMetadata' : 'metadata'][middlewares[index]] = obj;
|
||||
|
@ -52,9 +52,9 @@ export class Logger {
|
||||
|
||||
static async clearLogs() {
|
||||
for (const i of await promises.readdir(join(process.cwd(), Logger.dirname), { withFileTypes: true })) {
|
||||
if (this.streams[i.name]) await new Promise(res => this.streams[i.name]!.close(res));
|
||||
if (Logger.streams[i.name]) await new Promise(res => Logger.streams[i.name]!.close(res));
|
||||
await promises.unlink(join(process.cwd(), Logger.dirname, i.name)).catch(() => {});
|
||||
delete this.streams[i.name];
|
||||
delete Logger.streams[i.name];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,7 +247,6 @@ export async function magicImport(path: string) {
|
||||
try {
|
||||
return require(path);
|
||||
} catch {
|
||||
// biome-ignore lint/security/noGlobalEval: modules import broke
|
||||
return eval('((path) => import(`file:///${path}?update=${Date.now()}`))')(path.split('\\').join('\\\\'));
|
||||
}
|
||||
}
|
||||
@ -261,7 +260,6 @@ export function fakePromise<T = unknown | Promise<unknown>>(
|
||||
} {
|
||||
if (value instanceof Promise) return value as any;
|
||||
return {
|
||||
// biome-ignore lint/suspicious/noThenProperty: magic
|
||||
then: callback => callback(value as Awaited<T>),
|
||||
};
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ export class MessageShorter extends BaseShorter {
|
||||
.delete({ reason })
|
||||
.then(async () => {
|
||||
await this.client.cache.messages?.removeIfNI('GuildMessages', messageId, channelId);
|
||||
void this.client.components?.onMessageDelete(messageId);
|
||||
this.client.components?.onMessageDelete(messageId);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -54,8 +54,7 @@ import type {
|
||||
MessageWebhookCreateBodyRequest,
|
||||
ModalCreateBodyRequest,
|
||||
} from '../common';
|
||||
import type { AllChannels } from './';
|
||||
import channelFrom from './channels';
|
||||
import { channelFrom, type AllChannels } from './';
|
||||
import { DiscordBase } from './extra/DiscordBase';
|
||||
import { PermissionsBitField } from './extra/Permissions';
|
||||
import {
|
||||
@ -78,7 +77,6 @@ export type ReplyInteractionBody =
|
||||
}
|
||||
| Exclude<RESTPostAPIInteractionCallbackJSONBody, APIInteractionResponsePong>;
|
||||
|
||||
/** @internal */
|
||||
export type __InternalReplyFunction = (_: { body: APIInteractionResponse; files?: RawFile[] }) => Promise<any>;
|
||||
|
||||
export interface BaseInteraction
|
||||
|
@ -310,7 +310,7 @@ export interface TextBaseGuildChannel
|
||||
@mix(MessagesMethods)
|
||||
export class TextBaseGuildChannel extends BaseGuildChannel {}
|
||||
|
||||
export default function channelFrom(data: APIChannelBase<ChannelType>, client: UsingClient): AllChannels {
|
||||
export function channelFrom(data: APIChannelBase<ChannelType>, client: UsingClient): AllChannels {
|
||||
switch (data.type) {
|
||||
case ChannelType.GuildStageVoice:
|
||||
return Transformers.StageChannel(client, data);
|
||||
|
@ -103,15 +103,15 @@ export class Shard {
|
||||
// biome-ignore lint/correctness/noUndeclaredVariables: /\ bun lol
|
||||
this.websocket = new BaseSocket(typeof Bun === 'undefined' ? 'ws' : 'bun', this.currentGatewayURL);
|
||||
|
||||
this.websocket!.onmessage = ({ data }: { data: string | Buffer }) => {
|
||||
this.websocket.onmessage = ({ data }: { data: string | Buffer }) => {
|
||||
this.handleMessage(data);
|
||||
};
|
||||
|
||||
this.websocket!.onclose = (event: { code: number; reason: string }) => this.handleClosed(event);
|
||||
this.websocket.onclose = (event: { code: number; reason: string }) => this.handleClosed(event);
|
||||
|
||||
this.websocket!.onerror = (event: ErrorEvent) => this.debugger?.error(event);
|
||||
this.websocket.onerror = (event: ErrorEvent) => this.debugger?.error(event);
|
||||
|
||||
this.websocket!.onopen = () => {
|
||||
this.websocket.onopen = () => {
|
||||
this.heart.ack = true;
|
||||
};
|
||||
}
|
||||
|
@ -261,7 +261,7 @@ export class SeyfertWebSocket {
|
||||
* @returns
|
||||
*/
|
||||
|
||||
private readBytes(start: number, bits: number) {
|
||||
private readBytes(start: number, bits: number): number {
|
||||
// @ts-expect-error this is private, thanks nodejs
|
||||
const readable = this.socket._readableState as
|
||||
| {
|
||||
@ -286,7 +286,6 @@ export class SeyfertWebSocket {
|
||||
// Buffer to read
|
||||
let block;
|
||||
while ((block = readable.buffer[blockIndex++])) {
|
||||
// biome-ignore lint/style/useForOf: why we use biome
|
||||
for (let i = 0; i < block.length; i++) {
|
||||
if (++bitIndex > start) {
|
||||
value *= 256; // shift 8 bits (1 byte) `*= 256 is faster than <<= 8`
|
||||
@ -302,7 +301,6 @@ export class SeyfertWebSocket {
|
||||
// readable.buffer is kinda a LinkedList
|
||||
let head: ReadableHeadData | undefined = readable.buffer.head;
|
||||
while (head) {
|
||||
// biome-ignore lint/style/useForOf: why we use biome
|
||||
for (let i = 0; i < head.data.length; i++) {
|
||||
if (++bitIndex > start) {
|
||||
value *= 256; // shift 8 bits (1 byte) `*= 256 is faster than <<= 8`
|
||||
@ -317,7 +315,8 @@ export class SeyfertWebSocket {
|
||||
head = head.next;
|
||||
}
|
||||
}
|
||||
throw new Error('Unexpected error, not enough bytes');
|
||||
console.log(readable, 'Unexpected error, not enough bytes');
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ export class DynamicBucket {
|
||||
acquire(force = false) {
|
||||
return new Promise(res => {
|
||||
this.queue[force ? 'unshift' : 'push'](res);
|
||||
void this.processQueue();
|
||||
this.processQueue();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
"noUnusedParameters": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"skipLibCheck": false,
|
||||
"skipLibCheck": true,
|
||||
"noErrorTruncation": true,
|
||||
"outDir": "./lib",
|
||||
"stripInternal": true,
|
||||
|
Loading…
x
Reference in New Issue
Block a user