From 34f57b96dcfb146a7e48c40b5f3662c8bc017dbb Mon Sep 17 00:00:00 2001 From: Bradley Bickford Date: Wed, 12 Nov 2025 20:41:13 -0500 Subject: [PATCH 1/4] Large swathes of re-engineering --- .gitignore | 2 + package-lock.json | 1339 +++++++++++++++-- package.json | 18 +- src/breadbot.ts | 57 +- src/commands/breadthread.ts | 1 + src/utilties/discord/channels.ts | 49 +- src/utilties/discord/guilds.ts | 30 +- src/utilties/discord/roles.ts | 70 +- src/utilties/discord/voice.ts | 20 + src/utilties/events/messages.ts | 1 + src/utilties/events/roles.ts | 17 +- src/utilties/events/voice.ts | 19 + src/utilties/storage/entities/DBChannel.ts | 27 + src/utilties/storage/entities/DBMessage.ts | 28 + .../entities/DBMessageContentChanges.ts | 17 + src/utilties/storage/entities/DBRole.ts | 17 + src/utilties/storage/entities/DBServer.ts | 21 + src/utilties/storage/entities/DBUser.ts | 17 + src/utilties/storage/tables.ts | 4 - tsconfig.json | 9 +- 20 files changed, 1567 insertions(+), 196 deletions(-) create mode 100644 src/utilties/storage/entities/DBChannel.ts create mode 100644 src/utilties/storage/entities/DBMessage.ts create mode 100644 src/utilties/storage/entities/DBMessageContentChanges.ts create mode 100644 src/utilties/storage/entities/DBRole.ts create mode 100644 src/utilties/storage/entities/DBServer.ts create mode 100644 src/utilties/storage/entities/DBUser.ts diff --git a/.gitignore b/.gitignore index 7d87b3f..1bf5102 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ node_modules +dist +breadbot.db .env tools/profanity_filter/bin/Words.json tools/profanity_filter/src/Words.json \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 06528a8..5386e75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,16 +9,47 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@discordjs/opus": "^0.9.0", + "@discordjs/voice": "^0.18.0", "discord.js": "^14.20.0", "dotenv": "^16.5.0", - "sqlite3": "^5.1.7" + "libsodium-wrappers": "^0.7.13", + "node-crc": "1.3.2", + "prism-media": "^2.0.0-alpha.0", + "reflect-metadata": "^0.2.2", + "sqlite3": "^5.1.7", + "ts-node": "^10.9.2", + "typeorm": "^0.3.27" }, "devDependencies": { + "@types/node": "^24.10.0", "tsup": "^8.5.0", "tsx": "^4.20.3", "typescript": "^5.8.3" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@discordjs/builders": { "version": "1.11.2", "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.11.2.tgz", @@ -64,6 +95,141 @@ "url": "https://github.com/discordjs/discord.js?sponsor" } }, + "node_modules/@discordjs/node-pre-gyp": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@discordjs/node-pre-gyp/-/node-pre-gyp-0.4.5.tgz", + "integrity": "sha512-YJOVVZ545x24mHzANfYoy0BJX5PDyeZlpiJjDkUBM/V/Ao7TFX9lcUvCN4nr0tbr5ubeaXxtEBILUrHtTphVeQ==", + "license": "BSD-3-Clause", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@discordjs/node-pre-gyp/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@discordjs/node-pre-gyp/node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@discordjs/node-pre-gyp/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/@discordjs/node-pre-gyp/node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@discordjs/node-pre-gyp/node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/@discordjs/node-pre-gyp/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/@discordjs/node-pre-gyp/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@discordjs/node-pre-gyp/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@discordjs/opus": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@discordjs/opus/-/opus-0.9.0.tgz", + "integrity": "sha512-NEE76A96FtQ5YuoAVlOlB3ryMPrkXbUCTQICHGKb8ShtjXyubGicjRMouHtP1RpuDdm16cDa+oI3aAMo1zQRUQ==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@discordjs/node-pre-gyp": "^0.4.5", + "node-addon-api": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@discordjs/opus/node_modules/node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", + "license": "MIT" + }, "node_modules/@discordjs/rest": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.5.1.tgz", @@ -111,6 +277,57 @@ "url": "https://github.com/discordjs/discord.js?sponsor" } }, + "node_modules/@discordjs/voice": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@discordjs/voice/-/voice-0.18.0.tgz", + "integrity": "sha512-BvX6+VJE5/vhD9azV9vrZEt9hL1G+GlOdsQaVl5iv9n87fkXjf3cSwllhR3GdaUC8m6dqT8umXIWtn3yCu4afg==", + "license": "Apache-2.0", + "dependencies": { + "@types/ws": "^8.5.12", + "discord-api-types": "^0.37.103", + "prism-media": "^1.3.5", + "tslib": "^2.6.3", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/discordjs/discord.js?sponsor" + } + }, + "node_modules/@discordjs/voice/node_modules/discord-api-types": { + "version": "0.37.120", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.120.tgz", + "integrity": "sha512-7xpNK0EiWjjDFp2nAhHXezE4OUWm7s1zhc/UXXN6hnFFU8dfoPHgV0Hx0RPiCa3ILRpdeh152icc68DGCyXYIw==", + "license": "MIT" + }, + "node_modules/@discordjs/voice/node_modules/prism-media": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.3.5.tgz", + "integrity": "sha512-IQdl0Q01m4LrkN1EGIE9lphov5Hy7WWlH6ulf5QdGePLlPas9p2mhgddTEHrlaXYjjFToM1/rWuwF37VF4taaA==", + "license": "Apache-2.0", + "peerDependencies": { + "@discordjs/opus": ">=0.8.0 <1.0.0", + "ffmpeg-static": "^5.0.2 || ^4.2.7 || ^3.0.0 || ^2.4.0", + "node-opus": "^0.3.3", + "opusscript": "^0.0.8" + }, + "peerDependenciesMeta": { + "@discordjs/opus": { + "optional": true + }, + "ffmpeg-static": { + "optional": true + }, + "node-opus": { + "optional": true + }, + "opusscript": { + "optional": true + } + } + }, "node_modules/@discordjs/ws": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.2.3.tgz", @@ -582,7 +799,6 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, "license": "ISC", "dependencies": { "string-width": "^5.1.2", @@ -615,7 +831,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -635,7 +850,6 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { @@ -679,7 +893,6 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, "license": "MIT", "optional": true, "engines": { @@ -999,6 +1212,12 @@ "npm": ">=7.0.0" } }, + "node_modules/@sqltools/formatter": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", + "integrity": "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==", + "license": "MIT" + }, "node_modules/@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -1009,6 +1228,30 @@ "node": ">= 6" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1017,12 +1260,12 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.0.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.3.tgz", - "integrity": "sha512-R4I/kzCYAdRLzfiCabn9hxWfbuHS573x+r0dJMkkzThEa7pbrcDWK+9zu3e7aBOouf+rQAciqPFMnxwr0aWgKg==", + "version": "24.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz", + "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==", "license": "MIT", "dependencies": { - "undici-types": "~7.8.0" + "undici-types": "~7.16.0" } }, "node_modules/@types/ws": { @@ -1048,14 +1291,12 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -1064,12 +1305,23 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "license": "MIT", - "optional": true, "dependencies": { "debug": "4" }, @@ -1108,7 +1360,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -1121,7 +1372,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -1130,6 +1380,15 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/ansis": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-3.17.0.tgz", + "integrity": "sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg==", + "license": "ISC", + "engines": { + "node": ">=14" + } + }, "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", @@ -1137,12 +1396,20 @@ "dev": true, "license": "MIT" }, + "node_modules/app-root-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz", + "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/are-we-there-yet": { "version": "3.0.1", @@ -1159,11 +1426,31 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "license": "MIT" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "devOptional": true, "license": "MIT" }, "node_modules/base64-js": { @@ -1210,7 +1497,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -1368,6 +1654,53 @@ "node": ">=8" } }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/chokidar": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", @@ -1403,11 +1736,97 @@ "node": ">=6" } }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -1420,7 +1839,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, "license": "MIT" }, "node_modules/color-support": { @@ -1428,7 +1846,6 @@ "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", "license": "ISC", - "optional": true, "bin": { "color-support": "bin.js" } @@ -1447,8 +1864,7 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/confbox": { "version": "0.1.8", @@ -1471,14 +1887,18 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "license": "ISC", - "optional": true + "license": "ISC" + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -1489,11 +1909,16 @@ "node": ">= 8" } }, + "node_modules/dayjs": { + "version": "1.11.19", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz", + "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==", + "license": "MIT" + }, "node_modules/debug": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "devOptional": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -1522,6 +1947,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/dedent": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", + "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -1531,12 +1970,28 @@ "node": ">=4.0.0" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/detect-libc": { "version": "2.0.4", @@ -1547,6 +2002,15 @@ "node": ">=8" } }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/discord-api-types": { "version": "0.38.12", "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.12.tgz", @@ -1595,18 +2059,36 @@ "url": "https://dotenvx.com" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplex-child-process": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/duplex-child-process/-/duplex-child-process-1.0.1.tgz", + "integrity": "sha512-tWbt4tyioDjyK5nh+qicbdvBvNjSXsTUF5zKUwSauuKPg1mokjwn/HezwfvWhh6hXoLdgetY+ZlzU/sMwUMJkg==", + "license": "MIT" + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, "license": "MIT" }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, "license": "MIT" }, "node_modules/encoding": { @@ -1645,6 +2127,36 @@ "license": "MIT", "optional": true }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/esbuild": { "version": "0.25.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", @@ -1686,6 +2198,15 @@ "@esbuild/win32-x64": "0.25.5" } }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -1734,11 +2255,25 @@ "rollup": "^4.34.8" } }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/foreground-child": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "dev": true, "license": "ISC", "dependencies": { "cross-spawn": "^7.0.6", @@ -1785,8 +2320,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", @@ -1803,6 +2337,15 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gauge": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", @@ -1876,6 +2419,52 @@ "node": ">=8" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-tsconfig": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", @@ -1899,7 +2488,6 @@ "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -1916,6 +2504,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -1923,12 +2523,62 @@ "license": "ISC", "optional": true }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "license": "ISC", - "optional": true + "license": "ISC" + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } }, "node_modules/http-cache-semantics": { "version": "4.2.0", @@ -1957,7 +2607,6 @@ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "license": "MIT", - "optional": true, "dependencies": { "agent-base": "6", "debug": "4" @@ -2042,7 +2691,6 @@ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "license": "ISC", - "optional": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -2074,11 +2722,22 @@ "node": ">= 12" } }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -2091,18 +2750,37 @@ "license": "MIT", "optional": true }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "devOptional": true, "license": "ISC" }, "node_modules/jackspeak": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -2131,6 +2809,21 @@ "license": "MIT", "optional": true }, + "node_modules/libsodium": { + "version": "0.7.15", + "resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.15.tgz", + "integrity": "sha512-sZwRknt/tUpE2AwzHq3jEyUU5uvIZHtSssktXq7owd++3CSgn8RGrv6UZJJBpP7+iBghBqe7Z06/2M31rI2NKw==", + "license": "ISC" + }, + "node_modules/libsodium-wrappers": { + "version": "0.7.15", + "resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.15.tgz", + "integrity": "sha512-E4anqJQwcfiC6+Yrl01C1m8p99wEhLmJSs0VQqST66SbQXXBoaJY0pF4BNjRYa/sOQAxx6lXAaAFIlx+15tXJQ==", + "license": "ISC", + "dependencies": { + "libsodium": "^0.7.15" + } + }, "node_modules/lilconfig": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", @@ -2184,7 +2877,6 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, "license": "ISC" }, "node_modules/magic-bytes.js": { @@ -2203,6 +2895,36 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "license": "ISC" + }, "node_modules/make-fetch-happen": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", @@ -2257,6 +2979,15 @@ "node": ">=8" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/mimic-response": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", @@ -2273,7 +3004,6 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -2298,7 +3028,6 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" @@ -2499,7 +3228,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "devOptional": true, "license": "MIT" }, "node_modules/mz": { @@ -2548,6 +3276,68 @@ "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", "license": "MIT" }, + "node_modules/node-crc": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/node-crc/-/node-crc-1.3.2.tgz", + "integrity": "sha512-1ipluqUEawnH1SVUz3JvnHqHaKbjTW5Mz/4lnvSU4fEmvfw9NU4DcTtCU8j2atk9p4P1TzyDKjo7YxVIKGTGdg==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@types/node": "^15.6.1", + "bindings": "^1.3.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/node-crc/node_modules/@types/node": { + "version": "15.14.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.14.9.tgz", + "integrity": "sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A==", + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-gyp": { "version": "8.4.1", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", @@ -2624,7 +3414,6 @@ "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", "license": "ISC", - "optional": true, "dependencies": { "abbrev": "1" }, @@ -2656,7 +3445,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -2691,7 +3479,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, "license": "BlueOak-1.0.0" }, "node_modules/path-is-absolute": { @@ -2699,7 +3486,6 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } @@ -2708,7 +3494,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -2718,7 +3503,6 @@ "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", @@ -2780,6 +3564,15 @@ "pathe": "^2.0.1" } }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/postcss-load-config": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", @@ -2849,6 +3642,15 @@ "node": ">=10" } }, + "node_modules/prism-media": { + "version": "2.0.0-alpha.0", + "resolved": "https://registry.npmjs.org/prism-media/-/prism-media-2.0.0-alpha.0.tgz", + "integrity": "sha512-QL9rnO4xo0grgj7ptsA+AzSCYLirGWM4+ZcyboFmbkYHSgaXIESzHq/SXNizz2iHIfuM2og0cPhmSnTVMeFjKg==", + "license": "Apache-2.0", + "dependencies": { + "duplex-child-process": "^1.0.1" + } + }, "node_modules/promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", @@ -2933,6 +3735,21 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "license": "Apache-2.0" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -2969,7 +3786,6 @@ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", "license": "ISC", - "optional": true, "dependencies": { "glob": "^7.1.3" }, @@ -2985,7 +3801,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "license": "MIT", - "optional": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2997,7 +3812,6 @@ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", "license": "ISC", - "optional": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -3018,7 +3832,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "license": "ISC", - "optional": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -3109,14 +3922,49 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "license": "ISC", - "optional": true + "license": "ISC" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/sha.js": { + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" + }, + "bin": { + "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -3129,7 +3977,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3139,7 +3986,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, "license": "ISC", "engines": { "node": ">=14" @@ -3254,6 +4100,22 @@ "license": "BSD-3-Clause", "optional": true }, + "node_modules/sql-highlight": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/sql-highlight/-/sql-highlight-6.1.0.tgz", + "integrity": "sha512-ed7OK4e9ywpE7pgRMkMQmZDPKSVdm0oX5IEtZiKnFucSF0zu6c80GZBe38UqHuVhTWJ9xsKgSMjCG2bml86KvA==", + "funding": [ + "https://github.com/scriptcoded/sql-highlight?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/scriptcoded" + } + ], + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/sqlite3": { "version": "5.1.7", "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.7.tgz", @@ -3317,7 +4179,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", @@ -3336,7 +4197,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -3351,7 +4211,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3361,14 +4220,12 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, "license": "MIT" }, "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -3381,7 +4238,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -3398,7 +4254,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -3411,7 +4266,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3556,6 +4410,20 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/to-buffer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", + "license": "MIT", + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/tr46": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", @@ -3589,6 +4457,49 @@ "integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==", "license": "MIT" }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -3680,11 +4591,150 @@ "node": "*" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typeorm": { + "version": "0.3.27", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.27.tgz", + "integrity": "sha512-pNV1bn+1n8qEe8tUNsNdD8ejuPcMAg47u2lUGnbsajiNUr3p2Js1XLKQjBMH0yMRMDfdX8T+fIRejFmIwy9x4A==", + "license": "MIT", + "dependencies": { + "@sqltools/formatter": "^1.2.5", + "ansis": "^3.17.0", + "app-root-path": "^3.1.0", + "buffer": "^6.0.3", + "dayjs": "^1.11.13", + "debug": "^4.4.0", + "dedent": "^1.6.0", + "dotenv": "^16.4.7", + "glob": "^10.4.5", + "sha.js": "^2.4.12", + "sql-highlight": "^6.0.0", + "tslib": "^2.8.1", + "uuid": "^11.1.0", + "yargs": "^17.7.2" + }, + "bin": { + "typeorm": "cli.js", + "typeorm-ts-node-commonjs": "cli-ts-node-commonjs.js", + "typeorm-ts-node-esm": "cli-ts-node-esm.js" + }, + "engines": { + "node": ">=16.13.0" + }, + "funding": { + "url": "https://opencollective.com/typeorm" + }, + "peerDependencies": { + "@google-cloud/spanner": "^5.18.0 || ^6.0.0 || ^7.0.0", + "@sap/hana-client": "^2.14.22", + "better-sqlite3": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0", + "ioredis": "^5.0.4", + "mongodb": "^5.8.0 || ^6.0.0", + "mssql": "^9.1.1 || ^10.0.1 || ^11.0.1", + "mysql2": "^2.2.5 || ^3.0.1", + "oracledb": "^6.3.0", + "pg": "^8.5.1", + "pg-native": "^3.0.0", + "pg-query-stream": "^4.0.0", + "redis": "^3.1.1 || ^4.0.0 || ^5.0.14", + "reflect-metadata": "^0.1.14 || ^0.2.0", + "sql.js": "^1.4.0", + "sqlite3": "^5.0.3", + "ts-node": "^10.7.0", + "typeorm-aurora-data-api-driver": "^2.0.0 || ^3.0.0" + }, + "peerDependenciesMeta": { + "@google-cloud/spanner": { + "optional": true + }, + "@sap/hana-client": { + "optional": true + }, + "better-sqlite3": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "mongodb": { + "optional": true + }, + "mssql": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "oracledb": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-native": { + "optional": true + }, + "pg-query-stream": { + "optional": true + }, + "redis": { + "optional": true + }, + "sql.js": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "ts-node": { + "optional": true + }, + "typeorm-aurora-data-api-driver": { + "optional": true + } + } + }, + "node_modules/typeorm/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/typescript": { "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -3711,9 +4761,9 @@ } }, "node_modules/undici-types": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", - "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "license": "MIT" }, "node_modules/unique-filename": { @@ -3742,6 +4792,25 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "license": "MIT" + }, "node_modules/webidl-conversions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", @@ -3765,7 +4834,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "devOptional": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -3777,12 +4845,32 @@ "node": ">= 8" } }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", "license": "ISC", - "optional": true, "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } @@ -3792,7 +4880,6 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", - "optional": true, "engines": { "node": ">=8" } @@ -3801,15 +4888,13 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/wide-align/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "license": "MIT", - "optional": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -3824,7 +4909,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", - "optional": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -3836,7 +4920,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", @@ -3855,7 +4938,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -3873,7 +4955,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3883,7 +4964,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -3899,14 +4979,12 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, "license": "MIT" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -3921,7 +4999,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -3957,11 +5034,97 @@ } } }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } } } } diff --git a/package.json b/package.json index 5d5b8be..42f6aeb 100644 --- a/package.json +++ b/package.json @@ -3,25 +3,27 @@ "version": "1.0.0", "main": "breadbot.ts", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "dev": "tsx watch src/breadbot.ts", - "start": "node dist/breadbot.js", - "build": "tsup src/breadbot.ts --minify" + "watch": "tsc -w", + "start": "tsc && node dist/breadbot.js", + "typeorm": "./node_modules/.bin/typeorm" }, "author": "", "license": "ISC", "description": "", "dependencies": { + "@discordjs/opus": "^0.9.0", + "@discordjs/voice": "^0.18.0", "discord.js": "^14.20.0", "dotenv": "^16.5.0", - "sqlite3": "^5.1.7", - "@discordjs/opus": "^0.9.0", - "@discordjs/voice": "^0.16.0", "libsodium-wrappers": "^0.7.13", "node-crc": "1.3.2", - "prism-media": "^2.0.0-alpha.0" + "prism-media": "^2.0.0-alpha.0", + "reflect-metadata": "^0.2.2", + "sqlite3": "^5.1.7", + "typeorm": "^0.3.27" }, "devDependencies": { + "@types/node": "^24.10.0", "tsup": "^8.5.0", "tsx": "^4.20.3", "typescript": "^5.8.3" diff --git a/src/breadbot.ts b/src/breadbot.ts index ce926f2..25a71a3 100644 --- a/src/breadbot.ts +++ b/src/breadbot.ts @@ -1,8 +1,26 @@ -import { CacheType, ChatInputCommandInteraction, Client, Events, GatewayIntentBits, Guild, GuildBasedChannel, Interaction, Role } from "discord.js" -import { utilities } from "./utilties" -import { commands } from "./commands" +import "reflect-metadata" +import { Client, Events, GatewayIntentBits, Guild, GuildBasedChannel, Role } from "discord.js" import { config } from "./config" -import { SQLCommon } from "./utilties/storage/interfaces" +import { DataSource } from "typeorm" +import { DBServer } from "./utilties/storage/entities/DBServer" +import path from "path" +import { DBChannel } from "./utilties/storage/entities/DBChannel" +import { DBRole } from "./utilties/storage/entities/DBRole" +import { insertGuild } from "./utilties/discord/guilds" +import { insertChannel } from "./utilties/discord/channels" +import { insertRole } from "./utilties/discord/roles" +import { setupRoleCapture } from "./utilties/events/roles" +import { DBUser } from "./utilties/storage/entities/DBUser" + +console.log(__dirname + path.sep + "utilities" + path.sep + "storage" + path.sep + "entities" + path.sep + "*.ts") + +export const dataSource = new DataSource({ + type: "sqlite", + database: "breadbot.db", + entities: [DBServer, DBChannel, DBRole, DBUser], + synchronize: true, + logging: true +}) export const client : Client = new Client({ intents: [ @@ -14,6 +32,35 @@ export const client : Client = new Client({ ] }) +client.once(Events.ClientReady, async () => { + await dataSource.initialize() + + const serverRepo = dataSource.getRepository(DBServer) + const channelRepo = dataSource.getRepository(DBChannel) + const roleRepo = dataSource.getRepository(DBRole) + + client.guilds.cache.forEach(async (guild: Guild) => { + const server: DBServer | null = await insertGuild(serverRepo, guild) + + if (server != null) { + guild.channels.cache.forEach(async (channel: GuildBasedChannel) => { + await insertChannel(channelRepo, channel) + }) + + guild.roles.cache.forEach(async (role: Role) => { + await insertRole(roleRepo, role) + }) + } + }) + + setupRoleCapture(client, serverRepo, roleRepo) + + console.log("Breadbot is Ready") +}) + +client.login(config.DISCORD_TOKEN) + +/* export let db: SQLCommon if (config.DB_MODE == "sqlite") { @@ -82,4 +129,4 @@ setInterval(async () => { await utilities.breadthread.breadthreadProcessLocks(db, client) }, 5000) -client.login(config.DISCORD_TOKEN) \ No newline at end of file +client.login(config.DISCORD_TOKEN)*/ \ No newline at end of file diff --git a/src/commands/breadthread.ts b/src/commands/breadthread.ts index 6a3645d..cd84bf5 100644 --- a/src/commands/breadthread.ts +++ b/src/commands/breadthread.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { ChannelType, ChatInputCommandInteraction, CommandInteraction, MessageFlags, SlashCommandBuilder } from "discord.js"; import { breadthreadEnsureAutoLock, breadthreadRemoveAutoLock } from "../utilties/breadbot/breadthread"; import { db } from "../breadbot"; diff --git a/src/utilties/discord/channels.ts b/src/utilties/discord/channels.ts index 524f386..f351e45 100644 --- a/src/utilties/discord/channels.ts +++ b/src/utilties/discord/channels.ts @@ -1,50 +1,37 @@ -import { SQLCommon } from "../storage/interfaces"; import { DMChannel, GuildBasedChannel, PartialDMChannel } from "discord.js"; -import { SQLResult } from "../storage/enumerations"; +import { Repository } from "typeorm"; +import { DBChannel } from "../storage/entities/DBChannel"; -export async function doesChannelExistByID(db: SQLCommon, channelID: string) : Promise { - const queryResult : Object[] = await db.getAllParameterized( - "SELECT * FROM channels WHERE channel_snowflake = ?", - [channelID] - ) - - return queryResult.length != 0 +export async function doesChannelExistByID(db: Repository, channelID: string) : Promise { + return (await db.findOne({"where": {channel_snowflake: channelID}})) != null } -export async function doesChannelExist(db: SQLCommon, channel : GuildBasedChannel | DMChannel | PartialDMChannel) : Promise { - const queryResult : Object[] = await db.getAllParameterized( - "SELECT * FROM channels WHERE channel_snowflake = ?", - [channel.id] - ) - - return queryResult.length != 0 +export async function doesChannelExist(db: Repository, channel : GuildBasedChannel | DMChannel | PartialDMChannel) : Promise { + return await doesChannelExistByID(db, channel.id) } -export async function insertChannel(db: SQLCommon, channel: GuildBasedChannel | DMChannel | PartialDMChannel) : Promise { +export async function insertChannel(db: Repository, channel: GuildBasedChannel | DMChannel | PartialDMChannel) : Promise { const alreadyExists: boolean = await doesChannelExist(db, channel) if(alreadyExists) { - return SQLResult.ALREADYEXISTS + return await db.findOne({"where": {channel_snowflake: channel.id}}) } try { - if (channel.isDMBased()) { - await db.runParameterized( - "INSERT INTO channels VALUES (?, ?, ?, ?, ?, ?)", - [channel.id, null, channel.recipient?.username, channel.isThread(), channel.isDMBased(), channel.isVoiceBased()] - ) - } else { - await db.runParameterized( - "INSERT INTO channels VALUES (?, ?, ?, ?, ?, ?)", - [channel.id, channel.guild.id, channel.name, channel.isThread(), channel.isDMBased(), channel.isVoiceBased()] - ) - } + const newChannel : DBChannel = await db.create({ + channel_snowflake: channel.id, + channel_name: channel.isDMBased() ? channel.recipient?.username : channel.name, + is_dm: channel.isDMBased(), + is_thread: channel.isThread(), + is_voice: channel.isVoiceBased(), + server: channel.isDMBased() ? null : {server_snowflake: channel.guild.id} + }) - return SQLResult.CREATED + return await db.save(newChannel) } catch (err) { //TODO Winston should handle this console.log("CHANNEL INSERT ERROR") console.log(err) - return SQLResult.FAILED + return null } } \ No newline at end of file diff --git a/src/utilties/discord/guilds.ts b/src/utilties/discord/guilds.ts index 4433cbf..0934b5d 100644 --- a/src/utilties/discord/guilds.ts +++ b/src/utilties/discord/guilds.ts @@ -1,33 +1,29 @@ import { Guild } from "discord.js"; -import { SQLCommon } from "../storage/interfaces"; -import { SQLResult } from "../storage/enumerations"; +import { Repository } from "typeorm"; +import { DBServer } from "../storage/entities/DBServer"; -export async function doesGuildExist(db: SQLCommon, guild : Guild) : Promise { - const queryResult : Object[] = await db.getAllParameterized( - "SELECT * FROM servers WHERE server_snowflake = ?", - [guild.id] - ) - - return queryResult.length != 0 +export async function doesGuildExist(db: Repository, guild : Guild) : Promise { + return (await db.findOne({"where": {server_snowflake: guild.id}})) != null } -export async function insertGuild(db: SQLCommon, guild: Guild) : Promise { +export async function insertGuild(db: Repository, guild: Guild) : Promise { const alreadyExists: boolean = await doesGuildExist(db, guild) if (alreadyExists) { - return SQLResult.ALREADYEXISTS + return await db.findOne({"where": {server_snowflake: guild.id}}) } try { - await db.runParameterized( - "INSERT INTO servers VALUES (?, ?, ?)", - [guild.id, guild.name, guild.description] - ) + const server: DBServer = await db.create({ + server_snowflake: guild.id, + server_name: guild.name, + server_description: guild.description ?? "" + }) - return SQLResult.CREATED + return await db.save(server) } catch (err) { console.log("Insert Failed") //TODO Winston should handle this console.log(err) - return SQLResult.FAILED + return null } } \ No newline at end of file diff --git a/src/utilties/discord/roles.ts b/src/utilties/discord/roles.ts index 4b1eaf0..97dfa73 100644 --- a/src/utilties/discord/roles.ts +++ b/src/utilties/discord/roles.ts @@ -1,75 +1,79 @@ import { Role } from "discord.js"; -import { SQLCommon } from "../storage/interfaces"; -import { SQLResult } from "../storage/enumerations"; +import { Repository } from "typeorm"; +import { DBRole } from "../storage/entities/DBRole"; -export async function doesRoleExist(db: SQLCommon, role : Role) : Promise { - const queryResult : Object[] = await db.getAllParameterized( - "SELECT * FROM roles WHERE role_snowflake = ?", - [role.id] - ) - - return queryResult.length != 0 +export async function doesRoleExist(db: Repository, role : Role) : Promise { + return (await db.findOne({"where": {role_snowflake: role.id}})) != null } -export async function insertRole(db: SQLCommon, role: Role) : Promise { +export async function insertRole(db: Repository, role: Role) : Promise { const alreadyExists: boolean = await doesRoleExist(db, role) if(alreadyExists) { - return SQLResult.ALREADYEXISTS + return await db.findOne({"where": {role_snowflake: role.id}}) } try { - await db.runParameterized( - "INSERT INTO roles VALUES (?, ?, ?, 0)", - [role.id, role.guild.id, role.name] - ) + const newRole : DBRole = await db.create({ + role_snowflake: role.id, + server: {server_snowflake: role.guild.id}, + role_name: role.name, + is_deleted: false + }) - return SQLResult.CREATED + return await db.save(newRole) } catch (err) { console.log("ROLE INSERT ERROR") console.log(err) - return SQLResult.FAILED + return null } } -export async function updateRole(db: SQLCommon, role: Role): Promise { +export async function updateRole(db: Repository, role: Role): Promise { const roleExists: boolean = await doesRoleExist(db, role) if(!roleExists) { - return SQLResult.FAILED + return null } try { - await db.runParameterized( - "UPDATE roles SET role_name = ? WHERE role_snowflake = ?", - [role.name, role.id] - ) + const toUpdate: DBRole | null = await db.findOne({"where": {role_snowflake: role.id}}) - return SQLResult.UPDATED + if(toUpdate != null) { + toUpdate.role_name = role.name + + return await db.save(toUpdate) + } else { + return null + } + } catch (err) { console.log("ROLE UPDATE FAILED") console.log(err) - return SQLResult.FAILED + return null } } -export async function markRoleDeleted(db: SQLCommon, role: Role) : Promise { +export async function markRoleDeleted(db: Repository, role: Role) : Promise { const roleExists: boolean = await doesRoleExist(db, role) if(!roleExists) { - return SQLResult.FAILED + return null } try { - await db.runParameterized( - "UPDATE roles SET is_deleted = 1 WHERE role_snowflake = ?", - [role.id] - ) + const toUpdate: DBRole | null = await db.findOne({"where": {role_snowflake: role.id}}) - return SQLResult.UPDATED + if(toUpdate != null) { + toUpdate.is_deleted = true + + return await db.save(toUpdate) + } else { + return null + } } catch (err) { console.log("ROLE DELETE FAILED") console.log(err) - return SQLResult.FAILED + return null } } \ No newline at end of file diff --git a/src/utilties/discord/voice.ts b/src/utilties/discord/voice.ts index e69de29..3e39757 100644 --- a/src/utilties/discord/voice.ts +++ b/src/utilties/discord/voice.ts @@ -0,0 +1,20 @@ +import { Guild, VoiceBasedChannel } from "discord.js"; +import { SQLCommon } from "../storage/interfaces"; + +export async function breadbotInCall(db: SQLCommon, channel: VoiceBasedChannel) : Promise { + const queryResult: Object[] = await db.getAllParameterized( + "SELECT * FROM calls WHERE channel_snowflake = ? AND call_end_time IS NULL", + [channel.id] + ) + + return queryResult.length != 0 +} + +export async function getExistingCallID(db: SQLCommon, channel: VoiceBasedChannel) : Promise { + const queryResult: any[] = await db.getAllParameterized( + "SELECT * FROM calls WHERE channel_snowflake = ? AND call_end_time IS NULL", + [channel.id] + ) + + return queryResult.length != 0 ? queryResult[0].call_id : -1 +} diff --git a/src/utilties/events/messages.ts b/src/utilties/events/messages.ts index 67a8702..0e91d74 100644 --- a/src/utilties/events/messages.ts +++ b/src/utilties/events/messages.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { Client, Events, Message, OmitPartialGroupDMChannel, PartialMessage } from "discord.js"; import { SQLResult } from "../storage/enumerations"; import { SQLCommon } from "../storage/interfaces"; diff --git a/src/utilties/events/roles.ts b/src/utilties/events/roles.ts index 283bb24..5e5f45b 100644 --- a/src/utilties/events/roles.ts +++ b/src/utilties/events/roles.ts @@ -1,23 +1,24 @@ import { Client, Events } from "discord.js"; -import { SQLCommon } from "../storage/interfaces"; -import { SQLResult } from "../storage/enumerations"; import { insertRole, markRoleDeleted, updateRole } from "../discord/roles"; import { insertGuild } from "../discord/guilds"; +import { Repository } from "typeorm"; +import { DBServer } from "../storage/entities/DBServer"; +import { DBRole } from "../storage/entities/DBRole"; -export function setupRoleCapture(client: Client, db: SQLCommon) { +export function setupRoleCapture(client: Client, guildDB: Repository, roleDB: Repository) { client.on(Events.GuildRoleCreate, async (role) => { - const serverOk: SQLResult = await insertGuild(db, role.guild) + const serverOk: DBServer | null = await insertGuild(guildDB, role.guild) - if (serverOk == SQLResult.ALREADYEXISTS || serverOk == SQLResult.CREATED) { - await insertRole(db, role) + if (serverOk != null) { + await insertRole(roleDB, role) } }) client.on(Events.GuildRoleUpdate, async (role) => { - await updateRole(db, role) + await updateRole(roleDB, role) }) client.on(Events.GuildRoleDelete, async (role) => { - await markRoleDeleted(db, role) + await markRoleDeleted(roleDB, role) }) } \ No newline at end of file diff --git a/src/utilties/events/voice.ts b/src/utilties/events/voice.ts index e69de29..ec281c6 100644 --- a/src/utilties/events/voice.ts +++ b/src/utilties/events/voice.ts @@ -0,0 +1,19 @@ +import { Client, Events, VoiceState } from "discord.js" +import { SQLCommon } from "../storage/interfaces"; + +export function setupVoice(client: Client, db: SQLCommon) { + client.on(Events.VoiceStateUpdate, (oldState: VoiceState, newState: VoiceState) => { + if(oldState.channel == null && newState.channel != null) { + // TODO Null Type Safety Risk? + if (newState.member?.id == client.user?.id) { + return + } + + + } + }) +} + +async function processCallJoin(db: SQLCommon, voiceState: VoiceState) { + +} diff --git a/src/utilties/storage/entities/DBChannel.ts b/src/utilties/storage/entities/DBChannel.ts new file mode 100644 index 0000000..63c7e35 --- /dev/null +++ b/src/utilties/storage/entities/DBChannel.ts @@ -0,0 +1,27 @@ +import { Column, Entity, ManyToOne, OneToMany, PrimaryColumn } from "typeorm"; +import { DBServer } from "./DBServer"; +import { DBMessage } from "./DBMessage"; + +@Entity() +export class DBChannel { + @PrimaryColumn({type: "bigint"}) + channel_snowflake: string + + @ManyToOne(() => DBServer, (server: DBServer) => server.channels, {nullable: true}) + server: DBServer | null + + @Column() + channel_name: string + + @Column() + is_thread: boolean + + @Column() + is_dm: boolean + + @Column() + is_voice: boolean + + @OneToMany(() => DBMessage, (message: DBMessage) => message.channel) + messages: DBMessage[] +} \ No newline at end of file diff --git a/src/utilties/storage/entities/DBMessage.ts b/src/utilties/storage/entities/DBMessage.ts new file mode 100644 index 0000000..99df0c0 --- /dev/null +++ b/src/utilties/storage/entities/DBMessage.ts @@ -0,0 +1,28 @@ +import { Column, Entity, ManyToOne, OneToMany, PrimaryColumn } from "typeorm"; +import { DBChannel } from "./DBChannel"; +import { DBUser } from "./DBUser"; +import { DBMessageContentChanges } from "./DBMessageContentChanges"; + +@Entity() +export class DBMessage { + @PrimaryColumn({type: "bigint"}) + message_snowflake: string + + @ManyToOne(() => DBChannel, (channel: DBChannel) => channel.messages) + channel: DBChannel + + @ManyToOne(() => DBUser, (user: DBUser) => user.messages) + user: DBUser + + @Column({type: "longtext"}) + message_content: string + + @Column({type: "datetime"}) + message_timestamp: Date + + @Column() + message_deleted: boolean + + @OneToMany(() => DBMessageContentChanges, (mcc: DBMessageContentChanges) => mcc.message, {nullable: true}) + changes: DBMessageContentChanges | null +} \ No newline at end of file diff --git a/src/utilties/storage/entities/DBMessageContentChanges.ts b/src/utilties/storage/entities/DBMessageContentChanges.ts new file mode 100644 index 0000000..5a1e199 --- /dev/null +++ b/src/utilties/storage/entities/DBMessageContentChanges.ts @@ -0,0 +1,17 @@ +import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from "typeorm"; +import { DBMessage } from "./DBMessage"; + +@Entity() +export class DBMessageContentChanges { + @PrimaryGeneratedColumn() + message_change_id: number + + @ManyToOne(() => DBMessage, (message: DBMessage) => message.changes) + message: DBMessage + + @Column({type: "datetime"}) + message_change_old_timestamp: Date + + @Column({type: "longtext"}) + message_change_old_content: string +} \ No newline at end of file diff --git a/src/utilties/storage/entities/DBRole.ts b/src/utilties/storage/entities/DBRole.ts new file mode 100644 index 0000000..75f439d --- /dev/null +++ b/src/utilties/storage/entities/DBRole.ts @@ -0,0 +1,17 @@ +import { Column, Entity, ManyToOne, PrimaryColumn } from "typeorm"; +import { DBServer } from "./DBServer"; + +@Entity() +export class DBRole { + @PrimaryColumn({type: "bigint"}) + role_snowflake: string + + @ManyToOne(() => DBServer, (server: DBServer) => server.roles) + server: DBServer + + @Column() + role_name: string + + @Column() + is_deleted: boolean +} \ No newline at end of file diff --git a/src/utilties/storage/entities/DBServer.ts b/src/utilties/storage/entities/DBServer.ts new file mode 100644 index 0000000..2dbc475 --- /dev/null +++ b/src/utilties/storage/entities/DBServer.ts @@ -0,0 +1,21 @@ +import { Column, Entity, OneToMany, PrimaryColumn } from "typeorm"; +import { DBChannel } from "./DBChannel"; +import { DBRole } from "./DBRole"; + +@Entity() +export class DBServer { + @PrimaryColumn({type: "bigint"}) + server_snowflake: string + + @Column() + server_name: string + + @Column() + server_description: string + + @OneToMany(() => DBChannel, (channel: DBChannel) => channel.server) + channels: DBChannel[] + + @OneToMany(() => DBRole, (role: DBRole) => role.server) + roles: DBRole[] +} \ No newline at end of file diff --git a/src/utilties/storage/entities/DBUser.ts b/src/utilties/storage/entities/DBUser.ts new file mode 100644 index 0000000..bf11254 --- /dev/null +++ b/src/utilties/storage/entities/DBUser.ts @@ -0,0 +1,17 @@ +import { Column, Entity, OneToMany, PrimaryColumn } from "typeorm"; +import { DBMessage } from "./DBMessage"; + +@Entity() +export class DBUser { + @PrimaryColumn({type: "bigint"}) + user_snowflake: string + + @Column() + user_name: string + + @Column() + user_displayname: string + + @OneToMany(() => DBMessage, (message: DBMessage) => message.user) + messages: DBMessage[] +} \ No newline at end of file diff --git a/src/utilties/storage/tables.ts b/src/utilties/storage/tables.ts index a3e1869..187be1a 100644 --- a/src/utilties/storage/tables.ts +++ b/src/utilties/storage/tables.ts @@ -1,14 +1,10 @@ import { SQLCommon } from "./interfaces"; const tables: string[] = [ - "CREATE TABLE IF NOT EXISTS servers (server_snowflake bigint NOT NULL PRIMARY KEY,server_name text NOT NULL,server_description mediumtext);", - "CREATE TABLE IF NOT EXISTS channels (channel_snowflake bigint NOT NULL PRIMARY KEY,server_snowflake bigint,channel_name text,is_thread bit NOT NULL,is_dm bit NOT NULL,is_voice bit NOT NULL);", - "CREATE TABLE IF NOT EXISTS users (user_snowflake bigint NOT NULL PRIMARY KEY,user_name text NOT NULL,user_displayname text);", "CREATE TABLE IF NOT EXISTS messages (message_snowflake bigint NOT NULL PRIMARY KEY,channel_snowflake bigint NOT NULL,user_snowflake bigint NOT NULL,message_content longtext NOT NULL,message_timestamp datetime NOT NULL,message_deleted bit NOT NULL);", "CREATE TABLE IF NOT EXISTS message_content_changes (message_change_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,message_snowflake bigint NOT NULL,message_change_old_timestamp datetime NOT NULL,message_change_old_content longtext NOT NULL);", "CREATE TABLE IF NOT EXISTS message_attachments (attachment_snowflake bigint NOT NULL PRIMARY KEY,message_snowflake bigint NOT NULL,attachment_name text NOT NULL,attachment_description text,attachment_timestamp datetime NOT NULL,attachment_mime_type text,attachment_url text NOT NULL,attachment_downloaded bit NOT NULL);", "CREATE TABLE IF NOT EXISTS breadthread_autolock (breadthread_autolock_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,channel_snowflake bigint NOT NULL,inactivity_seconds bigint NOT NULL,locked bit NOT NULL);", - "CREATE TABLE IF NOT EXISTS roles (role_snowflake bigint NOT NULL PRIMARY KEY,server_snowflake bigint NOT NULL,role_name text NOT NULL,is_deleted bit NOT NULL);", "CREATE TABLE IF NOT EXISTS message_scan_regex_matches (message_scan_regex_matches_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,message_snowflake bigint NOT NULL,message_regexes_id bigint NOT NULL);", "CREATE TABLE IF NOT EXISTS message_regex_no_role_check (message_regex_no_role_check_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,server_snowflake bigint NOT NULL,role_snowflake bigint NOT NULL);", "CREATE TABLE IF NOT EXISTS message_regexes (message_regexes_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,server_snowflake bigint NOT NULL,regex text NOT NULL,priority int NOT NULL,severity int NOT NULL);", diff --git a/tsconfig.json b/tsconfig.json index f9ce197..4f9bd68 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,7 @@ { "compilerOptions": { - "target": "ES2020", + "lib": ["es5", "es6"], + "target": "es6", "module": "commonjs", "rootDir": "./src", "outDir": "./dist", @@ -10,6 +11,10 @@ "forceConsistentCasingInFileNames": true, "strict": true, "strictNullChecks": true, - "skipLibCheck": true + "skipLibCheck": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "strictPropertyInitialization": false, + "sourceMap": true } } \ No newline at end of file -- 2.45.2 From 69f2206a4b54d240ff4c855a5d48a75c3e315608 Mon Sep 17 00:00:00 2001 From: Bradley Bickford Date: Mon, 17 Nov 2025 14:22:59 -0500 Subject: [PATCH 2/4] Message component rework --- src/breadbot.ts | 19 ++- src/commands/breadthread.ts | 61 -------- src/commands/index.ts | 4 +- src/utilties/discord/messages.ts | 130 ++++++++---------- src/utilties/discord/users.ts | 30 ++-- src/utilties/events/messages.ts | 75 +++++----- src/utilties/storage/entities/DBMessage.ts | 8 +- .../storage/entities/DBMessageAttachment.ts | 29 ++++ src/utilties/storage/tables.ts | 4 - 9 files changed, 157 insertions(+), 203 deletions(-) delete mode 100644 src/commands/breadthread.ts create mode 100644 src/utilties/storage/entities/DBMessageAttachment.ts diff --git a/src/breadbot.ts b/src/breadbot.ts index 25a71a3..f80ead5 100644 --- a/src/breadbot.ts +++ b/src/breadbot.ts @@ -11,13 +11,25 @@ import { insertChannel } from "./utilties/discord/channels" import { insertRole } from "./utilties/discord/roles" import { setupRoleCapture } from "./utilties/events/roles" import { DBUser } from "./utilties/storage/entities/DBUser" +import { DBMessage } from "./utilties/storage/entities/DBMessage" +import { DBMessageContentChanges } from "./utilties/storage/entities/DBMessageContentChanges" +import { DBMessageAttachments } from "./utilties/storage/entities/DBMessageAttachment" +import { setupMessageCapture } from "./utilties/events/messages" console.log(__dirname + path.sep + "utilities" + path.sep + "storage" + path.sep + "entities" + path.sep + "*.ts") export const dataSource = new DataSource({ type: "sqlite", database: "breadbot.db", - entities: [DBServer, DBChannel, DBRole, DBUser], + entities: [ + DBServer, + DBChannel, + DBRole, + DBUser, + DBMessage, + DBMessageContentChanges, + DBMessageAttachments + ], synchronize: true, logging: true }) @@ -38,6 +50,10 @@ client.once(Events.ClientReady, async () => { const serverRepo = dataSource.getRepository(DBServer) const channelRepo = dataSource.getRepository(DBChannel) const roleRepo = dataSource.getRepository(DBRole) + const userRepo = dataSource.getRepository(DBUser) + const messageRepo = dataSource.getRepository(DBMessage) + const mccRepo = dataSource.getRepository(DBMessageContentChanges) + const maRepo = dataSource.getRepository(DBMessageAttachments) client.guilds.cache.forEach(async (guild: Guild) => { const server: DBServer | null = await insertGuild(serverRepo, guild) @@ -54,6 +70,7 @@ client.once(Events.ClientReady, async () => { }) setupRoleCapture(client, serverRepo, roleRepo) + setupMessageCapture(client, channelRepo, userRepo, messageRepo, mccRepo, maRepo) console.log("Breadbot is Ready") }) diff --git a/src/commands/breadthread.ts b/src/commands/breadthread.ts deleted file mode 100644 index cd84bf5..0000000 --- a/src/commands/breadthread.ts +++ /dev/null @@ -1,61 +0,0 @@ -// @ts-nocheck -import { ChannelType, ChatInputCommandInteraction, CommandInteraction, MessageFlags, SlashCommandBuilder } from "discord.js"; -import { breadthreadEnsureAutoLock, breadthreadRemoveAutoLock } from "../utilties/breadbot/breadthread"; -import { db } from "../breadbot"; -import { timeShorthandToSeconds } from "../utilties/time/conversions"; - -export const enabled: boolean = true - -export const data = new SlashCommandBuilder() - .setName("breadthread") - .setDescription("Manages Breadbot's extended thread features") - .addSubcommand(subcommand => - subcommand - .setName("autolock") - .setDescription("Enables auto locking of a thread after a period of thread inactivity") - .addChannelOption(option => - option - .setName("channel") - .setDescription("The name of the thread you want to autolock") - .addChannelTypes( - ChannelType.PublicThread, - ChannelType.PrivateThread, - ChannelType.AnnouncementThread - ) - .setRequired(true) - ) - .addBooleanOption(option => - option - .setName("enable") - .setDescription("Enable or disable the auto locking") - .setRequired(true) - ) - .addStringOption(option => - option - .setName("timeinactive") - .setDescription("How long the thread needs to be inactive before locking, default is 3 days") - .setRequired(false) - ) - - ) - -export async function execute(interaction: ChatInputCommandInteraction) { - await interaction.deferReply({flags: MessageFlags.Ephemeral}) - - if(interaction.options.getSubcommand() === "autolock") { - if(interaction.options.getBoolean("enable")) { - await breadthreadEnsureAutoLock( - db, - interaction.options.getChannel("channel", true).id, - interaction.options.getString("timeinactive") ?? "3d" - ) - } else { - await breadthreadRemoveAutoLock( - db, - interaction.options.getChannel("channel", true).id - ) - } - - await interaction.editReply("Autolock Action OK") - } -} \ No newline at end of file diff --git a/src/commands/index.ts b/src/commands/index.ts index 609f6e6..03ea096 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -1,9 +1,7 @@ import * as ping from "./ping"; import * as breadalert from "./breadalert" -import * as breadthread from "./breadthread" export const commands = { ping, - breadalert, - breadthread + breadalert } \ No newline at end of file diff --git a/src/utilties/discord/messages.ts b/src/utilties/discord/messages.ts index c52f683..629dcd0 100644 --- a/src/utilties/discord/messages.ts +++ b/src/utilties/discord/messages.ts @@ -1,118 +1,100 @@ import { Attachment, Message, OmitPartialGroupDMChannel, PartialMessage } from "discord.js"; -import { SQLCommon } from "../storage/interfaces"; -import { SQLResult } from "../storage/enumerations"; +import { Repository } from "typeorm"; +import { DBMessage } from "../storage/entities/DBMessage"; +import { DBMessageAttachments } from "../storage/entities/DBMessageAttachment"; +import { DBMessageContentChanges } from "../storage/entities/DBMessageContentChanges"; // TODO Do partial messages affect other functionality elsewhere? -export async function doesMessageExist(db: SQLCommon, message: OmitPartialGroupDMChannel> | PartialMessage) : Promise { - const queryResult: Object[] = await db.getAllParameterized( - "SELECT * FROM messages WHERE message_snowflake = ?", - [message.id] - ) - - return queryResult.length != 0 +export async function doesMessageExist(db: Repository, message: OmitPartialGroupDMChannel> | PartialMessage) : Promise { + return (await db.findOne({"where": {message_snowflake: message.id}})) != null } -export async function doesAttachmentExist(db: SQLCommon, attachment: Attachment) : Promise { - const queryResult: Object[] = await db.getAllParameterized( - "SELECT * FROM message_attachments WHERE attachment_snowflake = ?", - [attachment.id] - ) - - return queryResult.length != 0 +export async function doesAttachmentExist(db: Repository, attachment: Attachment) : Promise { + return (await db.findOne({"where": {attachment_snowflake: attachment.id}})) != null } -export async function insertMessage(db: SQLCommon, message: OmitPartialGroupDMChannel>) : Promise { - const alreadyExists: boolean = await doesMessageExist(db, message) +export async function insertMessage(messageDB: Repository, maDB: Repository, message: OmitPartialGroupDMChannel>) : Promise { + const alreadyExists: boolean = await doesMessageExist(messageDB, message) if(alreadyExists) { - return SQLResult.ALREADYEXISTS + return await messageDB.findOne({"where": {message_snowflake: message.id}}) } try { - await db.runParameterized( - "INSERT INTO messages VALUES (?, ?, ?, ?, ?, ?)", - [message.id, message.channel.id, message.author.id, - message.content, message.createdTimestamp, 0] - ) + const newMessage: DBMessage = await messageDB.create({ + message_snowflake: message.id, + channel: {channel_snowflake: message.channel.id}, + user: {user_snowflake: message.author.id}, + message_content: message.content, + message_timestamp: message.createdAt, + attachments: message.attachments.size == 0 ? null : message.attachments.map((attachment: Attachment) => { + return maDB.create({ + attachment_snowflake: attachment.id, + message: {message_snowflake: message.id}, + attachment_name: attachment.name, + attachment_description: attachment.description, + attachment_timestamp: message.createdAt, + attachment_mime_type: attachment.contentType, + attachment_url: attachment.url + }) + }) + }) - return SQLResult.CREATED + return await messageDB.save(newMessage) } catch (err) { //TODO Winston should handle this console.log("MESSAGE INSERTION ERROR") console.log(err) - return SQLResult.FAILED + return null } } -export async function updateMessageContentHistory(db: SQLCommon, message: OmitPartialGroupDMChannel>) : Promise { - const messageIDExists: boolean = await doesMessageExist(db, message) +export async function updateMessageContentHistory(messageDB: Repository, mccDB: Repository, + ma: Repository, message: OmitPartialGroupDMChannel>) : Promise { + let dbMessage: DBMessage | null = await messageDB.findOne({"where": {message_snowflake: message.id}}) - if(!messageIDExists) { - return SQLResult.FAILED + if(dbMessage == null) { + return null } try { - console.log([message.id, message.editedTimestamp ?? message.createdTimestamp, message.content, message.id]) - await db.runParameterized( - "INSERT INTO message_content_changes (message_snowflake, message_change_old_timestamp, message_change_old_content) " + - "SELECT messages.message_snowflake, message_timestamp, message_content FROM messages WHERE message_snowflake = ?;", - [message.id] - ) + const contentChange: DBMessageContentChanges = mccDB.create({ + message: {message_snowflake: message.id}, + message_change_old_content: dbMessage.message_content, + message_change_old_timestamp: dbMessage.message_timestamp + }) - await db.runParameterized( - "UPDATE messages SET message_timestamp = ?, message_content = ? WHERE message_snowflake = ?;", - [message.editedTimestamp ?? message.createdTimestamp, message.content, message.id] - ) + dbMessage.message_content = message.content + dbMessage.message_timestamp = message.editedAt ?? message.createdAt - return SQLResult.UPDATED + // TODO This should really be a transaction + // TODO Changes to attachments aren't captured + return await mccDB.save(contentChange).then(async (dbmcc: DBMessageContentChanges) => { + return await messageDB.save(dbMessage) + }) } catch (err) { //TODO Winston should handle this console.log("MESSAGE MODIFY FAILED") console.log(err) - return SQLResult.FAILED + return null } } -export async function markMessageDeleted(db: SQLCommon, message: OmitPartialGroupDMChannel> | PartialMessage) : Promise { - const messageIDExists: boolean = await doesMessageExist(db, message) +export async function markMessageDeleted(db: Repository, message: OmitPartialGroupDMChannel> | PartialMessage) : Promise { + let dbMessage: DBMessage | null = await db.findOne({"where": {message_snowflake: message.id}}) - if(!messageIDExists) { - return SQLResult.FAILED + if(dbMessage == null) { + return null } try { - await db.runParameterized( - "UPDATE messages SET message_deleted = 1 WHERE message_snowflake = ?", - [message.id] - ) + dbMessage.message_deleted = true - return SQLResult.UPDATED + return await db.save(dbMessage) } catch (err) { // TODO Winston should handle this console.log(err) - return SQLResult.FAILED - } -} - -export async function insertAttachment(db: SQLCommon, attachment: Attachment, message: OmitPartialGroupDMChannel> | PartialMessage) : Promise { - const alreadyExists: boolean = await doesAttachmentExist(db, attachment) - - if(alreadyExists) { - return SQLResult.ALREADYEXISTS - } - - try { - await db.runParameterized( - "INSERT INTO message_attachments VALUES (?, ?, ?, ?, ?, ?, ?, ?)", - [attachment.id, message.id, attachment.name, attachment.description, message.createdTimestamp, - attachment.contentType, attachment.url, 0] - ) - - return SQLResult.CREATED - } catch (err) { - // TODO Winston should handle this - console.log(err) - return SQLResult.FAILED + return null } } \ No newline at end of file diff --git a/src/utilties/discord/users.ts b/src/utilties/discord/users.ts index b05f7e5..9ba9235 100644 --- a/src/utilties/discord/users.ts +++ b/src/utilties/discord/users.ts @@ -1,34 +1,30 @@ import { User } from "discord.js"; -import { SQLCommon } from "../storage/interfaces"; -import { SQLResult } from "../storage/enumerations"; +import { Repository } from "typeorm"; +import { DBUser } from "../storage/entities/DBUser"; -export async function doesUserExist(db: SQLCommon, user: User): Promise { - const queryResult: Object[] = await db.getAllParameterized( - "SELECT * FROM users WHERE user_snowflake = ?", - [user.id] - ) - - return queryResult.length != 0 +export async function doesUserExist(db: Repository, user: User): Promise { + return (await db.findOne({"where": {user_snowflake: user.id}})) != null } -export async function insertUser(db: SQLCommon, user: User): Promise { +export async function insertUser(db: Repository, user: User): Promise { const alreadyExists: boolean = await doesUserExist(db, user) if(alreadyExists) { - return SQLResult.ALREADYEXISTS + return null } try { - await db.runParameterized( - "INSERT INTO users VALUES (?, ?, ?)", - [user.id, user.username, user.displayName] - ) + const newUser: DBUser = db.create({ + user_snowflake: user.id, + user_name: user.username, + user_displayname: user.displayName + }) - return SQLResult.CREATED + return await db.save(newUser) } catch (err) { //TODO Winston should handle this console.log("USER INSERT ERROR") console.log(err) - return SQLResult.FAILED + return null } } \ No newline at end of file diff --git a/src/utilties/events/messages.ts b/src/utilties/events/messages.ts index 0e91d74..f0fc219 100644 --- a/src/utilties/events/messages.ts +++ b/src/utilties/events/messages.ts @@ -1,64 +1,57 @@ -// @ts-nocheck import { Client, Events, Message, OmitPartialGroupDMChannel, PartialMessage } from "discord.js"; -import { SQLResult } from "../storage/enumerations"; -import { SQLCommon } from "../storage/interfaces"; import { insertChannel } from "../discord/channels"; import { insertUser } from "../discord/users"; -import { insertAttachment, insertMessage, markMessageDeleted, updateMessageContentHistory } from "../discord/messages"; +import { insertMessage, markMessageDeleted, updateMessageContentHistory } from "../discord/messages"; +import { Repository } from "typeorm"; +import { DBMessage } from "../storage/entities/DBMessage"; +import { DBMessageContentChanges } from "../storage/entities/DBMessageContentChanges"; +import { DBMessageAttachments } from "../storage/entities/DBMessageAttachment"; +import { DBChannel } from "../storage/entities/DBChannel"; +import { DBUser } from "../storage/entities/DBUser"; -export function setupMessageCapture(client: Client, db: SQLCommon) { +export function setupMessageCapture(client: Client, + channelDB: Repository, + userDB: Repository, + messageDB: Repository, + mccDB: Repository, + maDB: Repository +) { client.on(Events.MessageCreate, async (message) => { - await processMessageCreate(db, message) + await processMessageCreate(channelDB, userDB, messageDB, maDB, message) }) client.on(Events.MessageUpdate, async (oldMessage, newMessage) => { - await processMessageModify(db, newMessage) + await processMessageModify(messageDB, mccDB, maDB, newMessage) }) client.on(Events.MessageDelete, async (deletedMessage) => { - await processMessageDeleted(db, deletedMessage) + await processMessageDeleted(messageDB, deletedMessage) }) } -async function processMessageCreate(db: SQLCommon, message: OmitPartialGroupDMChannel>) { - const channelOk: SQLResult = await insertChannel(db, message.channel) - const userOk: SQLResult = await insertUser(db, message.author) +async function processMessageCreate( + channelDB: Repository, + userDB: Repository, + messageDB: Repository, + maDB: Repository, + message: OmitPartialGroupDMChannel>) { + const channelOk: DBChannel | null = await insertChannel(channelDB, message.channel) + const userOk: DBUser | null = await insertUser(userDB, message.author) - if (channelOk == SQLResult.ALREADYEXISTS || channelOk == SQLResult.CREATED || - userOk == SQLResult.ALREADYEXISTS || userOk == SQLResult.CREATED) { - - await insertMessage(db, message) - // TODO observe success of message insertion - if(message.attachments.size != 0) { - const allAttachments: void[] = message.attachments.map((attachment) => { - insertAttachment(db, attachment, message) - }) - - await Promise.all(allAttachments).catch((error) => { - // TODO Winston should handle this - console.log("MESSAGE ATTACHMENT INSERT ERROR") - console.log(error) - }) - } + if (channelOk != null && userOk != null) { + await insertMessage(messageDB, maDB, message) } } -async function processMessageModify(db: SQLCommon, newMessage: OmitPartialGroupDMChannel>) { - await updateMessageContentHistory(db, newMessage) - - if(newMessage.attachments.size != 0) { - const allAttachments: void[] = newMessage.attachments.map((attachment) => { - insertAttachment(db, attachment, newMessage) - }) - - await Promise.all(allAttachments).catch((error) => { - // TODO Winston should handle this - console.log(error) - }) - } +async function processMessageModify( + messageDB: Repository, + mccDB: Repository, + maDB: Repository, + newMessage: OmitPartialGroupDMChannel>) { + await updateMessageContentHistory(messageDB, mccDB, maDB, newMessage) } -async function processMessageDeleted(db: SQLCommon, deletedMessage: OmitPartialGroupDMChannel> | PartialMessage) { +async function processMessageDeleted(db: Repository, deletedMessage: OmitPartialGroupDMChannel> | PartialMessage) { await markMessageDeleted(db, deletedMessage) } \ No newline at end of file diff --git a/src/utilties/storage/entities/DBMessage.ts b/src/utilties/storage/entities/DBMessage.ts index 99df0c0..c186e21 100644 --- a/src/utilties/storage/entities/DBMessage.ts +++ b/src/utilties/storage/entities/DBMessage.ts @@ -2,6 +2,7 @@ import { Column, Entity, ManyToOne, OneToMany, PrimaryColumn } from "typeorm"; import { DBChannel } from "./DBChannel"; import { DBUser } from "./DBUser"; import { DBMessageContentChanges } from "./DBMessageContentChanges"; +import { DBMessageAttachments } from "./DBMessageAttachment"; @Entity() export class DBMessage { @@ -20,9 +21,12 @@ export class DBMessage { @Column({type: "datetime"}) message_timestamp: Date - @Column() + @Column({default: false}) message_deleted: boolean @OneToMany(() => DBMessageContentChanges, (mcc: DBMessageContentChanges) => mcc.message, {nullable: true}) - changes: DBMessageContentChanges | null + changes: DBMessageContentChanges[] | null + + @OneToMany(() => DBMessageAttachments, (ma: DBMessageAttachments) => ma.attachment_snowflake, {nullable: true}) + attachments: DBMessageAttachments[] | null } \ No newline at end of file diff --git a/src/utilties/storage/entities/DBMessageAttachment.ts b/src/utilties/storage/entities/DBMessageAttachment.ts new file mode 100644 index 0000000..6f3a9b7 --- /dev/null +++ b/src/utilties/storage/entities/DBMessageAttachment.ts @@ -0,0 +1,29 @@ +import { Column, Entity, ManyToOne, PrimaryColumn } from "typeorm"; +import { DBMessage } from "./DBMessage"; + +@Entity() +export class DBMessageAttachments { + @PrimaryColumn({"type": "bigint"}) + attachment_snowflake: string + + @ManyToOne(() => DBMessage, (message: DBMessage) => message.attachments) + message: DBMessage + + @Column() + attachment_name: string + + @Column({nullable: true}) + attachment_description: string | null + + @Column({type: "datetime"}) + attachment_timestamp: Date + + @Column({nullable: true}) + attachment_mime_type: string | null + + @Column() + attachment_url: string + + @Column({default: false}) + attachment_download: boolean +} \ No newline at end of file diff --git a/src/utilties/storage/tables.ts b/src/utilties/storage/tables.ts index 187be1a..97426af 100644 --- a/src/utilties/storage/tables.ts +++ b/src/utilties/storage/tables.ts @@ -1,10 +1,6 @@ import { SQLCommon } from "./interfaces"; const tables: string[] = [ - "CREATE TABLE IF NOT EXISTS messages (message_snowflake bigint NOT NULL PRIMARY KEY,channel_snowflake bigint NOT NULL,user_snowflake bigint NOT NULL,message_content longtext NOT NULL,message_timestamp datetime NOT NULL,message_deleted bit NOT NULL);", - "CREATE TABLE IF NOT EXISTS message_content_changes (message_change_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,message_snowflake bigint NOT NULL,message_change_old_timestamp datetime NOT NULL,message_change_old_content longtext NOT NULL);", - "CREATE TABLE IF NOT EXISTS message_attachments (attachment_snowflake bigint NOT NULL PRIMARY KEY,message_snowflake bigint NOT NULL,attachment_name text NOT NULL,attachment_description text,attachment_timestamp datetime NOT NULL,attachment_mime_type text,attachment_url text NOT NULL,attachment_downloaded bit NOT NULL);", - "CREATE TABLE IF NOT EXISTS breadthread_autolock (breadthread_autolock_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,channel_snowflake bigint NOT NULL,inactivity_seconds bigint NOT NULL,locked bit NOT NULL);", "CREATE TABLE IF NOT EXISTS message_scan_regex_matches (message_scan_regex_matches_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,message_snowflake bigint NOT NULL,message_regexes_id bigint NOT NULL);", "CREATE TABLE IF NOT EXISTS message_regex_no_role_check (message_regex_no_role_check_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,server_snowflake bigint NOT NULL,role_snowflake bigint NOT NULL);", "CREATE TABLE IF NOT EXISTS message_regexes (message_regexes_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,server_snowflake bigint NOT NULL,regex text NOT NULL,priority int NOT NULL,severity int NOT NULL);", -- 2.45.2 From 68d8415a77a8c4ce2615ba6d01ea65c49521d917 Mon Sep 17 00:00:00 2001 From: Bradley Bickford Date: Mon, 17 Nov 2025 16:16:03 -0500 Subject: [PATCH 3/4] Working on Voice stuff --- src/breadbot.ts | 116 +++++++----------- src/utilties/storage/entities/DBCall.ts | 34 +++++ .../storage/entities/DBCallTranscriptions.ts | 21 ++++ src/utilties/storage/entities/DBCallUsers.ts | 21 ++++ src/utilties/storage/entities/DBChannel.ts | 6 +- src/utilties/storage/entities/DBUser.ts | 8 ++ 6 files changed, 131 insertions(+), 75 deletions(-) create mode 100644 src/utilties/storage/entities/DBCall.ts create mode 100644 src/utilties/storage/entities/DBCallTranscriptions.ts create mode 100644 src/utilties/storage/entities/DBCallUsers.ts diff --git a/src/breadbot.ts b/src/breadbot.ts index f80ead5..b2e9fc6 100644 --- a/src/breadbot.ts +++ b/src/breadbot.ts @@ -1,5 +1,5 @@ import "reflect-metadata" -import { Client, Events, GatewayIntentBits, Guild, GuildBasedChannel, Role } from "discord.js" +import { ChatInputCommandInteraction, Client, Events, GatewayIntentBits, Guild, GuildBasedChannel, Interaction, Role } from "discord.js" import { config } from "./config" import { DataSource } from "typeorm" import { DBServer } from "./utilties/storage/entities/DBServer" @@ -15,6 +15,11 @@ import { DBMessage } from "./utilties/storage/entities/DBMessage" import { DBMessageContentChanges } from "./utilties/storage/entities/DBMessageContentChanges" import { DBMessageAttachments } from "./utilties/storage/entities/DBMessageAttachment" import { setupMessageCapture } from "./utilties/events/messages" +import { utilities } from "./utilties" +import { commands } from "./commands" +import { DBCall } from "./utilties/storage/entities/DBCall" +import { DBCallTranscriptions } from "./utilties/storage/entities/DBCallTranscriptions" +import { DBCallUsers } from "./utilties/storage/entities/DBCallUsers" console.log(__dirname + path.sep + "utilities" + path.sep + "storage" + path.sep + "entities" + path.sep + "*.ts") @@ -28,7 +33,10 @@ export const dataSource = new DataSource({ DBUser, DBMessage, DBMessageContentChanges, - DBMessageAttachments + DBMessageAttachments, + DBCall, + DBCallTranscriptions, + DBCallUsers ], synchronize: true, logging: true @@ -69,81 +77,41 @@ client.once(Events.ClientReady, async () => { } }) + client.on(Events.GuildCreate, async (guild : Guild) => { + await utilities.commands.deployCommands(guild.id) + await utilities.guilds.insertGuild(serverRepo, guild) + + guild.channels.cache.forEach(async (channel: GuildBasedChannel) => { + await utilities.channels.insertChannel(channelRepo, channel) + }) + + guild.roles.cache.forEach(async (role: Role) => { + await insertRole(roleRepo, role) + }) + }) + + client.on(Events.ChannelCreate, async (channel) => { + await utilities.channels.insertChannel(channelRepo, channel) + }) + + client.on(Events.ThreadCreate, async (channel) => { + await utilities.channels.insertChannel(channelRepo, channel) + }) + + client.on(Events.InteractionCreate, async (interaction: Interaction) => { + if (!interaction.isCommand()) { + return + } + + if (commands[interaction.commandName as keyof typeof commands]) { + commands[interaction.commandName as keyof typeof commands].execute(interaction as ChatInputCommandInteraction) + } + }) + setupRoleCapture(client, serverRepo, roleRepo) setupMessageCapture(client, channelRepo, userRepo, messageRepo, mccRepo, maRepo) console.log("Breadbot is Ready") }) -client.login(config.DISCORD_TOKEN) - -/* -export let db: SQLCommon - -if (config.DB_MODE == "sqlite") { - db = new utilities.sqlite.SqliteDB("breadbot_test.db") - - db.run("PRAGMA foreign_keys = ON") - - utilities.tables.makeTables(db) - - //TODO I really don't want this to be here. - utilities.events.messages.setupMessageCapture(client, db) - utilities.events.roles.setupRoleCapture(client, db) -} - -client.once(Events.ClientReady, () => { - // TODO Winston should handle this - console.log("Breadbot is ready") - - client.guilds.cache.forEach(async (guild: Guild) => { - await utilities.commands.deployCommands(guild.id) - - // TODO handle failures? - await utilities.guilds.insertGuild(db, guild) - - guild.channels.cache.forEach(async (channel: GuildBasedChannel) => { - await utilities.channels.insertChannel(db, channel) - }) - - guild.roles.cache.forEach(async (role: Role) => { - await utilities.roles.insertRole(db, role) - }) - }) -}) - -client.on(Events.GuildCreate, async (guild : Guild) => { - await utilities.commands.deployCommands(guild.id) - await utilities.guilds.insertGuild(db, guild) - - guild.channels.cache.forEach(async (channel: GuildBasedChannel) => { - await utilities.channels.insertChannel(db, channel) - }) -}) - -client.on(Events.ChannelCreate, async (channel) => { - console.log("CHANNEL CREATE CALLED") - await utilities.channels.insertChannel(db, channel) -}) - -client.on(Events.ThreadCreate, async (channel) => { - console.log("THREAD CREATE CALLED") - console.log(channel.toString()) - await utilities.channels.insertChannel(db, channel) -}) - -client.on(Events.InteractionCreate, async (interaction: Interaction) => { - if (!interaction.isCommand()) { - return - } - - if (commands[interaction.commandName as keyof typeof commands]) { - commands[interaction.commandName as keyof typeof commands].execute(interaction as ChatInputCommandInteraction) - } -}) - -setInterval(async () => { - await utilities.breadthread.breadthreadProcessLocks(db, client) -}, 5000) - -client.login(config.DISCORD_TOKEN)*/ \ No newline at end of file +client.login(config.DISCORD_TOKEN) \ No newline at end of file diff --git a/src/utilties/storage/entities/DBCall.ts b/src/utilties/storage/entities/DBCall.ts new file mode 100644 index 0000000..1424f5b --- /dev/null +++ b/src/utilties/storage/entities/DBCall.ts @@ -0,0 +1,34 @@ +import { Column, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn } from "typeorm"; +import { DBChannel } from "./DBChannel"; +import { DBCallTranscriptions } from "./DBCallTranscriptions"; +import { DBCallUsers } from "./DBCallUsers"; + +@Entity() +export class DBCall { + @PrimaryGeneratedColumn() + call_id: number + + @ManyToOne(() => DBChannel, (channel: DBChannel) => channel.calls) + channel: DBChannel + + @Column({type: "datetime"}) + call_start_time: Date + + @Column({type: "datetime", nullable: true, default: null}) + call_end_time: Date | null + + @Column({default: false}) + call_consolidated: boolean + + @Column({default: false}) + call_transcribed: boolean + + @Column({default: false}) + call_data_cleaned_up: boolean + + @OneToMany(() => DBCallTranscriptions, (transcription: DBCallTranscriptions) => transcription.call, {nullable: true}) + transcriptions: DBCallTranscriptions[] | null + + @OneToMany(() => DBCallUsers, (callUser: DBCallUsers) => callUser.call, {nullable: true}) + participants: DBCallUsers | null +} \ No newline at end of file diff --git a/src/utilties/storage/entities/DBCallTranscriptions.ts b/src/utilties/storage/entities/DBCallTranscriptions.ts new file mode 100644 index 0000000..04520ac --- /dev/null +++ b/src/utilties/storage/entities/DBCallTranscriptions.ts @@ -0,0 +1,21 @@ +import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from "typeorm"; +import { DBCall } from "./DBCall"; +import { DBUser } from "./DBUser"; + +@Entity() +export class DBCallTranscriptions { + @PrimaryGeneratedColumn() + transcription_id: number + + @ManyToOne(() => DBCall, (call: DBCall) => call.transcriptions) + call: DBCall + + @ManyToOne(() => DBUser, (user: DBUser) => user.transcriptions) + user: DBUser + + @Column({type: "datetime"}) + speaking_start_time: Date + + @Column() + text: string +} \ No newline at end of file diff --git a/src/utilties/storage/entities/DBCallUsers.ts b/src/utilties/storage/entities/DBCallUsers.ts new file mode 100644 index 0000000..1a36d2b --- /dev/null +++ b/src/utilties/storage/entities/DBCallUsers.ts @@ -0,0 +1,21 @@ +import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from "typeorm"; +import { DBCall } from "./DBCall"; +import { DBUser } from "./DBUser"; + +@Entity() +export class DBCallUsers { + @PrimaryGeneratedColumn() + call_users_id: number + + @ManyToOne(() => DBCall, (call: DBCall) => call.participants) + call: DBCall + + @ManyToOne(() => DBUser, (user: DBUser) => user.call_history) + user: DBUser + + @Column({type: "datetime"}) + call_join_time: Date + + @Column({type: "datetime", nullable: true, default: null}) + call_leave_time: Date | null +} \ No newline at end of file diff --git a/src/utilties/storage/entities/DBChannel.ts b/src/utilties/storage/entities/DBChannel.ts index 63c7e35..f2fdf02 100644 --- a/src/utilties/storage/entities/DBChannel.ts +++ b/src/utilties/storage/entities/DBChannel.ts @@ -1,6 +1,7 @@ import { Column, Entity, ManyToOne, OneToMany, PrimaryColumn } from "typeorm"; import { DBServer } from "./DBServer"; import { DBMessage } from "./DBMessage"; +import { DBCall } from "./DBCall"; @Entity() export class DBChannel { @@ -23,5 +24,8 @@ export class DBChannel { is_voice: boolean @OneToMany(() => DBMessage, (message: DBMessage) => message.channel) - messages: DBMessage[] + messages: DBMessage[] | null + + @OneToMany(() => DBCall, (call: DBCall) => call.channel) + calls: DBCall[] | null } \ No newline at end of file diff --git a/src/utilties/storage/entities/DBUser.ts b/src/utilties/storage/entities/DBUser.ts index bf11254..bce4cc3 100644 --- a/src/utilties/storage/entities/DBUser.ts +++ b/src/utilties/storage/entities/DBUser.ts @@ -1,5 +1,7 @@ import { Column, Entity, OneToMany, PrimaryColumn } from "typeorm"; import { DBMessage } from "./DBMessage"; +import { DBCallTranscriptions } from "./DBCallTranscriptions"; +import { DBCallUsers } from "./DBCallUsers"; @Entity() export class DBUser { @@ -14,4 +16,10 @@ export class DBUser { @OneToMany(() => DBMessage, (message: DBMessage) => message.user) messages: DBMessage[] + + @OneToMany(() => DBCallTranscriptions, (transcription: DBCallTranscriptions) => transcription.user, {nullable: true}) + transcriptions: DBCallTranscriptions[] | null + + @OneToMany(() => DBCallUsers, (call_user: DBCallUsers) => call_user.user) + call_history: DBCallUsers[] | null } \ No newline at end of file -- 2.45.2 From 7d8e252b7969d2c61e20ff029808a627fe33549a Mon Sep 17 00:00:00 2001 From: Bradley Bickford Date: Tue, 18 Nov 2025 16:31:02 -0500 Subject: [PATCH 4/4] Finalizing the work for moving to TypeORM before testing of previously working functions begins --- src/breadbot.ts | 4 +- src/commands/breadalert.ts | 55 --------------- src/commands/index.ts | 4 +- src/utilties/breadbot/breadthread.ts | 57 ---------------- src/utilties/discord/regex_matching.ts | 28 ++++---- src/utilties/discord/voice.ts | 33 ++++----- src/utilties/events/voice.ts | 7 +- src/utilties/index.ts | 6 -- src/utilties/storage/entities/DBMessage.ts | 6 +- .../storage/entities/DBMessageRegex.ts | 18 +++++ .../storage/entities/DBMessageRegexMatches.ts | 15 ++++ src/utilties/storage/entities/DBServer.ts | 4 ++ src/utilties/storage/enumerations.ts | 7 -- src/utilties/storage/interfaces.ts | 7 -- src/utilties/storage/sqlite.ts | 68 ------------------- src/utilties/storage/tables.ts | 24 ------- 16 files changed, 82 insertions(+), 261 deletions(-) delete mode 100644 src/commands/breadalert.ts delete mode 100644 src/utilties/breadbot/breadthread.ts create mode 100644 src/utilties/storage/entities/DBMessageRegex.ts create mode 100644 src/utilties/storage/entities/DBMessageRegexMatches.ts delete mode 100644 src/utilties/storage/enumerations.ts delete mode 100644 src/utilties/storage/interfaces.ts delete mode 100644 src/utilties/storage/sqlite.ts delete mode 100644 src/utilties/storage/tables.ts diff --git a/src/breadbot.ts b/src/breadbot.ts index b2e9fc6..add93b4 100644 --- a/src/breadbot.ts +++ b/src/breadbot.ts @@ -20,6 +20,7 @@ import { commands } from "./commands" import { DBCall } from "./utilties/storage/entities/DBCall" import { DBCallTranscriptions } from "./utilties/storage/entities/DBCallTranscriptions" import { DBCallUsers } from "./utilties/storage/entities/DBCallUsers" +import { DBMessageRegex } from "./utilties/storage/entities/DBMessageRegex" console.log(__dirname + path.sep + "utilities" + path.sep + "storage" + path.sep + "entities" + path.sep + "*.ts") @@ -36,7 +37,8 @@ export const dataSource = new DataSource({ DBMessageAttachments, DBCall, DBCallTranscriptions, - DBCallUsers + DBCallUsers, + DBMessageRegex ], synchronize: true, logging: true diff --git a/src/commands/breadalert.ts b/src/commands/breadalert.ts deleted file mode 100644 index 0a19372..0000000 --- a/src/commands/breadalert.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { CommandInteraction, SlashCommandBuilder } from "discord.js"; - -export const enabled: boolean = true - -export const data = new SlashCommandBuilder() - .setName("breadalert") - .setDescription("Controls event alerting using the Bread Alert subsystem") - .addSubcommand((subcommand) => - subcommand - .setName("list") - .setDescription("List the current Bread Alert active alerts") - .addIntegerOption(option => - option - .setName("count") - .setDescription("The number of future alerts to return, default 5") - .setRequired(false) - ) - ) - .addSubcommand(subcommand => - subcommand - .setName("add") - .setDescription("Add a new Bread Alert") - .addStringOption(option => - option - .setName("name") - .setDescription("The name of the event, must be unique") - .setRequired(true) - ) - .addStringOption(option => - option - .setName("date") - .setDescription("The date and time of the event in YYYY-MM-DD HH:MM:SS format") - .setRequired(true) - ) - .addStringOption(option => - option - .setName("notifications") - .setDescription("A comma separated list of time offsets that determine when to alert prior to the event") - .setRequired(false) - ) - ) - .addSubcommand(subcommand => - subcommand - .setName("delete") - .setDescription("Delete a Bread Alert") - .addStringOption(option => - option - .setName("name") - .setDescription("The name of the event to remove") - ) - ) - -export async function execute(interaction: CommandInteraction) { - return interaction.reply("NOT IMPLEMENTED!") -} \ No newline at end of file diff --git a/src/commands/index.ts b/src/commands/index.ts index 03ea096..6333e84 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -1,7 +1,5 @@ import * as ping from "./ping"; -import * as breadalert from "./breadalert" export const commands = { - ping, - breadalert + ping } \ No newline at end of file diff --git a/src/utilties/breadbot/breadthread.ts b/src/utilties/breadbot/breadthread.ts deleted file mode 100644 index 77e95d3..0000000 --- a/src/utilties/breadbot/breadthread.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { timeShorthandToSeconds } from "../time/conversions"; -import { SQLCommon } from "../storage/interfaces"; -import { Client } from "discord.js"; - -export async function breadthreadLockExists(db: SQLCommon, channelId: string) : Promise { - const queryResult: Object[] = await db.getAllParameterized( - "SELECT * FROM breadthread_autolock WHERE channel_snowflake = ?", - [channelId] - ) - - return queryResult.length != 0 -} - -export async function breadthreadEnsureAutoLock(db: SQLCommon, channelId: string, inactiveTimeUntilLocked: string) { - const timeUntilLocked = timeShorthandToSeconds(inactiveTimeUntilLocked) - - if(await breadthreadLockExists(db, channelId)) { - await db.runParameterized( - "UPDATE breadthread_autolock SET inactivity_seconds = ? WHERE channel_snowflake = ?", - [timeUntilLocked, channelId] - ) - } else { - await db.runParameterized( - "INSERT INTO breadthread_autolock (channel_snowflake, inactivity_seconds, locked) VALUES (?, ?, ?)", - [channelId, timeUntilLocked, 0] - ) - } -} - -export async function breadthreadRemoveAutoLock(db: SQLCommon, channelId: string) { - await db.runParameterized( - "DELETE FROM breadthread_autolock WHERE channel_snowflake = ?", - [channelId] - ) -} - -export async function breadthreadProcessLocks(db: SQLCommon, client: Client) { - const currentTimeSeconds = Math.round((new Date()).getTime() / 1000); - (await db.getAll("SELECT * FROM breadthread_autolock WHERE locked = 0")).forEach(async (row : any) => { - const channel = client.channels.cache.find(row.channel_snowflake) - - if(channel?.isThread()) { - const lastMessageTime: number = Math.round( - channel.lastMessage?.createdAt.getTime() ?? 0 / 1000 - ) - - if(lastMessageTime != 0 && currentTimeSeconds - lastMessageTime >= row.inactivity_seconds) { - await channel.setLocked(true, "Breadbot is locking this thread because the inactivity timeout was exceeded!") - - await db.runParameterized( - "UPDATE breadthread_autolock SET locked = 1 WHERE locked = 0 AND channel_snowflake = ?", - [channel.id] - ) - } - } - }) -} \ No newline at end of file diff --git a/src/utilties/discord/regex_matching.ts b/src/utilties/discord/regex_matching.ts index 14cda5f..08094c7 100644 --- a/src/utilties/discord/regex_matching.ts +++ b/src/utilties/discord/regex_matching.ts @@ -1,16 +1,18 @@ import { Guild } from "discord.js"; -import { SQLCommon } from "../storage/interfaces"; +import { DBMessageRegex } from "../storage/entities/DBMessageRegex"; +import { Repository } from "typeorm"; +import { DBServer } from "../storage/entities/DBServer"; -export async function getRegexesForGuild(db: SQLCommon, guild: Guild): Promise { - return db.getAllParameterized( - "SELECT * FROM message_regexes WHERE server_snowflake = ?", - [guild.id] - ) -} - -export async function getRoleExclusionSnowflakesForGuild(db: SQLCommon, guild: Guild): Promise { - return (await db.getAllParameterized( - "SELECT role_snowflake FROM message_regex_no_role_check WHERE server_snowflake = ?", - [guild.id] - )).map((o) => (o as any).role_snowflake) +export async function getRegexesForGuild(db: Repository, guild: Guild): Promise { + return (await db.findOne({ + select: { + regexes: true + }, + relations: { + regexes: true + }, + where: { + server_snowflake: guild.id + } + }))?.regexes } \ No newline at end of file diff --git a/src/utilties/discord/voice.ts b/src/utilties/discord/voice.ts index 3e39757..7174b10 100644 --- a/src/utilties/discord/voice.ts +++ b/src/utilties/discord/voice.ts @@ -1,20 +1,21 @@ -import { Guild, VoiceBasedChannel } from "discord.js"; -import { SQLCommon } from "../storage/interfaces"; +import { VoiceBasedChannel } from "discord.js"; +import { IsNull, Repository } from "typeorm"; +import { DBCall } from "../storage/entities/DBCall"; -export async function breadbotInCall(db: SQLCommon, channel: VoiceBasedChannel) : Promise { - const queryResult: Object[] = await db.getAllParameterized( - "SELECT * FROM calls WHERE channel_snowflake = ? AND call_end_time IS NULL", - [channel.id] - ) - - return queryResult.length != 0 +export async function breadbotInCall(db: Repository, channel: VoiceBasedChannel) : Promise { + return (await db.findOne({ + where: { + channel: {channel_snowflake: channel.id}, + call_end_time: IsNull() + } + })) != null } -export async function getExistingCallID(db: SQLCommon, channel: VoiceBasedChannel) : Promise { - const queryResult: any[] = await db.getAllParameterized( - "SELECT * FROM calls WHERE channel_snowflake = ? AND call_end_time IS NULL", - [channel.id] - ) - - return queryResult.length != 0 ? queryResult[0].call_id : -1 +export async function getExistingCallID(db: Repository, channel: VoiceBasedChannel) : Promise { + return (await db.findOne({ + where: { + channel: {channel_snowflake: channel.id}, + call_end_time: IsNull() + } + }))?.call_id } diff --git a/src/utilties/events/voice.ts b/src/utilties/events/voice.ts index ec281c6..b16498c 100644 --- a/src/utilties/events/voice.ts +++ b/src/utilties/events/voice.ts @@ -1,7 +1,8 @@ import { Client, Events, VoiceState } from "discord.js" -import { SQLCommon } from "../storage/interfaces"; +import { Repository } from "typeorm" +import { DBCall } from "../storage/entities/DBCall" -export function setupVoice(client: Client, db: SQLCommon) { +export function setupVoice(client: Client, db: Repository) { client.on(Events.VoiceStateUpdate, (oldState: VoiceState, newState: VoiceState) => { if(oldState.channel == null && newState.channel != null) { // TODO Null Type Safety Risk? @@ -14,6 +15,6 @@ export function setupVoice(client: Client, db: SQLCommon) { }) } -async function processCallJoin(db: SQLCommon, voiceState: VoiceState) { +async function processCallJoin(db: Repository, voiceState: VoiceState) { } diff --git a/src/utilties/index.ts b/src/utilties/index.ts index 67a9f5b..30c5995 100644 --- a/src/utilties/index.ts +++ b/src/utilties/index.ts @@ -1,21 +1,15 @@ import * as commands from "./discord/commands" -import * as sqlite from "./storage/sqlite" -import * as tables from "./storage/tables" import * as guilds from "./discord/guilds" import * as channels from "./discord/channels" import * as users from "./discord/users" -import * as breadthread from "./breadbot/breadthread" import * as roles from "./discord/roles" import { events } from "./events" export const utilities = { commands, - sqlite, - tables, guilds, channels, users, events, - breadthread, roles } \ No newline at end of file diff --git a/src/utilties/storage/entities/DBMessage.ts b/src/utilties/storage/entities/DBMessage.ts index c186e21..b35ea69 100644 --- a/src/utilties/storage/entities/DBMessage.ts +++ b/src/utilties/storage/entities/DBMessage.ts @@ -1,8 +1,9 @@ -import { Column, Entity, ManyToOne, OneToMany, PrimaryColumn } from "typeorm"; +import { Column, Entity, ManyToOne, OneToMany, OneToOne, PrimaryColumn } from "typeorm"; import { DBChannel } from "./DBChannel"; import { DBUser } from "./DBUser"; import { DBMessageContentChanges } from "./DBMessageContentChanges"; import { DBMessageAttachments } from "./DBMessageAttachment"; +import { DBMessageRegexMatches } from "./DBMessageRegexMatches"; @Entity() export class DBMessage { @@ -29,4 +30,7 @@ export class DBMessage { @OneToMany(() => DBMessageAttachments, (ma: DBMessageAttachments) => ma.attachment_snowflake, {nullable: true}) attachments: DBMessageAttachments[] | null + + @OneToOne(() => DBMessageRegexMatches, (mrm: DBMessageRegexMatches) => mrm.message, {nullable: true}) + violation_regex: DBMessageRegexMatches | null } \ No newline at end of file diff --git a/src/utilties/storage/entities/DBMessageRegex.ts b/src/utilties/storage/entities/DBMessageRegex.ts new file mode 100644 index 0000000..4971c7b --- /dev/null +++ b/src/utilties/storage/entities/DBMessageRegex.ts @@ -0,0 +1,18 @@ +import { Column, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn } from "typeorm"; +import { DBServer } from "./DBServer"; +import { DBMessageRegexMatches } from "./DBMessageRegexMatches"; + +@Entity() +export class DBMessageRegex { + @PrimaryGeneratedColumn() + message_regex_id: number + + @ManyToOne(() => DBServer, (server: DBServer) => server.regexes) + server: DBServer + + @Column() + regex: string + + @OneToMany(() => DBMessageRegexMatches, (mrm: DBMessageRegexMatches) => mrm.regex, {nullable: true}) + matches: DBMessageRegexMatches[] | null +} \ No newline at end of file diff --git a/src/utilties/storage/entities/DBMessageRegexMatches.ts b/src/utilties/storage/entities/DBMessageRegexMatches.ts new file mode 100644 index 0000000..42f6ebf --- /dev/null +++ b/src/utilties/storage/entities/DBMessageRegexMatches.ts @@ -0,0 +1,15 @@ +import { Entity, ManyToOne, OneToOne, PrimaryGeneratedColumn } from "typeorm"; +import { DBMessage } from "./DBMessage"; +import { DBMessageRegex } from "./DBMessageRegex"; + +@Entity() +export class DBMessageRegexMatches { + @PrimaryGeneratedColumn() + message_regex_match_id: number + + @OneToOne(() => DBMessage, (message: DBMessage) => message.violation_regex) + message: DBMessage + + @ManyToOne(() => DBMessageRegex, (regex: DBMessageRegex) => regex.matches) + regex: DBMessageRegex +} \ No newline at end of file diff --git a/src/utilties/storage/entities/DBServer.ts b/src/utilties/storage/entities/DBServer.ts index 2dbc475..b32c70c 100644 --- a/src/utilties/storage/entities/DBServer.ts +++ b/src/utilties/storage/entities/DBServer.ts @@ -1,6 +1,7 @@ import { Column, Entity, OneToMany, PrimaryColumn } from "typeorm"; import { DBChannel } from "./DBChannel"; import { DBRole } from "./DBRole"; +import { DBMessageRegex } from "./DBMessageRegex"; @Entity() export class DBServer { @@ -18,4 +19,7 @@ export class DBServer { @OneToMany(() => DBRole, (role: DBRole) => role.server) roles: DBRole[] + + @OneToMany(() => DBMessageRegex, (regex: DBMessageRegex) => regex.server, {nullable: true}) + regexes: DBMessageRegex[] | null } \ No newline at end of file diff --git a/src/utilties/storage/enumerations.ts b/src/utilties/storage/enumerations.ts deleted file mode 100644 index ef7583c..0000000 --- a/src/utilties/storage/enumerations.ts +++ /dev/null @@ -1,7 +0,0 @@ -export enum SQLResult { - CREATED, - UPDATED, - DELETED, - ALREADYEXISTS, - FAILED -} \ No newline at end of file diff --git a/src/utilties/storage/interfaces.ts b/src/utilties/storage/interfaces.ts deleted file mode 100644 index e5ee6ba..0000000 --- a/src/utilties/storage/interfaces.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface SQLCommon { - run(query: string) : Promise - runParameterized(query: string, parameters: any[]): Promise - getAll(query: string) : Promise - getAllParameterized(query: string, parameters: any[]) : Promise -} - diff --git a/src/utilties/storage/sqlite.ts b/src/utilties/storage/sqlite.ts deleted file mode 100644 index fec7541..0000000 --- a/src/utilties/storage/sqlite.ts +++ /dev/null @@ -1,68 +0,0 @@ -import * as sqlite3 from 'sqlite3' - -import { SQLCommon } from "./interfaces" - -export class SqliteDB implements SQLCommon { - private db : sqlite3.Database; - - public constructor(private readonly dbName: string) { - this.db = new sqlite3.Database(this.dbName); - } - - async run(query: string): Promise { - return new Promise((resolve, reject) => { - this.db.run(query, function (this : sqlite3.RunResult, err: Error) { - if (err) { - // TODO Winston should handle this - console.log(err) - reject(err) - } else { - resolve(this.changes) - } - }) - }) - } - - async runParameterized(query: string, parameters: any[]): Promise { - return new Promise((resolve, reject) => { - this.db.run(query, parameters, function (this : sqlite3.RunResult, err: Error) { - if (err) { - // TODO Winston should handle this - console.log(err) - reject(err) - } else { - resolve(this.changes) - } - }) - }) - } - - async getAll(query: string): Promise { - return new Promise((resolve, reject) => { - this.db.all(query, (err: Error, rows: Object[]) => { - if (err) { - // TODO Winston should handle this - console.log(err) - reject(err) - } else { - resolve(rows) - } - }) - }) - } - - getAllParameterized(query: string, parameters: any[]): Promise { - return new Promise((resolve, reject) => { - this.db.all(query, parameters, (err: Error, rows: Object[]) => { - if (err) { - // TODO Winston should handle this - console.log(err) - reject(err) - } else { - resolve(rows) - } - }) - }) - } - -} \ No newline at end of file diff --git a/src/utilties/storage/tables.ts b/src/utilties/storage/tables.ts deleted file mode 100644 index 97426af..0000000 --- a/src/utilties/storage/tables.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { SQLCommon } from "./interfaces"; - -const tables: string[] = [ - "CREATE TABLE IF NOT EXISTS message_scan_regex_matches (message_scan_regex_matches_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,message_snowflake bigint NOT NULL,message_regexes_id bigint NOT NULL);", - "CREATE TABLE IF NOT EXISTS message_regex_no_role_check (message_regex_no_role_check_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,server_snowflake bigint NOT NULL,role_snowflake bigint NOT NULL);", - "CREATE TABLE IF NOT EXISTS message_regexes (message_regexes_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,server_snowflake bigint NOT NULL,regex text NOT NULL,priority int NOT NULL,severity int NOT NULL);", - "CREATE TABLE IF NOT EXISTS message_regex_words (message_regex_words_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,message_regexes_id bigint,word text NOT NULL);", - "CREATE TABLE IF NOT EXISTS calls (call_id bigint NOT NULL PRIMARY KEY AUTOINCREMENT, channel_snowflake bigint NOT NULL, call_start_time datetime NOT NULL, call_end_time datetime DEFAULT NULL, call_consolidated INTEGER DEFAULT 0 CHECK(call_consolidated IN (0, 1)), call_transcribed INTEGER DEFAULT 0 CHECK(call_transcribed IN (0, 1)), call_data_cleaned_up INTEGER DEFAULT 0 CHECK(call_data_cleaned_up IN (0, 1)));", - "CREATE TABLE IF NOT EXISTS call_transcriptions (transcription_id bitint NOT NULL PRIMARY KEY AUTOINCREMENT, call_id bigint NOT NULL, user_snowflake bigint NOT NULL, speaking_start_time datetime NOT NULL, text TEXT NOT NULL);", - "CREATE TABLE IF NOT EXISTS call_users (call_users_id bigint NOT NULL PRIMARY KEY AUTOINCREMENT, call_id bigint NOT NULL, user_snowflake bigint NOT NULL, call_join_time datetime NOT NULL, call_leave_time datetime DEFAULT NULL);" -] - -const constraints: string[] = [ - "ALTER TABLE channels ADD CONSTRAINT channels_server_snowflake_fk FOREIGN KEY (server_snowflake) REFERENCES servers (server_snowflake);" -] - -export async function makeTables(db: SQLCommon): Promise { - return Promise.all(tables.map((statement) => db.run(statement))) -} - -export async function makeConstraints(db: SQLCommon): Promise { - return Promise.all(constraints.map((statement) => db.run(statement))) -} - -- 2.45.2